All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH v2 00/41] Scalable Vector Extension (SVE) core support
@ 2017-03-22 14:50 ` Dave Martin
  0 siblings, 0 replies; 75+ messages in thread
From: Dave Martin @ 2017-03-22 14:50 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Will Deacon, Catalin Marinas, Marc Zyngier, Ard Biesheuvel,
	Florian Weimer, Joseph Myers, Szabolcs Nagy, Andrew Morton,
	linux-kernel, Alan Hayward, Yao Qi, gdb, Christoffer Dall,
	libc-alpha, Richard Sandiford, Torvald Riegel

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] 75+ messages in thread

* [RFC PATCH v2 00/41] Scalable Vector Extension (SVE) core support
@ 2017-03-22 14:50 ` Dave Martin
  0 siblings, 0 replies; 75+ 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] 75+ messages in thread

* [RFC PATCH v2 01/41] arm64: signal: Refactor sigcontext parsing in rt_sigreturn
  2017-03-22 14:50 ` Dave Martin
  (?)
@ 2017-03-22 14:50 ` Dave Martin
  -1 siblings, 0 replies; 75+ 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 = &current->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(&regs->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] 75+ messages in thread

* [RFC PATCH v2 02/41] arm64: signal: factor frame layout and population into separate passes
  2017-03-22 14:50 ` Dave Martin
  (?)
  (?)
@ 2017-03-22 14:50 ` Dave Martin
  -1 siblings, 0 replies; 75+ 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 = &current->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] 75+ messages in thread

* [RFC PATCH v2 03/41] arm64: signal: factor out signal frame record allocation
  2017-03-22 14:50 ` Dave Martin
                   ` (2 preceding siblings ...)
  (?)
@ 2017-03-22 14:50 ` Dave Martin
  -1 siblings, 0 replies; 75+ 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] 75+ messages in thread

* [RFC PATCH v2 04/41] arm64: signal: Allocate extra sigcontext space as needed
  2017-03-22 14:50 ` Dave Martin
                   ` (3 preceding siblings ...)
  (?)
@ 2017-03-22 14:50 ` Dave Martin
  -1 siblings, 0 replies; 75+ 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] 75+ messages in thread

* [RFC PATCH v2 05/41] arm64: signal: Parse extra_context during sigreturn
  2017-03-22 14:50 ` Dave Martin
                   ` (4 preceding siblings ...)
  (?)
@ 2017-03-22 14:50 ` Dave Martin
  -1 siblings, 0 replies; 75+ 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] 75+ messages in thread

* [RFC PATCH v2 06/41] arm64: efi: Add missing Kconfig dependency on KERNEL_MODE_NEON
  2017-03-22 14:50 ` Dave Martin
                   ` (5 preceding siblings ...)
  (?)
@ 2017-03-22 14:50 ` Dave Martin
  -1 siblings, 0 replies; 75+ 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] 75+ messages in thread

* [RFC PATCH v2 07/41] arm64/sve: Allow kernel-mode NEON to be disabled in Kconfig
  2017-03-22 14:50 ` Dave Martin
                   ` (6 preceding siblings ...)
  (?)
@ 2017-03-22 14:50 ` Dave Martin
  -1 siblings, 0 replies; 75+ 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] 75+ messages in thread

* [RFC PATCH v2 08/41] arm64/sve: Low-level save/restore code
  2017-03-22 14:50 ` Dave Martin
                   ` (7 preceding siblings ...)
  (?)
@ 2017-03-22 14:50 ` Dave Martin
  -1 siblings, 0 replies; 75+ 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] 75+ messages in thread

* [RFC PATCH v2 09/41] arm64/sve: Boot-time feature detection and reporting
  2017-03-22 14:50 ` Dave Martin
                   ` (8 preceding siblings ...)
  (?)
@ 2017-03-22 14:50 ` Dave Martin
  -1 siblings, 0 replies; 75+ 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] 75+ messages in thread

* [RFC PATCH v2 10/41] arm64/sve: Boot-time feature enablement
  2017-03-22 14:50 ` Dave Martin
                   ` (9 preceding siblings ...)
  (?)
@ 2017-03-22 14:50 ` Dave Martin
  -1 siblings, 0 replies; 75+ 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] 75+ messages in thread

* [RFC PATCH v2 11/41] arm64/sve: Expand task_struct for Scalable Vector Extension state
  2017-03-22 14:50 ` Dave Martin
                   ` (10 preceding siblings ...)
  (?)
@ 2017-03-22 14:50 ` Dave Martin
  2017-03-22 16:20   ` Mark Rutland
  -1 siblings, 1 reply; 75+ 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 IS_ENABLED(CONFIG_ARM64_SVE): */
+extern void *__sve_state(struct task_struct *task);
+extern void *sve_pffr(struct task_struct *task);
+
+#endif /* ! CONFIG_ARM64_SVE */
+
 /*
  * Trapped FP/ASIMD access.
  */
@@ -125,6 +149,27 @@ void do_fpsimd_exc(unsigned int esr, struct pt_regs *regs)
 	send_sig_info(SIGFPE, &info, current);
 }
 
+static void task_fpsimd_load(struct task_struct *task)
+{
+	if (IS_ENABLED(CONFIG_ARM64_SVE) && (elf_hwcap & HWCAP_SVE))
+		sve_load_state(sve_pffr(task),
+			       &task->thread.fpsimd_state.fpsr);
+	else
+		fpsimd_load_state(&task->thread.fpsimd_state);
+}
+
+static void task_fpsimd_save(struct task_struct *task)
+{
+	/* FIXME: remove task argument? */
+	BUG_ON(task != current);
+
+	if (IS_ENABLED(CONFIG_ARM64_SVE) && (elf_hwcap & HWCAP_SVE))
+		sve_save_state(sve_pffr(task),
+			       &task->thread.fpsimd_state.fpsr);
+	else
+		fpsimd_save_state(&task->thread.fpsimd_state);
+}
+
 void fpsimd_thread_switch(struct task_struct *next)
 {
 	if (!system_supports_fpsimd())
@@ -161,8 +206,21 @@ void fpsimd_flush_thread(void)
 {
 	if (!system_supports_fpsimd())
 		return;
-	memset(&current->thread.fpsimd_state, 0, sizeof(struct fpsimd_state));
+
 	fpsimd_flush_task_state(current);
+
+	memset(&current->thread.fpsimd_state, 0, sizeof(struct fpsimd_state));
+
+	if (IS_ENABLED(CONFIG_ARM64_SVE) && (elf_hwcap & HWCAP_SVE)) {
+		BUG_ON((char *)__sve_state(current) < (char *)current);
+		BUG_ON(arch_task_struct_size <
+		       ((char *)__sve_state(current) - (char *)current));
+
+		memset(__sve_state(current), 0,
+		       arch_task_struct_size -
+		       ((char *)__sve_state(current) - (char *)current));
+	}
+
 	set_thread_flag(TIF_FOREIGN_FPSTATE);
 }
 
@@ -329,6 +387,21 @@ static inline void fpsimd_hotplug_init(void)
 static inline void fpsimd_hotplug_init(void) { }
 #endif
 
+void __init fpsimd_init_task_struct_size(void)
+{
+	arch_task_struct_size = sizeof(struct task_struct);
+
+	if (IS_ENABLED(CONFIG_ARM64_SVE) &&
+	    ((read_cpuid(ID_AA64PFR0_EL1) >> ID_AA64PFR0_SVE_SHIFT)
+	     & 0xf) == 1) {
+		arch_task_struct_size = sizeof(struct task_struct) +
+			35 * sve_get_vl();
+
+		pr_info("SVE: enabled with maximum %u bits per vector\n",
+			sve_get_vl() * 8);
+	}
+}
+
 /*
  * FP/SIMD support code initialisation.
  */
diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c
index 043d373..717dd0f 100644
--- a/arch/arm64/kernel/process.c
+++ b/arch/arm64/kernel/process.c
@@ -246,7 +246,7 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
 {
 	if (current->mm)
 		fpsimd_preserve_current_state();
-	*dst = *src;
+	memcpy(dst, src, arch_task_struct_size);
 	return 0;
 }
 
diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c
index 42274bd..1412a35 100644
--- a/arch/arm64/kernel/setup.c
+++ b/arch/arm64/kernel/setup.c
@@ -236,6 +236,9 @@ void __init setup_arch(char **cmdline_p)
 	pr_info("Boot CPU: AArch64 Processor [%08x]\n", read_cpuid_id());
 
 	sprintf(init_utsname()->machine, UTS_MACHINE);
+
+	fpsimd_init_task_struct_size();
+
 	init_mm.start_code = (unsigned long) _text;
 	init_mm.end_code   = (unsigned long) _etext;
 	init_mm.end_data   = (unsigned long) _edata;
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [RFC PATCH v2 12/41] arm64/sve: Save/restore SVE state on context switch paths
  2017-03-22 14:50 ` Dave Martin
                   ` (11 preceding siblings ...)
  (?)
@ 2017-03-22 14:50 ` Dave Martin
  -1 siblings, 0 replies; 75+ messages in thread
From: Dave Martin @ 2017-03-22 14:50 UTC (permalink / raw)
  To: linux-arm-kernel

This patch implements basic handling of the Scalable Vector
Extension state on the primary context switch paths.

This does *not* (correctly) handle the signal path, and doesn't do
save/restore for SVE-only accesses that don't affect the FPSIMD
state (i.e., FFR).

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
---
 arch/arm64/kernel/fpsimd.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index bc7a2d5..f8acce2 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -180,7 +180,7 @@ void fpsimd_thread_switch(struct task_struct *next)
 	 * 'current'.
 	 */
 	if (current->mm && !test_thread_flag(TIF_FOREIGN_FPSTATE))
-		fpsimd_save_state(&current->thread.fpsimd_state);
+		task_fpsimd_save(current);
 
 	if (next->mm) {
 		/*
@@ -234,7 +234,7 @@ void fpsimd_preserve_current_state(void)
 		return;
 	preempt_disable();
 	if (!test_thread_flag(TIF_FOREIGN_FPSTATE))
-		fpsimd_save_state(&current->thread.fpsimd_state);
+		task_fpsimd_save(current);
 	preempt_enable();
 }
 
@@ -251,7 +251,7 @@ void fpsimd_restore_current_state(void)
 	if (test_and_clear_thread_flag(TIF_FOREIGN_FPSTATE)) {
 		struct fpsimd_state *st = &current->thread.fpsimd_state;
 
-		fpsimd_load_state(st);
+		task_fpsimd_load(current);
 		this_cpu_write(fpsimd_last_state, st);
 		st->cpu = smp_processor_id();
 	}
@@ -343,7 +343,7 @@ static int fpsimd_cpu_pm_notifier(struct notifier_block *self,
 	switch (cmd) {
 	case CPU_PM_ENTER:
 		if (current->mm && !test_thread_flag(TIF_FOREIGN_FPSTATE))
-			fpsimd_save_state(&current->thread.fpsimd_state);
+			task_fpsimd_save(current);
 		this_cpu_write(fpsimd_last_state, NULL);
 		break;
 	case CPU_PM_EXIT:
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [RFC PATCH v2 13/41] arm64/sve: [BROKEN] Basic support for KERNEL_MODE_NEON
  2017-03-22 14:50 ` Dave Martin
                   ` (12 preceding siblings ...)
  (?)
@ 2017-03-22 14:50 ` Dave Martin
  -1 siblings, 0 replies; 75+ messages in thread
From: Dave Martin @ 2017-03-22 14:50 UTC (permalink / raw)
  To: linux-arm-kernel

In order to enable CONFIG_KERNEL_MODE_NEON and things that rely on
it to be configured together with Scalable Vector Extension support
in the same kernel, this patch implements basic support for
saving/restoring the SVE state around kernel_neon_begin()...
kernel_neon_end().

This patch is not optimal and will generally save more state than
necessary, more often than necessary.  Further optimisations can be
implemented in future patches.

This patch is not intended to allow general-purpose _SVE_ code to
execute in the kernel safely.  That functionality may also follow
in later patches.

*** This patch is broken in its current form: ***

Only the FPSIMD registers are ever saved around kernel_neon_begin{,
_partial}()..._end().  However, for each Vn written, the high bits
of each Zn other than bits [127:0] will be zeroed.  This is a
feature of the SVE architecture, and can corrupt userspace SVE
state with this patch as-is.

Instead, we need to save the full SVE regs if they are live: but
this is a potentially large cost.  It may also be unacceptable to
pay this cost in IRQ handlers, but we have no way to back out once
an IRQ handler calls kernel_neon_begin().  This will extend the
interrupt blackout associated with IRQ handlers that use FPSIMD.

It may be simpler to allow kernel_neon_begin() to fail if, say, the
SVE registers are live or if called in IRQ context.  The caller
would need to have a fallback C implementation of its
number-crunching code for this case.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
---
 arch/arm64/Kconfig         |  1 -
 arch/arm64/kernel/fpsimd.c | 23 +++++++++++++++++++----
 2 files changed, 19 insertions(+), 5 deletions(-)

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 820fad1..05b6dd3 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -936,7 +936,6 @@ 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
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index f8acce2..7c6417a 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -298,11 +298,27 @@ void kernel_neon_begin_partial(u32 num_regs)
 {
 	if (WARN_ON(!system_supports_fpsimd()))
 		return;
+
+	preempt_disable();
+
+	/*
+	 * For now, we have no special storage for SVE registers in
+	 * interrupt context, so always save the userland SVE state
+	 * if there is any, even for interrupts.
+	 */
+	if (IS_ENABLED(CONFIG_ARM64_SVE) && (elf_hwcap & HWCAP_SVE) &&
+	    current->mm &&
+	    !test_and_set_thread_flag(TIF_FOREIGN_FPSTATE)) {
+		fpsimd_save_state(&current->thread.fpsimd_state);
+		this_cpu_write(fpsimd_last_state, NULL);
+	}
+
 	if (in_interrupt()) {
 		struct fpsimd_partial_state *s = this_cpu_ptr(
 			in_irq() ? &hardirq_fpsimdstate : &softirq_fpsimdstate);
-
 		BUG_ON(num_regs > 32);
+
+		/* Save partial state for interrupted kernel-mode NEON code: */
 		fpsimd_save_partial_state(s, roundup(num_regs, 2));
 	} else {
 		/*
@@ -311,7 +327,6 @@ void kernel_neon_begin_partial(u32 num_regs)
 		 * that there is no longer userland FPSIMD state in the
 		 * registers.
 		 */
-		preempt_disable();
 		if (current->mm &&
 		    !test_and_set_thread_flag(TIF_FOREIGN_FPSTATE))
 			fpsimd_save_state(&current->thread.fpsimd_state);
@@ -328,9 +343,9 @@ void kernel_neon_end(void)
 		struct fpsimd_partial_state *s = this_cpu_ptr(
 			in_irq() ? &hardirq_fpsimdstate : &softirq_fpsimdstate);
 		fpsimd_load_partial_state(s);
-	} else {
-		preempt_enable();
 	}
+
+	preempt_enable();
 }
 EXPORT_SYMBOL(kernel_neon_end);
 
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [RFC PATCH v2 14/41] Revert "arm64/sve: Allow kernel-mode NEON to be disabled in Kconfig"
  2017-03-22 14:50 ` Dave Martin
                   ` (13 preceding siblings ...)
  (?)
@ 2017-03-22 14:50 ` Dave Martin
  -1 siblings, 0 replies; 75+ messages in thread
From: Dave Martin @ 2017-03-22 14:50 UTC (permalink / raw)
  To: linux-arm-kernel

Now that KERNEL_MODE_NEON works for SVE, we can just default it
back to y.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
---
 arch/arm64/Kconfig | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 05b6dd3..593d2db 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -227,6 +227,9 @@ config SWIOTLB
 config IOMMU_HELPER
 	def_bool SWIOTLB
 
+config KERNEL_MODE_NEON
+	def_bool y
+
 config FIX_EARLYCON_MEM
 	def_bool y
 
@@ -272,10 +275,6 @@ 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] 75+ messages in thread

* [RFC PATCH v2 15/41] arm64/sve: Restore working FPSIMD save/restore around signals
  2017-03-22 14:50 ` Dave Martin
                   ` (14 preceding siblings ...)
  (?)
@ 2017-03-22 14:50 ` Dave Martin
  -1 siblings, 0 replies; 75+ messages in thread
From: Dave Martin @ 2017-03-22 14:50 UTC (permalink / raw)
  To: linux-arm-kernel

Because fpsimd_state and the SVE state are not magically
synchronised in the task_struct, stale FPSIMD data may be saved on
signal handler entry, and restored data my be lost on sigreturn.

This patch converts between SVE and FPSIMD views around the signal,
restoring working FPSIMD save/restore.

This will not save/restore the SVE state properly, but it should
restore a working FPSIMD ABI.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
---
 arch/arm64/include/asm/fpsimd.h |  1 +
 arch/arm64/kernel/fpsimd.c      | 73 ++++++++++++++++++++++++++++++++++++++++-
 arch/arm64/kernel/signal.c      |  2 +-
 arch/arm64/kernel/signal32.c    |  2 +-
 4 files changed, 75 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/include/asm/fpsimd.h b/arch/arm64/include/asm/fpsimd.h
index 757d304..93ae8a7 100644
--- a/arch/arm64/include/asm/fpsimd.h
+++ b/arch/arm64/include/asm/fpsimd.h
@@ -80,6 +80,7 @@ extern void fpsimd_load_state(struct fpsimd_state *state);
 extern void fpsimd_thread_switch(struct task_struct *next);
 extern void fpsimd_flush_thread(void);
 
+extern void fpsimd_signal_preserve_current_state(void);
 extern void fpsimd_preserve_current_state(void);
 extern void fpsimd_restore_current_state(void);
 extern void fpsimd_update_current_state(struct fpsimd_state *state);
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index 7c6417a..0024931 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -105,11 +105,66 @@ static void *sve_pffr(struct task_struct *task)
 	return (char *)__sve_state(task) + 34 * vl;
 }
 
+static void __fpsimd_to_sve(struct task_struct *task, unsigned int vq)
+{
+	struct sve_struct fpsimd_sve_state(vq) *sst = __sve_state(task);
+	struct fpsimd_state *fst = &task->thread.fpsimd_state;
+	unsigned int i;
+
+	memset(sst, 0, sizeof(*sst));
+	for (i = 0; i < 32; ++i)
+		sst->zregs[i][0] = fst->vregs[i];
+}
+
+static void fpsimd_to_sve(struct task_struct *task)
+{
+	unsigned int vl = sve_get_vl();
+	unsigned int vq;
+
+	if (!(elf_hwcap & HWCAP_SVE))
+		return;
+
+	BUG_ON(vl % 16);
+	vq = vl / 16;
+	BUG_ON(vq < 1 || vq > 16);
+
+	__fpsimd_to_sve(task, vq);
+}
+
+static void __sve_to_fpsimd(struct task_struct *task, unsigned int vq)
+{
+	struct sve_struct fpsimd_sve_state(vq) *sst = __sve_state(task);
+	struct fpsimd_state *fst = &task->thread.fpsimd_state;
+	unsigned int i;
+
+	for (i = 0; i < 32; ++i)
+		fst->vregs[i] = sst->zregs[i][0];
+}
+
+static void sve_to_fpsimd(struct task_struct *task)
+{
+	unsigned int vl = sve_get_vl();
+	unsigned int vq;
+
+	if (!(elf_hwcap & HWCAP_SVE))
+		return;
+
+	BUG_ON(vl % 16);
+	vq = vl / 16;
+	BUG_ON(vq < 1 || vq > 16);
+
+	__sve_to_fpsimd(task, vq);
+}
+
 #else /* ! CONFIG_ARM64_SVE */
 
 /* Dummy declarations for usage protected with IS_ENABLED(CONFIG_ARM64_SVE): */
 extern void *__sve_state(struct task_struct *task);
 extern void *sve_pffr(struct task_struct *task);
+extern void fpsimd_to_sve(struct task_struct *task);
+
+/* Functions that map to no-ops without SVE: */
+static void sve_to_fpsimd(struct task_struct *task __always_unused) { }
 
 #endif /* ! CONFIG_ARM64_SVE */
 
@@ -238,6 +293,15 @@ void fpsimd_preserve_current_state(void)
 	preempt_enable();
 }
 
+void fpsimd_signal_preserve_current_state(void)
+{
+	WARN_ONCE(elf_hwcap & HWCAP_SVE,
+		  "SVE state save/restore around signals doesn't work properly, expect userspace corruption!\n");
+
+	fpsimd_preserve_current_state();
+	sve_to_fpsimd(current);
+}
+
 /*
  * Load the userland FPSIMD state of 'current' from memory, but only if the
  * FPSIMD state already held in the registers is /not/ the most recent FPSIMD
@@ -268,13 +332,20 @@ void fpsimd_update_current_state(struct fpsimd_state *state)
 	if (!system_supports_fpsimd())
 		return;
 	preempt_disable();
-	fpsimd_load_state(state);
+
+	if (IS_ENABLED(CONFIG_ARM64_SVE)) {
+		current->thread.fpsimd_state = *state;
+		fpsimd_to_sve(current);
+	}
+	task_fpsimd_load(current);
+
 	if (test_and_clear_thread_flag(TIF_FOREIGN_FPSTATE)) {
 		struct fpsimd_state *st = &current->thread.fpsimd_state;
 
 		this_cpu_write(fpsimd_last_state, st);
 		st->cpu = smp_processor_id();
 	}
+
 	preempt_enable();
 }
 
diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c
index 49c30df..15c7edf 100644
--- a/arch/arm64/kernel/signal.c
+++ b/arch/arm64/kernel/signal.c
@@ -168,7 +168,7 @@ static int preserve_fpsimd_context(struct fpsimd_context __user *ctx)
 	int err;
 
 	/* dump the hardware registers to the fpsimd_state structure */
-	fpsimd_preserve_current_state();
+	fpsimd_signal_preserve_current_state();
 
 	/* copy the FP and status/control registers */
 	err = __copy_to_user(ctx->vregs, fpsimd->vregs, sizeof(fpsimd->vregs));
diff --git a/arch/arm64/kernel/signal32.c b/arch/arm64/kernel/signal32.c
index c747a0f..2df31a38 100644
--- a/arch/arm64/kernel/signal32.c
+++ b/arch/arm64/kernel/signal32.c
@@ -244,7 +244,7 @@ static int compat_preserve_vfp_context(struct compat_vfp_sigframe __user *frame)
 	 * Note that this also saves V16-31, which aren't visible
 	 * in AArch32.
 	 */
-	fpsimd_preserve_current_state();
+	fpsimd_signal_preserve_current_state();
 
 	/* Place structure header on the stack */
 	__put_user_error(magic, &frame->magic, err);
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [RFC PATCH v2 16/41] arm64/sve: signal: Add SVE state record to sigcontext
  2017-03-22 14:50 ` Dave Martin
                   ` (15 preceding siblings ...)
  (?)
@ 2017-03-22 14:50 ` Dave Martin
  -1 siblings, 0 replies; 75+ messages in thread
From: Dave Martin @ 2017-03-22 14:50 UTC (permalink / raw)
  To: linux-arm-kernel

This patch adds a record to sigcontext that will contain the SVE
state.

The sigcontext SVE layout is intentionally the same as the layout
used internally by the kernel to store the SVE state in
task_struct, so this patch also uses the new macros to replace
magic numbers currently used to describe the layout.

Subsequent patches will implement the actual register dumping.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
---
 arch/arm64/include/uapi/asm/sigcontext.h | 86 ++++++++++++++++++++++++++++++++
 arch/arm64/kernel/fpsimd.c               | 31 ++++++------
 arch/arm64/kernel/signal.c               | 62 +++++++++++++++++++++++
 3 files changed, 162 insertions(+), 17 deletions(-)

diff --git a/arch/arm64/include/uapi/asm/sigcontext.h b/arch/arm64/include/uapi/asm/sigcontext.h
index 1af8437..11c915d 100644
--- a/arch/arm64/include/uapi/asm/sigcontext.h
+++ b/arch/arm64/include/uapi/asm/sigcontext.h
@@ -88,4 +88,90 @@ struct extra_context {
 	__u32 size;	/* size in bytes of the extra space */
 };
 
+#define SVE_MAGIC	0x53564501
+
+struct sve_context {
+	struct _aarch64_ctx head;
+	__u16 vl;
+	__u16 __reserved[3];
+};
+
+/*
+ * The SVE architecture leaves space for future expansion of the
+ * vector length beyond its initial architectural limit of 2048 bits
+ * (16 quadwords).
+ */
+#define SVE_VQ_MIN		1
+#define SVE_VQ_MAX		0x200
+
+#define SVE_VL_MIN		(SVE_VQ_MIN * 0x10)
+#define SVE_VL_MAX		(SVE_VQ_MAX * 0x10)
+
+#define SVE_NUM_ZREGS		32
+#define SVE_NUM_PREGS		16
+
+#define sve_vl_valid(vl) \
+	((vl) % 0x10 == 0 && (vl) >= SVE_VL_MIN && (vl) <= SVE_VL_MAX)
+#define sve_vq_from_vl(vl)	((vl) / 0x10)
+
+/*
+ * The total size of meaningful data in the SVE context in bytes,
+ * including the header, is given by SVE_SIG_CONTEXT_SIZE(vq).
+ *
+ * Note: for all these macros, the "vq" argument denotes the SVE
+ * vector length in quadwords (i.e., units of 128 bits).
+ *
+ * The correct way to obtain vq is to use sve_vq_from_vl(vl).  The
+ * result is valid if and only if sve_vl_valid(vl) is true.  This is
+ * guaranteed for a struct sve_context written by the kernel.
+ *
+ *
+ * Additional macros describe the contents and layout of the payload.
+ * For each, SVE_SIG_x_OFFSET(args) is the start offset relative to
+ * the start of struct sve_context, and SVE_SIG_x_SIZE(args) is the
+ * size in bytes:
+ *
+ *	x	type				description
+ *	-	----				-----------
+ *	REGS					the entire SVE context
+ *
+ *	ZREGS	__uint128_t[SVE_NUM_ZREGS][vq]	all Z-registers
+ *	ZREG	__uint128_t[vq]			individual Z-register Zn
+ *
+ *	PREGS	uint16_t[SVE_NUM_PREGS][vq]	all P-registers
+ *	PREG	uint16_t[vq]			individual P-register Pn
+ *
+ *	FFR	uint16_t[vq]			first-fault status register
+ *
+ * Additional data might be appended in the future.
+ */
+
+#define SVE_SIG_ZREG_SIZE(vq)	((__u32)(vq) * 16)
+#define SVE_SIG_PREG_SIZE(vq)	((__u32)(vq) * 2)
+#define SVE_SIG_FFR_SIZE(vq)	SVE_SIG_PREG_SIZE(vq)
+
+#define SVE_SIG_REGS_OFFSET	((sizeof(struct sve_context) + 15) / 16 * 16)
+
+#define SVE_SIG_ZREGS_OFFSET	SVE_SIG_REGS_OFFSET
+#define SVE_SIG_ZREG_OFFSET(vq, n) \
+	(SVE_SIG_ZREGS_OFFSET + SVE_SIG_ZREG_SIZE(vq) * (n))
+#define SVE_SIG_ZREGS_SIZE(vq) \
+	(SVE_SIG_ZREG_OFFSET(vq, SVE_NUM_ZREGS) - SVE_SIG_ZREGS_OFFSET)
+
+#define SVE_SIG_PREGS_OFFSET(vq) \
+	(SVE_SIG_ZREGS_OFFSET + SVE_SIG_ZREGS_SIZE(vq))
+#define SVE_SIG_PREG_OFFSET(vq, n) \
+	(SVE_SIG_PREGS_OFFSET(vq) + SVE_SIG_PREG_SIZE(vq) * (n))
+#define SVE_SIG_PREGS_SIZE(vq) \
+	(SVE_SIG_PREG_OFFSET(vq, SVE_NUM_PREGS) - SVE_SIG_PREGS_OFFSET(vq))
+
+#define SVE_SIG_FFR_OFFSET(vq) \
+	(SVE_SIG_PREGS_OFFSET(vq) + SVE_SIG_PREGS_SIZE(vq))
+
+#define SVE_SIG_REGS_SIZE(vq) \
+	(SVE_SIG_FFR_OFFSET(vq) + SVE_SIG_FFR_SIZE(vq) - SVE_SIG_REGS_OFFSET)
+
+#define SVE_SIG_CONTEXT_SIZE(vq) (SVE_SIG_REGS_OFFSET + SVE_SIG_REGS_SIZE(vq))
+
+
 #endif /* _UAPI__ASM_SIGCONTEXT_H */
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index 0024931..801f4d3 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -28,6 +28,7 @@
 #include <asm/fpsimd.h>
 #include <asm/cputype.h>
 #include <asm/hwcap.h>
+#include <asm/sigcontext.h>
 
 #define FPEXC_IOF	(1 << 0)
 #define FPEXC_DZF	(1 << 1)
@@ -101,8 +102,9 @@ 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;
+	BUG_ON(!sve_vl_valid(vl));
+	return (char *)__sve_state(task) +
+		(SVE_SIG_FFR_OFFSET(sve_vq_from_vl(vl)) - SVE_SIG_REGS_OFFSET);
 }
 
 static void __fpsimd_to_sve(struct task_struct *task, unsigned int vq)
@@ -119,16 +121,12 @@ static void __fpsimd_to_sve(struct task_struct *task, unsigned int vq)
 static void fpsimd_to_sve(struct task_struct *task)
 {
 	unsigned int vl = sve_get_vl();
-	unsigned int vq;
 
 	if (!(elf_hwcap & HWCAP_SVE))
 		return;
 
-	BUG_ON(vl % 16);
-	vq = vl / 16;
-	BUG_ON(vq < 1 || vq > 16);
-
-	__fpsimd_to_sve(task, vq);
+	BUG_ON(!sve_vl_valid(vl));
+	__fpsimd_to_sve(task, sve_vq_from_vl(vl));
 }
 
 static void __sve_to_fpsimd(struct task_struct *task, unsigned int vq)
@@ -144,16 +142,12 @@ static void __sve_to_fpsimd(struct task_struct *task, unsigned int vq)
 static void sve_to_fpsimd(struct task_struct *task)
 {
 	unsigned int vl = sve_get_vl();
-	unsigned int vq;
 
 	if (!(elf_hwcap & HWCAP_SVE))
 		return;
 
-	BUG_ON(vl % 16);
-	vq = vl / 16;
-	BUG_ON(vq < 1 || vq > 16);
-
-	__sve_to_fpsimd(task, vq);
+	BUG_ON(!sve_vl_valid(vl));
+	__sve_to_fpsimd(task, sve_vq_from_vl(vl));
 }
 
 #else /* ! CONFIG_ARM64_SVE */
@@ -480,11 +474,14 @@ void __init fpsimd_init_task_struct_size(void)
 	if (IS_ENABLED(CONFIG_ARM64_SVE) &&
 	    ((read_cpuid(ID_AA64PFR0_EL1) >> ID_AA64PFR0_SVE_SHIFT)
 	     & 0xf) == 1) {
-		arch_task_struct_size = sizeof(struct task_struct) +
-			35 * sve_get_vl();
+		unsigned int vl = sve_get_vl();
+
+		BUG_ON(!sve_vl_valid(vl));
+		arch_task_struct_size = ALIGN(sizeof(struct task_struct), 16) +
+			ALIGN(SVE_SIG_REGS_SIZE(sve_vq_from_vl(vl)), 16);
 
 		pr_info("SVE: enabled with maximum %u bits per vector\n",
-			sve_get_vl() * 8);
+			vl * 8);
 	}
 }
 
diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c
index 15c7edf..113502e 100644
--- a/arch/arm64/kernel/signal.c
+++ b/arch/arm64/kernel/signal.c
@@ -57,6 +57,7 @@ struct rt_sigframe_user_layout {
 
 	unsigned long fpsimd_offset;
 	unsigned long esr_offset;
+	unsigned long sve_offset;
 	unsigned long extra_offset;
 	unsigned long end_offset;
 };
@@ -209,8 +210,39 @@ static int restore_fpsimd_context(struct fpsimd_context __user *ctx)
 	return err ? -EFAULT : 0;
 }
 
+
+#ifdef CONFIG_ARM64_SVE
+
+static int preserve_sve_context(struct sve_context __user *ctx)
+{
+	int err = 0;
+	u16 reserved[ARRAY_SIZE(ctx->__reserved)];
+	unsigned int vl = sve_get_vl();
+	unsigned int vq = sve_vq_from_vl(vl);
+
+	memset(reserved, 0, sizeof(reserved));
+
+	__put_user_error(SVE_MAGIC, &ctx->head.magic, err);
+	__put_user_error(round_up(SVE_SIG_CONTEXT_SIZE(vq), 16),
+			 &ctx->head.size, err);
+	__put_user_error(vl, &ctx->vl, err);
+	BUILD_BUG_ON(sizeof(ctx->__reserved) != sizeof(reserved));
+	err |= copy_to_user(&ctx->__reserved, reserved, sizeof(reserved));
+
+	return err ? -EFAULT : 0;
+}
+
+#else /* ! CONFIG_ARM64_SVE */
+
+/* Turn any non-optimised out attempt to use this into a link error: */
+extern int preserve_sve_context(void __user *ctx);
+
+#endif /* ! CONFIG_ARM64_SVE */
+
+
 struct user_ctxs {
 	struct fpsimd_context __user *fpsimd;
+	struct sve_context __user *sve;
 };
 
 static int parse_user_sigframe(struct user_ctxs *user,
@@ -224,6 +256,7 @@ static int parse_user_sigframe(struct user_ctxs *user,
 	bool have_extra_context = false;
 
 	user->fpsimd = NULL;
+	user->sve = NULL;
 
 	if (!IS_ALIGNED((unsigned long)base, 16))
 		goto invalid;
@@ -271,6 +304,19 @@ static int parse_user_sigframe(struct user_ctxs *user,
 			/* ignore */
 			break;
 
+		case SVE_MAGIC:
+			if (!IS_ENABLED(CONFIG_ARM64_SVE))
+				goto invalid;
+
+			if (user->sve)
+				goto invalid;
+
+			if (size < sizeof(*user->sve))
+				goto invalid;
+
+			user->sve = (struct sve_context __user *)head;
+			break;
+
 		case EXTRA_MAGIC:
 			if (have_extra_context)
 				goto invalid;
@@ -417,6 +463,15 @@ static int setup_sigframe_layout(struct rt_sigframe_user_layout *user)
 			return err;
 	}
 
+	if (IS_ENABLED(CONFIG_ARM64_SVE) && (elf_hwcap & HWCAP_SVE)) {
+		unsigned int vq = sve_vq_from_vl(sve_get_vl());
+
+		err = sigframe_alloc(user, &user->sve_offset,
+				     SVE_SIG_CONTEXT_SIZE(vq));
+		if (err)
+			return err;
+	}
+
 	return sigframe_alloc_end(user);
 }
 
@@ -458,6 +513,13 @@ static int setup_sigframe(struct rt_sigframe_user_layout *user,
 		__put_user_error(current->thread.fault_code, &esr_ctx->esr, err);
 	}
 
+	/* Scalable Vector Extension state, if present */
+	if (IS_ENABLED(CONFIG_ARM64_SVE) && err == 0 && user->sve_offset) {
+		struct sve_context __user *sve_ctx =
+			apply_user_offset(user, user->sve_offset);
+		err |= preserve_sve_context(sve_ctx);
+	}
+
 	if (err == 0 && user->extra_offset) {
 		struct extra_context __user *extra =
 			apply_user_offset(user, user->extra_offset);
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [RFC PATCH v2 17/41] arm64/sve: signal: Dump Scalable Vector Extension registers to user stack
  2017-03-22 14:50 ` Dave Martin
                   ` (16 preceding siblings ...)
  (?)
@ 2017-03-22 14:50 ` Dave Martin
  -1 siblings, 0 replies; 75+ messages in thread
From: Dave Martin @ 2017-03-22 14:50 UTC (permalink / raw)
  To: linux-arm-kernel

This patch populates the sve_regs() area reserved on the user stack
with the actual register context.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
---
 arch/arm64/include/asm/fpsimd.h | 1 +
 arch/arm64/kernel/fpsimd.c      | 3 +--
 arch/arm64/kernel/signal.c      | 8 ++++++++
 3 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/include/asm/fpsimd.h b/arch/arm64/include/asm/fpsimd.h
index 93ae8a7..be292c5 100644
--- a/arch/arm64/include/asm/fpsimd.h
+++ b/arch/arm64/include/asm/fpsimd.h
@@ -95,6 +95,7 @@ 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);
+extern void *__sve_state(struct task_struct *task);
 
 #endif
 
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index 801f4d3..1bdf7f2 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -93,7 +93,7 @@ static DEFINE_PER_CPU(struct fpsimd_state *, fpsimd_last_state);
 
 #ifdef CONFIG_ARM64_SVE
 
-static void *__sve_state(struct task_struct *task)
+void *__sve_state(struct task_struct *task)
 {
 	return (char *)task + ALIGN(sizeof(*task), 16);
 }
@@ -153,7 +153,6 @@ static void sve_to_fpsimd(struct task_struct *task)
 #else /* ! CONFIG_ARM64_SVE */
 
 /* Dummy declarations for usage protected with IS_ENABLED(CONFIG_ARM64_SVE): */
-extern void *__sve_state(struct task_struct *task);
 extern void *sve_pffr(struct task_struct *task);
 extern void fpsimd_to_sve(struct task_struct *task);
 
diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c
index 113502e..6b83917 100644
--- a/arch/arm64/kernel/signal.c
+++ b/arch/arm64/kernel/signal.c
@@ -229,6 +229,14 @@ static int preserve_sve_context(struct sve_context __user *ctx)
 	BUILD_BUG_ON(sizeof(ctx->__reserved) != sizeof(reserved));
 	err |= copy_to_user(&ctx->__reserved, reserved, sizeof(reserved));
 
+	/*
+	 * This assumes that the SVE state has already been saved to
+	 * the task struct by calling preserve_fpsimd_context().
+	 */
+	err |= copy_to_user((char __user *)ctx + SVE_SIG_REGS_OFFSET,
+			    __sve_state(current),
+			    SVE_SIG_REGS_SIZE(vq));
+
 	return err ? -EFAULT : 0;
 }
 
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [RFC PATCH v2 18/41] arm64/sve: signal: Restore FPSIMD/SVE state in rt_sigreturn
  2017-03-22 14:50 ` Dave Martin
                   ` (17 preceding siblings ...)
  (?)
@ 2017-03-22 14:50 ` Dave Martin
  -1 siblings, 0 replies; 75+ messages in thread
From: Dave Martin @ 2017-03-22 14:50 UTC (permalink / raw)
  To: linux-arm-kernel

This patch adds the missing logic to restore the SVE state in
rt_sigreturn.

Because the FPSIMD and SVE state alias, this code replaces the
existing fpsimd restore code when there is SVE state to restore.

For Zn[127:0], the saved FPSIMD state in Vn takes precedence.

Since __task_fpsimd_to_sve() is used to merge the FPSIMD and SVE
state back together, and only for this purpose, we don't want it to
zero out the SVE state -- hence delete the memset() from there.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
---
 arch/arm64/kernel/fpsimd.c |  4 ---
 arch/arm64/kernel/signal.c | 87 ++++++++++++++++++++++++++++++++++++++++------
 2 files changed, 76 insertions(+), 15 deletions(-)

diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index 1bdf7f2..952dd20 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -113,7 +113,6 @@ static void __fpsimd_to_sve(struct task_struct *task, unsigned int vq)
 	struct fpsimd_state *fst = &task->thread.fpsimd_state;
 	unsigned int i;
 
-	memset(sst, 0, sizeof(*sst));
 	for (i = 0; i < 32; ++i)
 		sst->zregs[i][0] = fst->vregs[i];
 }
@@ -288,9 +287,6 @@ void fpsimd_preserve_current_state(void)
 
 void fpsimd_signal_preserve_current_state(void)
 {
-	WARN_ONCE(elf_hwcap & HWCAP_SVE,
-		  "SVE state save/restore around signals doesn't work properly, expect userspace corruption!\n");
-
 	fpsimd_preserve_current_state();
 	sve_to_fpsimd(current);
 }
diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c
index 6b83917..9d4f7c8 100644
--- a/arch/arm64/kernel/signal.c
+++ b/arch/arm64/kernel/signal.c
@@ -211,6 +211,11 @@ static int restore_fpsimd_context(struct fpsimd_context __user *ctx)
 }
 
 
+struct user_ctxs {
+	struct fpsimd_context __user *fpsimd;
+	struct sve_context __user *sve;
+};
+
 #ifdef CONFIG_ARM64_SVE
 
 static int preserve_sve_context(struct sve_context __user *ctx)
@@ -240,19 +245,68 @@ static int preserve_sve_context(struct sve_context __user *ctx)
 	return err ? -EFAULT : 0;
 }
 
+static int __restore_sve_fpsimd_context(struct user_ctxs *user,
+					unsigned int vl, unsigned int vq)
+{
+	int err;
+	struct fpsimd_sve_state(vq) *task_sve_regs =
+		__sve_state(current);
+	struct fpsimd_state fpsimd;
+
+	if (vl != sve_get_vl())
+		return -EINVAL;
+
+	BUG_ON(SVE_SIG_REGS_SIZE(vq) > sizeof(*task_sve_regs));
+	BUG_ON(round_up(SVE_SIG_REGS_SIZE(vq), 16) < sizeof(*task_sve_regs));
+	BUG_ON(SVE_SIG_FFR_OFFSET(vq) - SVE_SIG_REGS_OFFSET !=
+	       (char *)&task_sve_regs->ffr - (char *)task_sve_regs);
+	err = __copy_from_user(task_sve_regs,
+			       (char __user const *)user->sve +
+					SVE_SIG_REGS_OFFSET,
+			       SVE_SIG_REGS_SIZE(vq));
+	if (err)
+		return err;
+
+	/* copy the FP and status/control registers */
+	/* restore_sigframe() already checked that user->fpsimd != NULL. */
+	err = __copy_from_user(fpsimd.vregs, user->fpsimd->vregs,
+			       sizeof(fpsimd.vregs));
+	__get_user_error(fpsimd.fpsr, &user->fpsimd->fpsr, err);
+	__get_user_error(fpsimd.fpcr, &user->fpsimd->fpcr, err);
+
+	/* load the hardware registers from the fpsimd_state structure */
+	if (!err)
+		fpsimd_update_current_state(&fpsimd);
+
+	return err;
+}
+
+static int restore_sve_fpsimd_context(struct user_ctxs *user)
+{
+	int err;
+	u16 vl, vq;
+
+	err = __get_user(vl, &user->sve->vl);
+	if (err)
+		return err;
+
+	if (!sve_vl_valid(vl))
+		return -EINVAL;
+
+	vq = sve_vq_from_vl(vl);
+
+	return __restore_sve_fpsimd_context(user, vl, vq);
+}
+
 #else /* ! CONFIG_ARM64_SVE */
 
-/* Turn any non-optimised out attempt to use this into a link error: */
+/* Turn any non-optimised out attempts to use these into a link error: */
 extern int preserve_sve_context(void __user *ctx);
+extern int restore_sve_fpsimd_context(struct user_ctxs *user);
 
 #endif /* ! CONFIG_ARM64_SVE */
 
 
-struct user_ctxs {
-	struct fpsimd_context __user *fpsimd;
-	struct sve_context __user *sve;
-};
-
 static int parse_user_sigframe(struct user_ctxs *user,
 			       struct rt_sigframe __user *sf)
 {
@@ -316,6 +370,9 @@ static int parse_user_sigframe(struct user_ctxs *user,
 			if (!IS_ENABLED(CONFIG_ARM64_SVE))
 				goto invalid;
 
+			if (!(elf_hwcap & HWCAP_SVE))
+				goto invalid;
+
 			if (user->sve)
 				goto invalid;
 
@@ -375,9 +432,6 @@ static int parse_user_sigframe(struct user_ctxs *user,
 	}
 
 done:
-	if (!user->fpsimd)
-		goto invalid;
-
 	return 0;
 
 invalid:
@@ -411,8 +465,19 @@ static int restore_sigframe(struct pt_regs *regs,
 	if (err == 0)
 		err = parse_user_sigframe(&user, sf);
 
-	if (err == 0)
-		err = restore_fpsimd_context(user.fpsimd);
+	if (err == 0) {
+		if (!user.fpsimd)
+			return -EINVAL;
+
+		if (user.sve) {
+			if (!IS_ENABLED(CONFIG_ARM64_SVE) ||
+			    !(elf_hwcap & HWCAP_SVE))
+				return -EINVAL;
+
+			err = restore_sve_fpsimd_context(&user);
+		} else
+			err = restore_fpsimd_context(user.fpsimd);
+	}
 
 	return err;
 }
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [RFC PATCH v2 19/41] arm64/sve: Avoid corruption when replacing the SVE state
  2017-03-22 14:50 ` Dave Martin
                   ` (18 preceding siblings ...)
  (?)
@ 2017-03-22 14:50 ` Dave Martin
  -1 siblings, 0 replies; 75+ messages in thread
From: Dave Martin @ 2017-03-22 14:50 UTC (permalink / raw)
  To: linux-arm-kernel

If preemption occurs during replacement of the whole SVE state,
as occurs during execve() or rt_sigreturn(), then some or all of
the new state for the thread can be lost, due to erroneous saving
of the pre-existing state over the new data.

This patch disables preemption around the affected operations to
avoid this failure mode.

This should be reexamined later if the impact on preemption latency
proves to be excessive.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
---
 arch/arm64/kernel/fpsimd.c | 4 ++++
 arch/arm64/kernel/signal.c | 9 ++++++++-
 2 files changed, 12 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index 952dd20..f3006a6 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -254,6 +254,8 @@ void fpsimd_flush_thread(void)
 	if (!system_supports_fpsimd())
 		return;
 
+	preempt_disable();
+
 	fpsimd_flush_task_state(current);
 
 	memset(&current->thread.fpsimd_state, 0, sizeof(struct fpsimd_state));
@@ -269,6 +271,8 @@ void fpsimd_flush_thread(void)
 	}
 
 	set_thread_flag(TIF_FOREIGN_FPSTATE);
+
+	preempt_enable();
 }
 
 /*
diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c
index 9d4f7c8..c3e15e2 100644
--- a/arch/arm64/kernel/signal.c
+++ b/arch/arm64/kernel/signal.c
@@ -256,6 +256,10 @@ static int __restore_sve_fpsimd_context(struct user_ctxs *user,
 	if (vl != sve_get_vl())
 		return -EINVAL;
 
+	preempt_disable();
+
+	set_thread_flag(TIF_FOREIGN_FPSTATE);
+
 	BUG_ON(SVE_SIG_REGS_SIZE(vq) > sizeof(*task_sve_regs));
 	BUG_ON(round_up(SVE_SIG_REGS_SIZE(vq), 16) < sizeof(*task_sve_regs));
 	BUG_ON(SVE_SIG_FFR_OFFSET(vq) - SVE_SIG_REGS_OFFSET !=
@@ -265,7 +269,7 @@ static int __restore_sve_fpsimd_context(struct user_ctxs *user,
 					SVE_SIG_REGS_OFFSET,
 			       SVE_SIG_REGS_SIZE(vq));
 	if (err)
-		return err;
+		goto out_preempt;
 
 	/* copy the FP and status/control registers */
 	/* restore_sigframe() already checked that user->fpsimd != NULL. */
@@ -278,6 +282,9 @@ static int __restore_sve_fpsimd_context(struct user_ctxs *user,
 	if (!err)
 		fpsimd_update_current_state(&fpsimd);
 
+out_preempt:
+	preempt_enable();
+
 	return err;
 }
 
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [RFC PATCH v2 20/41] arm64/sve: traps: Add descriptive string for SVE exceptions
  2017-03-22 14:50 ` Dave Martin
                   ` (19 preceding siblings ...)
  (?)
@ 2017-03-22 14:50 ` Dave Martin
  -1 siblings, 0 replies; 75+ messages in thread
From: Dave Martin @ 2017-03-22 14:50 UTC (permalink / raw)
  To: linux-arm-kernel

In preparation for SVE trapping in userspace, let's print something
relevant instead of "UNREGOCNIZED EC" when an unhandled SVE
exception occurs.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
---
 arch/arm64/include/asm/esr.h | 3 ++-
 arch/arm64/kernel/traps.c    | 1 +
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/include/asm/esr.h b/arch/arm64/include/asm/esr.h
index d14c478..87729f3 100644
--- a/arch/arm64/include/asm/esr.h
+++ b/arch/arm64/include/asm/esr.h
@@ -42,7 +42,8 @@
 #define ESR_ELx_EC_HVC64	(0x16)
 #define ESR_ELx_EC_SMC64	(0x17)
 #define ESR_ELx_EC_SYS64	(0x18)
-/* Unallocated EC: 0x19 - 0x1E */
+#define ESR_ELx_EC_SVE		(0x19)
+/* Unallocated EC: 0x1A - 0x1E */
 #define ESR_ELx_EC_IMP_DEF	(0x1f)
 #define ESR_ELx_EC_IABT_LOW	(0x20)
 #define ESR_ELx_EC_IABT_CUR	(0x21)
diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c
index e52be6a..e2e7c3c 100644
--- a/arch/arm64/kernel/traps.c
+++ b/arch/arm64/kernel/traps.c
@@ -587,6 +587,7 @@ static const char *esr_class_str[] = {
 	[ESR_ELx_EC_HVC64]		= "HVC (AArch64)",
 	[ESR_ELx_EC_SMC64]		= "SMC (AArch64)",
 	[ESR_ELx_EC_SYS64]		= "MSR/MRS (AArch64)",
+	[ESR_ELx_EC_SVE]		= "SVE",
 	[ESR_ELx_EC_IMP_DEF]		= "EL3 IMP DEF",
 	[ESR_ELx_EC_IABT_LOW]		= "IABT (lower EL)",
 	[ESR_ELx_EC_IABT_CUR]		= "IABT (current EL)",
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [RFC PATCH v2 21/41] arm64/sve: Enable SVE on demand for userspace
  2017-03-22 14:50 ` Dave Martin
                   ` (20 preceding siblings ...)
  (?)
@ 2017-03-22 14:50 ` Dave Martin
  2017-03-22 16:48   ` Mark Rutland
  -1 siblings, 1 reply; 75+ messages in thread
From: Dave Martin @ 2017-03-22 14:50 UTC (permalink / raw)
  To: linux-arm-kernel

This patch tracks whether a task has ever attempted to use the
Scalable Vector Extension.  If and only if SVE is in use by a task,
it will be enabled for userspace when scheduling the task in.  For
other tasks, SVE is disabled when scheduling in.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
---
 arch/arm64/include/asm/thread_info.h |  1 +
 arch/arm64/kernel/entry.S            | 18 +++++++++++++++++-
 arch/arm64/kernel/fpsimd.c           | 28 ++++++++++++++++++++++++++++
 3 files changed, 46 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/thread_info.h
index 46c3b93..272c32d 100644
--- a/arch/arm64/include/asm/thread_info.h
+++ b/arch/arm64/include/asm/thread_info.h
@@ -91,6 +91,7 @@ struct thread_info {
 #define TIF_SYSCALL_AUDIT	9
 #define TIF_SYSCALL_TRACEPOINT	10
 #define TIF_SECCOMP		11
+#define TIF_SVE			17	/* Scalable Vector Extension in use */
 #define TIF_MEMDIE		18	/* is terminating due to OOM killer */
 #define TIF_FREEZE		19
 #define TIF_RESTORE_SIGMASK	20
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
index 43512d4..a9ae051 100644
--- a/arch/arm64/kernel/entry.S
+++ b/arch/arm64/kernel/entry.S
@@ -524,6 +524,10 @@ el0_sync:
 	b.eq	el0_ia
 	cmp	x24, #ESR_ELx_EC_FP_ASIMD	// FP/ASIMD access
 	b.eq	el0_fpsimd_acc
+#ifdef CONFIG_ARM64_SVE
+	cmp	x24, #ESR_ELx_EC_SVE		// SVE access
+	b.eq	el0_sve_acc
+#endif
 	cmp	x24, #ESR_ELx_EC_FP_EXC64	// FP/ASIMD exception
 	b.eq	el0_fpsimd_exc
 	cmp	x24, #ESR_ELx_EC_SYS64		// configurable trap
@@ -622,9 +626,21 @@ el0_fpsimd_acc:
 	mov	x1, sp
 	bl	do_fpsimd_acc
 	b	ret_to_user
+#ifdef CONFIG_ARM64_SVE
+	/*
+	 * Scalable Vector Extension access
+	 */
+el0_sve_acc:
+	enable_dbg
+	ct_user_exit
+	mov	x0, x25
+	mov	x1, sp
+	bl	do_sve_acc
+	b	ret_to_user
+#endif
 el0_fpsimd_exc:
 	/*
-	 * Floating Point or Advanced SIMD exception
+	 * Floating Point, Advanced SIMD or SVE exception
 	 */
 	enable_dbg
 	ct_user_exit
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index f3006a6..749f4f0 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -149,6 +149,18 @@ static void sve_to_fpsimd(struct task_struct *task)
 	__sve_to_fpsimd(task, sve_vq_from_vl(vl));
 }
 
+void do_sve_acc(unsigned int esr, struct pt_regs *regs)
+{
+	unsigned long tmp;
+
+	if (test_and_set_thread_flag(TIF_SVE))
+		BUG();
+
+	asm ("mrs %0, cpacr_el1" : "=r" (tmp));
+	asm volatile ("msr cpacr_el1, %0" :: "r" (tmp | (1 << 17)));
+	/* Serialised by exception return to user */
+}
+
 #else /* ! CONFIG_ARM64_SVE */
 
 /* Dummy declarations for usage protected with IS_ENABLED(CONFIG_ARM64_SVE): */
@@ -306,11 +318,27 @@ void fpsimd_restore_current_state(void)
 		return;
 	preempt_disable();
 	if (test_and_clear_thread_flag(TIF_FOREIGN_FPSTATE)) {
+		unsigned long tmp;
+		unsigned long flags;
+
 		struct fpsimd_state *st = &current->thread.fpsimd_state;
 
 		task_fpsimd_load(current);
 		this_cpu_write(fpsimd_last_state, st);
 		st->cpu = smp_processor_id();
+
+		if (IS_ENABLED(CONFIG_ARM64_SVE)) {
+			/*
+			 * Flip SVE enable for userspace if it doesn't
+			 * match the current_task.
+			 */
+			asm ("mrs %0, cpacr_el1" : "=r" (tmp));
+			flags = current_thread_info()->flags;
+			if ((tmp ^ (unsigned long)flags) & (1 << 17)) {
+				tmp ^= 1 << 17;
+				asm volatile ("msr cpacr_el1, %0" :: "r" (tmp));
+			}
+		}
 	}
 	preempt_enable();
 }
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [RFC PATCH v2 22/41] arm64/sve: Implement FPSIMD-only context for tasks not using SVE
  2017-03-22 14:50 ` Dave Martin
                   ` (21 preceding siblings ...)
  (?)
@ 2017-03-22 14:50 ` Dave Martin
  -1 siblings, 0 replies; 75+ messages in thread
From: Dave Martin @ 2017-03-22 14:50 UTC (permalink / raw)
  To: linux-arm-kernel

To reduce unnecessary context switch overhead, we don't need to
switch the whole SVE state for tasks that are not using it.

This patch restores the FPSIMD-only behaviour for tasks that have
never used SVE.

Note that coredumps and ptrace may see FPSIMD/SVE out of sync at
present -- this will be fixed later.

SVE state is saved on signal delivery only for tasks that have
used SVE.  However, it should be possible to add SVE state on
return from a signal handler when the task didn't have any SVE
state previously.  The caller may need to add its own SVE record
to the signal frame in this case.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
---
 arch/arm64/kernel/fpsimd.c | 28 ++++++++++++++++++----------
 arch/arm64/kernel/signal.c |  5 ++++-
 2 files changed, 22 insertions(+), 11 deletions(-)

diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index 749f4f0..260438d 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -156,6 +156,10 @@ void do_sve_acc(unsigned int esr, struct pt_regs *regs)
 	if (test_and_set_thread_flag(TIF_SVE))
 		BUG();
 
+	BUG_ON(is_compat_task());
+
+	fpsimd_to_sve(current);
+
 	asm ("mrs %0, cpacr_el1" : "=r" (tmp));
 	asm volatile ("msr cpacr_el1, %0" :: "r" (tmp | (1 << 17)));
 	/* Serialised by exception return to user */
@@ -210,7 +214,8 @@ void do_fpsimd_exc(unsigned int esr, struct pt_regs *regs)
 
 static void task_fpsimd_load(struct task_struct *task)
 {
-	if (IS_ENABLED(CONFIG_ARM64_SVE) && (elf_hwcap & HWCAP_SVE))
+	if (IS_ENABLED(CONFIG_ARM64_SVE) &&
+	    test_tsk_thread_flag(task, TIF_SVE))
 		sve_load_state(sve_pffr(task),
 			       &task->thread.fpsimd_state.fpsr);
 	else
@@ -222,7 +227,8 @@ static void task_fpsimd_save(struct task_struct *task)
 	/* FIXME: remove task argument? */
 	BUG_ON(task != current);
 
-	if (IS_ENABLED(CONFIG_ARM64_SVE) && (elf_hwcap & HWCAP_SVE))
+	if (IS_ENABLED(CONFIG_ARM64_SVE) &&
+	    test_tsk_thread_flag(task, TIF_SVE))
 		sve_save_state(sve_pffr(task),
 			       &task->thread.fpsimd_state.fpsr);
 	else
@@ -253,11 +259,9 @@ void fpsimd_thread_switch(struct task_struct *next)
 
 		if (__this_cpu_read(fpsimd_last_state) == st
 		    && st->cpu == smp_processor_id())
-			clear_ti_thread_flag(task_thread_info(next),
-					     TIF_FOREIGN_FPSTATE);
+			clear_tsk_thread_flag(next, TIF_FOREIGN_FPSTATE);
 		else
-			set_ti_thread_flag(task_thread_info(next),
-					   TIF_FOREIGN_FPSTATE);
+			set_tsk_thread_flag(next, TIF_FOREIGN_FPSTATE);
 	}
 }
 
@@ -304,7 +308,8 @@ void fpsimd_preserve_current_state(void)
 void fpsimd_signal_preserve_current_state(void)
 {
 	fpsimd_preserve_current_state();
-	sve_to_fpsimd(current);
+	if (test_thread_flag(TIF_SVE))
+		sve_to_fpsimd(current);
 }
 
 /*
@@ -354,7 +359,7 @@ void fpsimd_update_current_state(struct fpsimd_state *state)
 		return;
 	preempt_disable();
 
-	if (IS_ENABLED(CONFIG_ARM64_SVE)) {
+	if (IS_ENABLED(CONFIG_ARM64_SVE) && test_thread_flag(TIF_SVE)) {
 		current->thread.fpsimd_state = *state;
 		fpsimd_to_sve(current);
 	}
@@ -398,8 +403,8 @@ void kernel_neon_begin_partial(u32 num_regs)
 	 * interrupt context, so always save the userland SVE state
 	 * if there is any, even for interrupts.
 	 */
-	if (IS_ENABLED(CONFIG_ARM64_SVE) && (elf_hwcap & HWCAP_SVE) &&
-	    current->mm &&
+	if (IS_ENABLED(CONFIG_ARM64_SVE) &&
+	    test_thread_flag(TIF_SVE) && current->mm &&
 	    !test_and_set_thread_flag(TIF_FOREIGN_FPSTATE)) {
 		fpsimd_save_state(&current->thread.fpsimd_state);
 		this_cpu_write(fpsimd_last_state, NULL);
@@ -527,6 +532,9 @@ static int __init fpsimd_init(void)
 	if (!(elf_hwcap & HWCAP_ASIMD))
 		pr_notice("Advanced SIMD is not implemented\n");
 
+	if (!(elf_hwcap & HWCAP_SVE))
+		pr_info("Scalable Vector Extension available\n");
+
 	return 0;
 }
 late_initcall(fpsimd_init);
diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c
index c3e15e2..619dca5 100644
--- a/arch/arm64/kernel/signal.c
+++ b/arch/arm64/kernel/signal.c
@@ -259,6 +259,7 @@ static int __restore_sve_fpsimd_context(struct user_ctxs *user,
 	preempt_disable();
 
 	set_thread_flag(TIF_FOREIGN_FPSTATE);
+	set_thread_flag(TIF_SVE);
 
 	BUG_ON(SVE_SIG_REGS_SIZE(vq) > sizeof(*task_sve_regs));
 	BUG_ON(round_up(SVE_SIG_REGS_SIZE(vq), 16) < sizeof(*task_sve_regs));
@@ -543,9 +544,11 @@ static int setup_sigframe_layout(struct rt_sigframe_user_layout *user)
 			return err;
 	}
 
-	if (IS_ENABLED(CONFIG_ARM64_SVE) && (elf_hwcap & HWCAP_SVE)) {
+	if (IS_ENABLED(CONFIG_ARM64_SVE) && test_thread_flag(TIF_SVE)) {
 		unsigned int vq = sve_vq_from_vl(sve_get_vl());
 
+		BUG_ON(!(elf_hwcap & HWCAP_SVE));
+
 		err = sigframe_alloc(user, &user->sve_offset,
 				     SVE_SIG_CONTEXT_SIZE(vq));
 		if (err)
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [RFC PATCH v2 23/41] arm64/sve: Move ZEN handling to the common task_fpsimd_load() path
  2017-03-22 14:50 ` Dave Martin
                   ` (22 preceding siblings ...)
  (?)
@ 2017-03-22 14:50 ` Dave Martin
  2017-03-22 16:55   ` Mark Rutland
  -1 siblings, 1 reply; 75+ messages in thread
From: Dave Martin @ 2017-03-22 14:50 UTC (permalink / raw)
  To: linux-arm-kernel

Currently, ZEN is handled only in fpsimd_restore_current_state(),
which is not sufficient since it applies only in certain
situations.

Since all the relevant paths call task_fpsimd_load(), this patch
moves the ZEN handling there.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
---
 arch/arm64/include/asm/thread_info.h |  1 +
 arch/arm64/kernel/fpsimd.c           | 50 ++++++++++++++++++++----------------
 2 files changed, 29 insertions(+), 22 deletions(-)

diff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/thread_info.h
index 272c32d..a0f5498 100644
--- a/arch/arm64/include/asm/thread_info.h
+++ b/arch/arm64/include/asm/thread_info.h
@@ -107,6 +107,7 @@ struct thread_info {
 #define _TIF_SYSCALL_AUDIT	(1 << TIF_SYSCALL_AUDIT)
 #define _TIF_SYSCALL_TRACEPOINT	(1 << TIF_SYSCALL_TRACEPOINT)
 #define _TIF_SECCOMP		(1 << TIF_SECCOMP)
+#define _TIF_SVE		(1 << TIF_SVE)
 #define _TIF_UPROBE		(1 << TIF_UPROBE)
 #define _TIF_32BIT		(1 << TIF_32BIT)
 
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index 260438d..5fb5585 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -37,6 +37,9 @@
 #define FPEXC_IXF	(1 << 4)
 #define FPEXC_IDF	(1 << 7)
 
+/* Forward declarations for local functions used by both SVE and FPSIMD */
+static void task_fpsimd_load(struct task_struct *task);
+
 /*
  * In order to reduce the number of times the FPSIMD state is needlessly saved
  * and restored, we need to keep track of two things:
@@ -151,18 +154,20 @@ static void sve_to_fpsimd(struct task_struct *task)
 
 void do_sve_acc(unsigned int esr, struct pt_regs *regs)
 {
-	unsigned long tmp;
+	if (test_and_set_thread_flag(TIF_SVE)) {
+		unsigned long tmp;
 
-	if (test_and_set_thread_flag(TIF_SVE))
+		asm ("mrs %0, cpacr_el1" : "=r" (tmp));
+
+		printk(KERN_INFO "%s: Strange, ZEN=%u\n",
+		       __func__, (unsigned int)((tmp >> 16) & 3));
 		BUG();
+	}
 
 	BUG_ON(is_compat_task());
 
 	fpsimd_to_sve(current);
-
-	asm ("mrs %0, cpacr_el1" : "=r" (tmp));
-	asm volatile ("msr cpacr_el1, %0" :: "r" (tmp | (1 << 17)));
-	/* Serialised by exception return to user */
+	task_fpsimd_load(current);
 }
 
 #else /* ! CONFIG_ARM64_SVE */
@@ -220,6 +225,23 @@ static void task_fpsimd_load(struct task_struct *task)
 			       &task->thread.fpsimd_state.fpsr);
 	else
 		fpsimd_load_state(&task->thread.fpsimd_state);
+
+	/*
+	 * Flip SVE enable for userspace if it doesn't match the
+	 * current_task.
+	 */
+	if (IS_ENABLED(CONFIG_ARM64_SVE) && (elf_hwcap & HWCAP_SVE)) {
+		unsigned int tmp, flags;
+
+		asm ("mrs %0, cpacr_el1" : "=r" (tmp));
+		flags = task_thread_info(task)->flags;
+		BUILD_BUG_ON(_TIF_SVE != CPACR_EL1_ZEN_EL0EN);
+		if ((tmp ^ (unsigned long)flags) & _TIF_SVE) {
+			tmp ^= _TIF_SVE;
+			asm volatile ("msr cpacr_el1, %0" :: "r" (tmp));
+			/* Serialised by exception return to user */
+		}
+	}
 }
 
 static void task_fpsimd_save(struct task_struct *task)
@@ -323,27 +345,11 @@ void fpsimd_restore_current_state(void)
 		return;
 	preempt_disable();
 	if (test_and_clear_thread_flag(TIF_FOREIGN_FPSTATE)) {
-		unsigned long tmp;
-		unsigned long flags;
-
 		struct fpsimd_state *st = &current->thread.fpsimd_state;
 
 		task_fpsimd_load(current);
 		this_cpu_write(fpsimd_last_state, st);
 		st->cpu = smp_processor_id();
-
-		if (IS_ENABLED(CONFIG_ARM64_SVE)) {
-			/*
-			 * Flip SVE enable for userspace if it doesn't
-			 * match the current_task.
-			 */
-			asm ("mrs %0, cpacr_el1" : "=r" (tmp));
-			flags = current_thread_info()->flags;
-			if ((tmp ^ (unsigned long)flags) & (1 << 17)) {
-				tmp ^= 1 << 17;
-				asm volatile ("msr cpacr_el1, %0" :: "r" (tmp));
-			}
-		}
 	}
 	preempt_enable();
 }
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [RFC PATCH v2 24/41] arm64/sve: Discard SVE state on system call
  2017-03-22 14:50 ` Dave Martin
                   ` (23 preceding siblings ...)
  (?)
@ 2017-03-22 14:50 ` Dave Martin
  2017-03-22 17:03   ` Mark Rutland
  -1 siblings, 1 reply; 75+ messages in thread
From: Dave Martin @ 2017-03-22 14:50 UTC (permalink / raw)
  To: linux-arm-kernel

The base procedure call standard for the Scalable Vector Extension
defines all of the SVE programmer's model state (Z0-31, P0-15, FFR)
as caller-save, except for that subset of the state that aliases
FPSIMD state.

System calls from userspace will almost always be made through C
library wrappers -- as a consequence of the PCS there will thus
rarely if ever be any live SVE state at syscall entry in practice.

This gives us an opportinity to make SVE explicitly caller-save
around SVC and so stop carrying around the SVE state for tasks that
use SVE only occasionally (say, by calling a library).

Note that FPSIMD state will still be preserved around SVC.

As a crude heuristic to avoid pathological cases where a thread
that uses SVE frequently has to fault back into the kernel again to
re-enable SVE after a syscall, we switch the thread back to
FPSIMD-only context tracking only if the context is actually
switched out before returning to userspace.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
---
 arch/arm64/kernel/fpsimd.c | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index 5fb5585..8c18384 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -250,6 +250,23 @@ static void task_fpsimd_save(struct task_struct *task)
 	BUG_ON(task != current);
 
 	if (IS_ENABLED(CONFIG_ARM64_SVE) &&
+	    task_pt_regs(task)->syscallno != ~0UL &&
+	    test_tsk_thread_flag(task, TIF_SVE)) {
+		unsigned long tmp;
+
+		clear_tsk_thread_flag(task, TIF_SVE);
+
+		/* Trap if the task tries to use SVE again: */
+		asm volatile (
+			"mrs	%[tmp], cpacr_el1\n\t"
+			"bic	%[tmp], %[tmp], %[mask]\n\t"
+			"msr	cpacr_el1, %[tmp]"
+			: [tmp] "=r" (tmp)
+			: [mask] "i" (CPACR_EL1_ZEN_EL0EN)
+		);
+	}
+
+	if (IS_ENABLED(CONFIG_ARM64_SVE) &&
 	    test_tsk_thread_flag(task, TIF_SVE))
 		sve_save_state(sve_pffr(task),
 			       &task->thread.fpsimd_state.fpsr);
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [RFC PATCH v2 25/41] arm64/sve: Avoid preempt_disable() during sigreturn
  2017-03-22 14:50 ` Dave Martin
                   ` (24 preceding siblings ...)
  (?)
@ 2017-03-22 14:50 ` Dave Martin
  -1 siblings, 0 replies; 75+ messages in thread
From: Dave Martin @ 2017-03-22 14:50 UTC (permalink / raw)
  To: linux-arm-kernel

Currently the sigreturn implementation for SVE relies on
preempt_disable() to avoid an intervening context switch from
corrupting the SVE state in the task_struct.

Unforunately, __get_user() and friends are not safe under
preempt_disable().

As an alternative, this patch removes preempt_disable() and sets
TIF_FOREIGN_FPSTATE instead: this will inform the context switch
code that the current CPU registers don't contain the SVE/FPSIMD
state of the current task, preventing writeback to the task_struct
during context switch.

To avoid an intervening context switch from spontaneously clearing
TIF_FOREIGN_FPSTATE again while doing this,
fpsimd_flush_task_state() is also called beforehand.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
---
 arch/arm64/kernel/signal.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c
index 619dca5..20bc312 100644
--- a/arch/arm64/kernel/signal.c
+++ b/arch/arm64/kernel/signal.c
@@ -256,10 +256,10 @@ static int __restore_sve_fpsimd_context(struct user_ctxs *user,
 	if (vl != sve_get_vl())
 		return -EINVAL;
 
-	preempt_disable();
-
+	fpsimd_flush_task_state(current);
+	barrier();
 	set_thread_flag(TIF_FOREIGN_FPSTATE);
-	set_thread_flag(TIF_SVE);
+	barrier();
 
 	BUG_ON(SVE_SIG_REGS_SIZE(vq) > sizeof(*task_sve_regs));
 	BUG_ON(round_up(SVE_SIG_REGS_SIZE(vq), 16) < sizeof(*task_sve_regs));
@@ -270,7 +270,7 @@ static int __restore_sve_fpsimd_context(struct user_ctxs *user,
 					SVE_SIG_REGS_OFFSET,
 			       SVE_SIG_REGS_SIZE(vq));
 	if (err)
-		goto out_preempt;
+		return err;
 
 	/* copy the FP and status/control registers */
 	/* restore_sigframe() already checked that user->fpsimd != NULL. */
@@ -279,13 +279,13 @@ static int __restore_sve_fpsimd_context(struct user_ctxs *user,
 	__get_user_error(fpsimd.fpsr, &user->fpsimd->fpsr, err);
 	__get_user_error(fpsimd.fpcr, &user->fpsimd->fpcr, err);
 
+	barrier();
+	set_thread_flag(TIF_SVE);
+
 	/* load the hardware registers from the fpsimd_state structure */
 	if (!err)
 		fpsimd_update_current_state(&fpsimd);
 
-out_preempt:
-	preempt_enable();
-
 	return err;
 }
 
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [RFC PATCH v2 26/41] arm64/sve: Avoid stale user register state after SVE access exception
  2017-03-22 14:50 ` Dave Martin
                   ` (25 preceding siblings ...)
  (?)
@ 2017-03-22 14:50 ` Dave Martin
  -1 siblings, 0 replies; 75+ messages in thread
From: Dave Martin @ 2017-03-22 14:50 UTC (permalink / raw)
  To: linux-arm-kernel

Currently, when an SVE access exception is taken from userspace,
the FPSIMD state in the task_struct is converted to SVE state and
reloaded as SVE state.

Unfortunately, since we've been executing in userspace there's no
guarantee that the FPSIMD state saved will actually be up to date
with respect to the registers, so updates may be lost.

This patch saves the FPSIMD state back to the task_struct first, to
ensure that the task_struct copy of the data is up to date.

Also, the CPACR handling logic is removed since task_fpsimd_load()
handles it anyway.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
---
 arch/arm64/kernel/fpsimd.c | 16 ++++++----------
 1 file changed, 6 insertions(+), 10 deletions(-)

diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index 8c18384..4e2d796 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -39,6 +39,7 @@
 
 /* Forward declarations for local functions used by both SVE and FPSIMD */
 static void task_fpsimd_load(struct task_struct *task);
+static void task_fpsimd_save(struct task_struct *task);
 
 /*
  * In order to reduce the number of times the FPSIMD state is needlessly saved
@@ -154,19 +155,14 @@ static void sve_to_fpsimd(struct task_struct *task)
 
 void do_sve_acc(unsigned int esr, struct pt_regs *regs)
 {
-	if (test_and_set_thread_flag(TIF_SVE)) {
-		unsigned long tmp;
-
-		asm ("mrs %0, cpacr_el1" : "=r" (tmp));
-
-		printk(KERN_INFO "%s: Strange, ZEN=%u\n",
-		       __func__, (unsigned int)((tmp >> 16) & 3));
-		BUG();
-	}
-
 	BUG_ON(is_compat_task());
 
+	task_fpsimd_save(current);
+
 	fpsimd_to_sve(current);
+	if (test_and_set_thread_flag(TIF_SVE))
+		BUG(); /* We shouldn't trap if SVE was already enabled! */
+
 	task_fpsimd_load(current);
 }
 
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [RFC PATCH v2 27/41] arm64/sve: ptrace support
  2017-03-22 14:50 ` Dave Martin
                   ` (26 preceding siblings ...)
  (?)
@ 2017-03-22 14:50 ` Dave Martin
  -1 siblings, 0 replies; 75+ messages in thread
From: Dave Martin @ 2017-03-22 14:50 UTC (permalink / raw)
  To: linux-arm-kernel

From: Alan Hayward <alan.hayward@arm.com>

This patch adds support for accessing a task's SVE registers via
ptrace.

Some additional helpers are added in order to support the SVE/
FPSIMD register view synchronisation operations that are required
in order to make the NT_PRFPREG and NT_ARM_SVE regsets interact
correctly.

fpr_set()/fpr_get() are refactored into backend/frontend functions,
so that the core can be reused by sve_set()/sve_get() for the case
where no SVE registers are stored for a thread.

Signed-off-by: Alan Hayward <alan.hayward@arm.com>
Signed-off-by: Dave Martin <Dave.Martin@arm.com>
---
 arch/arm64/include/asm/fpsimd.h          |  18 +++
 arch/arm64/include/uapi/asm/ptrace.h     | 124 +++++++++++++++
 arch/arm64/include/uapi/asm/sigcontext.h |   4 +
 arch/arm64/kernel/fpsimd.c               |  38 +++++
 arch/arm64/kernel/ptrace.c               | 252 ++++++++++++++++++++++++++++++-
 include/uapi/linux/elf.h                 |   1 +
 6 files changed, 430 insertions(+), 7 deletions(-)

diff --git a/arch/arm64/include/asm/fpsimd.h b/arch/arm64/include/asm/fpsimd.h
index be292c5..71b94ee 100644
--- a/arch/arm64/include/asm/fpsimd.h
+++ b/arch/arm64/include/asm/fpsimd.h
@@ -35,6 +35,10 @@ struct fpsimd_state {
 			__uint128_t vregs[32];
 			u32 fpsr;
 			u32 fpcr;
+			/*
+			 * For ptrace compatibility, pad to next 128-bit
+			 * boundary here if extending this struct.
+			 */
 		};
 	};
 	/* the id of the last cpu to have restored this state */
@@ -97,6 +101,20 @@ extern unsigned int sve_get_vl(void);
 extern void __init fpsimd_init_task_struct_size(void);
 extern void *__sve_state(struct task_struct *task);
 
+#ifdef CONFIG_ARM64_SVE
+
+extern void fpsimd_sync_to_sve(struct task_struct *task);
+extern void sve_sync_to_fpsimd(struct task_struct *task);
+extern void sve_sync_from_fpsimd_zeropad(struct task_struct *task);
+
+#else /* ! CONFIG_ARM64_SVE */
+
+static void __maybe_unused sve_sync_to_fpsimd(struct task_struct *task) { }
+static void __maybe_unused sve_sync_from_fpsimd_zeropad(
+	struct task_struct *task) { }
+
+#endif /* ! CONFIG_ARM64_SVE */
+
 #endif
 
 #endif
diff --git a/arch/arm64/include/uapi/asm/ptrace.h b/arch/arm64/include/uapi/asm/ptrace.h
index d1ff83d..f26b68e 100644
--- a/arch/arm64/include/uapi/asm/ptrace.h
+++ b/arch/arm64/include/uapi/asm/ptrace.h
@@ -22,6 +22,7 @@
 #include <linux/types.h>
 
 #include <asm/hwcap.h>
+#include <asm/sigcontext.h>
 
 
 /*
@@ -90,6 +91,129 @@ struct user_hwdebug_state {
 	}		dbg_regs[16];
 };
 
+/* SVE/FP/SIMD state (NT_ARM_SVE) */
+
+struct user_sve_header {
+	__u32 size; /* total meaningful regset content in bytes */
+	__u32 max_size; /* maxmium possible size for this thread */
+	__u16 vl; /* current vector length */
+	__u16 max_vl; /* maximum possible vector length */
+	__u16 flags;
+	__u16 __reserved;
+};
+
+/* Definitions for user_sve_header.flags: */
+#define SVE_PT_REGS_MASK		(1 << 0)
+
+#define SVE_PT_REGS_FPSIMD		0
+#define SVE_PT_REGS_SVE			SVE_PT_REGS_MASK
+
+
+/*
+ * The remainder of the SVE state follows struct user_sve_header.  The
+ * total size of the SVE state (including header) depends on the
+ * metadata in the header:  SVE_PT_SIZE(vq, flags) gives the total size
+ * of the state in bytes, including the header.
+ *
+ * Refer to <asm/sigcontext.h> for details of how to pass the correct
+ * "vq" argument to these macros.
+ */
+
+/* Offset from the start of struct user_sve_header to the register data */
+#define SVE_PT_REGS_OFFSET	((sizeof(struct sve_context) + 15) / 16 * 16)
+
+/*
+ * The register data content and layout depends on the value of the
+ * flags field.
+ */
+
+/*
+ * (flags & SVE_PT_REGS_MASK) == SVE_PT_REGS_FPSIMD case:
+ *
+ * The payload starts at offset SVE_PT_FPSIMD_OFFSET, and is of type
+ * struct user_fpsimd_state.  Additional data might be appended in the
+ * future: use SVE_PT_FPSIMD_SIZE(vq, flags) to compute the total size.
+ * SVE_PT_FPSIMD_SIZE(vq, flags) will never be less than
+ * sizeof(struct user_fpsimd_state).
+ */
+
+#define SVE_PT_FPSIMD_OFFSET		SVE_PT_REGS_OFFSET
+
+#define SVE_PT_FPSIMD_SIZE(vq, flags)	(sizeof(struct user_fpsimd_state))
+
+/*
+ * (flags & SVE_PT_REGS_MASK) == SVE_PT_REGS_SVE case:
+ *
+ * The payload starts at offset SVE_PT_SVE_OFFSET, and is of size
+ * SVE_PT_SVE_SIZE(vq, flags).
+ *
+ * Additional macros describe the contents and layout of the payload.
+ * For each, SVE_PT_SVE_x_OFFSET(args) is the start offset relative to
+ * the start of struct user_sve_header, and SVE_PT_SVE_x_SIZE(args) is
+ * the size in bytes:
+ *
+ *	x	type				description
+ *	-	----				-----------
+ *	ZREGS		\
+ *	ZREG		|
+ *	PREGS		| refer to <asm/sigcontext.h>
+ *	PREG		|
+ *	FFR		/
+ *
+ *	FPSR	uint32_t			FPSR
+ *	FPCR	uint32_t			FPCR
+ *
+ * Additional data might be appended in the future.
+ */
+
+#define SVE_PT_SVE_ZREG_SIZE(vq)	SVE_SIG_ZREG_SIZE(vq)
+#define SVE_PT_SVE_PREG_SIZE(vq)	SVE_SIG_PREG_SIZE(vq)
+#define SVE_PT_SVE_FFR_SIZE(vq)		SVE_SIG_FFR_SIZE(vq)
+#define SVE_PT_SVE_FPSR_SIZE		sizeof(__u32)
+#define SVE_PT_SVE_FPCR_SIZE		sizeof(__u32)
+
+#define __SVE_SIG_TO_PT(offset) \
+	((offset) - SVE_SIG_REGS_OFFSET + SVE_PT_REGS_OFFSET)
+
+#define SVE_PT_SVE_OFFSET		SVE_PT_REGS_OFFSET
+
+#define SVE_PT_SVE_ZREGS_OFFSET \
+	__SVE_SIG_TO_PT(SVE_SIG_ZREGS_OFFSET)
+#define SVE_PT_SVE_ZREG_OFFSET(vq, n) \
+	__SVE_SIG_TO_PT(SVE_SIG_ZREG_OFFSET(vq, n))
+#define SVE_PT_SVE_ZREGS_SIZE(vq) \
+	(SVE_PT_SVE_ZREG_OFFSET(vq, SVE_NUM_ZREGS) - SVE_PT_SVE_ZREGS_OFFSET)
+
+#define SVE_PT_SVE_PREGS_OFFSET(vq) \
+	__SVE_SIG_TO_PT(SVE_SIG_PREGS_OFFSET(vq))
+#define SVE_PT_SVE_PREG_OFFSET(vq, n) \
+	__SVE_SIG_TO_PT(SVE_SIG_PREG_OFFSET(vq, n))
+#define SVE_PT_SVE_PREGS_SIZE(vq) \
+	(SVE_PT_SVE_PREG_OFFSET(vq, SVE_NUM_PREGS) - \
+		SVE_PT_SVE_PREGS_OFFSET(vq))
+
+#define SVE_PT_SVE_FFR_OFFSET(vq) \
+	__SVE_SIG_TO_PT(SVE_SIG_FFR_OFFSET(vq))
+
+#define SVE_PT_SVE_FPSR_OFFSET(vq) \
+	((SVE_PT_SVE_FFR_OFFSET(vq) + SVE_PT_SVE_FFR_SIZE(vq) + 15) / 16 * 16)
+#define SVE_PT_SVE_FPCR_OFFSET(vq) \
+	(SVE_PT_SVE_FPSR_OFFSET(vq) + SVE_PT_SVE_FPSR_SIZE)
+
+/*
+ * Any future extension appended after FPCR must be aligned to the next
+ * 128-bit boundary.
+ */
+
+#define SVE_PT_SVE_SIZE(vq, flags)				\
+	((SVE_PT_SVE_FPCR_OFFSET(vq) + SVE_PT_SVE_FPCR_SIZE -	\
+		SVE_PT_SVE_OFFSET + 15) / 16 * 16)
+
+#define SVE_PT_SIZE(vq, flags)						\
+	 (((flags) & SVE_PT_REGS_MASK) == SVE_PT_REGS_SVE ?		\
+		  SVE_PT_SVE_OFFSET + SVE_PT_SVE_SIZE(vq, flags)	\
+		: SVE_PT_FPSIMD_OFFSET + SVE_PT_FPSIMD_SIZE(vq, flags))
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* _UAPI__ASM_PTRACE_H */
diff --git a/arch/arm64/include/uapi/asm/sigcontext.h b/arch/arm64/include/uapi/asm/sigcontext.h
index 11c915d..91e55de 100644
--- a/arch/arm64/include/uapi/asm/sigcontext.h
+++ b/arch/arm64/include/uapi/asm/sigcontext.h
@@ -16,6 +16,8 @@
 #ifndef _UAPI__ASM_SIGCONTEXT_H
 #define _UAPI__ASM_SIGCONTEXT_H
 
+#ifndef __ASSEMBLY__
+
 #include <linux/types.h>
 
 /*
@@ -96,6 +98,8 @@ struct sve_context {
 	__u16 __reserved[3];
 };
 
+#endif /* !__ASSEMBLY__ */
+
 /*
  * The SVE architecture leaves space for future expansion of the
  * vector length beyond its initial architectural limit of 2048 bits
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index 4e2d796..ee59325 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -153,6 +153,44 @@ static void sve_to_fpsimd(struct task_struct *task)
 	__sve_to_fpsimd(task, sve_vq_from_vl(vl));
 }
 
+void fpsimd_sync_to_sve(struct task_struct *task)
+{
+	if (!test_tsk_thread_flag(task, TIF_SVE))
+		fpsimd_to_sve(task);
+}
+
+void sve_sync_to_fpsimd(struct task_struct *task)
+{
+	if (test_tsk_thread_flag(task, TIF_SVE))
+		sve_to_fpsimd(task);
+}
+
+static void __sve_sync_from_fpsimd_zeropad(struct task_struct *task,
+					   unsigned int vq)
+{
+	struct sve_struct fpsimd_sve_state(vq) *sst = __sve_state(task);
+	struct fpsimd_state *fst = &task->thread.fpsimd_state;
+	unsigned int i;
+
+	BUG_ON(!test_tsk_thread_flag(task, TIF_SVE));
+
+	memset(sst->zregs, 0, sizeof(sst->zregs));
+
+	for (i = 0; i < 32; ++i)
+		sst->zregs[i][0] = fst->vregs[i];
+}
+
+void sve_sync_from_fpsimd_zeropad(struct task_struct *task)
+{
+	unsigned int vl;
+
+	if (!test_tsk_thread_flag(task, TIF_SVE))
+		return;
+
+	vl = sve_get_vl();
+	__sve_sync_from_fpsimd_zeropad(task, sve_vq_from_vl(vl));
+}
+
 void do_sve_acc(unsigned int esr, struct pt_regs *regs)
 {
 	BUG_ON(is_compat_task());
diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
index c142459..3e97e16 100644
--- a/arch/arm64/kernel/ptrace.c
+++ b/arch/arm64/kernel/ptrace.c
@@ -31,7 +31,9 @@
 #include <linux/seccomp.h>
 #include <linux/security.h>
 #include <linux/init.h>
+#include <linux/sched.h>
 #include <linux/signal.h>
+#include <linux/string.h>
 #include <linux/uaccess.h>
 #include <linux/perf_event.h>
 #include <linux/hw_breakpoint.h>
@@ -617,29 +619,62 @@ static int gpr_set(struct task_struct *target, const struct user_regset *regset,
 /*
  * TODO: update fp accessors for lazy context switching (sync/flush hwstate)
  */
-static int fpr_get(struct task_struct *target, const struct user_regset *regset,
-		   unsigned int pos, unsigned int count,
-		   void *kbuf, void __user *ubuf)
+static int __fpr_get(struct task_struct *target,
+		     const struct user_regset *regset,
+		     unsigned int pos, unsigned int count,
+		     void *kbuf, void __user *ubuf, unsigned int start_pos)
 {
 	struct user_fpsimd_state *uregs;
+
+	sve_sync_to_fpsimd(target);
+
 	uregs = &target->thread.fpsimd_state.user_fpsimd;
-	return user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs, 0, -1);
+	return user_regset_copyout(&pos, &count, &kbuf, &ubuf, uregs,
+				   start_pos, start_pos + sizeof(*uregs));
 }
 
-static int fpr_set(struct task_struct *target, const struct user_regset *regset,
+static int fpr_get(struct task_struct *target, const struct user_regset *regset,
 		   unsigned int pos, unsigned int count,
-		   const void *kbuf, const void __user *ubuf)
+		   void *kbuf, void __user *ubuf)
+{
+	return __fpr_get(target, regset, pos, count, kbuf, ubuf, 0);
+}
+
+static int __fpr_set(struct task_struct *target,
+		     const struct user_regset *regset,
+		     unsigned int pos, unsigned int count,
+		     const void *kbuf, const void __user *ubuf,
+		     unsigned int start_pos)
 {
 	int ret;
 	struct user_fpsimd_state newstate =
 		target->thread.fpsimd_state.user_fpsimd;
 
-	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &newstate, 0, -1);
+	sve_sync_to_fpsimd(target);
+
+	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &newstate,
+				 start_pos, start_pos + sizeof(newstate));
 	if (ret)
 		return ret;
 
 	target->thread.fpsimd_state.user_fpsimd = newstate;
+
+	return ret;
+}
+
+static int fpr_set(struct task_struct *target, const struct user_regset *regset,
+		   unsigned int pos, unsigned int count,
+		   const void *kbuf, const void __user *ubuf)
+{
+	int ret;
+
+	ret = __fpr_set(target, regset, pos, count, kbuf, ubuf, 0);
+	if (ret)
+		return ret;
+
+	sve_sync_from_fpsimd_zeropad(target);
 	fpsimd_flush_task_state(target);
+
 	return ret;
 }
 
@@ -693,6 +728,196 @@ static int system_call_set(struct task_struct *target,
 	return ret;
 }
 
+#ifdef CONFIG_ARM64_SVE
+
+static int sve_get(struct task_struct *target,
+		     const struct user_regset *regset,
+		     unsigned int pos, unsigned int count,
+		     void *kbuf, void __user *ubuf)
+{
+	int ret;
+	struct user_sve_header header;
+	unsigned int vq;
+	unsigned long start, end;
+
+	if (!(elf_hwcap & HWCAP_SVE))
+		return -EINVAL;
+
+	/* Header */
+	memset(&header, 0, sizeof(header));
+
+	header.vl = sve_get_vl();
+
+	BUG_ON(!sve_vl_valid(header.vl));
+	vq = sve_vq_from_vl(header.vl);
+
+	/* Until runtime or per-task vector length changing is supported: */
+	header.max_vl = header.vl;
+
+	header.flags = test_tsk_thread_flag(target, TIF_SVE) ?
+		SVE_PT_REGS_SVE : SVE_PT_REGS_FPSIMD;
+
+	header.size = SVE_PT_SIZE(vq, header.flags);
+	header.max_size = SVE_PT_SIZE(vq, SVE_PT_REGS_SVE);
+
+	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &header,
+				  0, sizeof(header));
+	if (ret)
+		return ret;
+
+	/* Registers: FPSIMD-only case */
+
+	BUILD_BUG_ON(SVE_PT_FPSIMD_OFFSET != sizeof(header));
+
+	if ((header.flags & SVE_PT_REGS_MASK) == SVE_PT_REGS_FPSIMD)
+		return __fpr_get(target, regset, pos, count, kbuf, ubuf,
+				 SVE_PT_FPSIMD_OFFSET);
+
+	/* Otherwise: full SVE case */
+
+	BUILD_BUG_ON(SVE_PT_SVE_OFFSET != sizeof(header));
+
+	start = SVE_PT_SVE_OFFSET;
+	end = SVE_PT_SVE_FFR_OFFSET(vq) + SVE_PT_SVE_FFR_SIZE(vq);
+
+	BUG_ON((char *)__sve_state(target) < (char *)target);
+	BUG_ON(end < start);
+	BUG_ON(arch_task_struct_size < end - start);
+	BUG_ON((char *)__sve_state(target) - (char *)target >
+	       arch_task_struct_size - (end - start));
+	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+				  __sve_state(target),
+				  start, end);
+	if (ret)
+		return ret;
+
+	start = end;
+	end = SVE_PT_SVE_FPSR_OFFSET(vq);
+
+	BUG_ON(end < start);
+	ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
+				       start, end);
+	if (ret)
+		return ret;
+
+	start = end;
+	end = SVE_PT_SVE_FPCR_OFFSET(vq) + SVE_PT_SVE_FPCR_SIZE;
+
+	BUG_ON((char *)(&target->thread.fpsimd_state.fpcr + 1) <
+	       (char *)&target->thread.fpsimd_state.fpsr);
+	BUG_ON(end < start);
+	BUG_ON((char *)(&target->thread.fpsimd_state.fpcr + 1) -
+	       (char *)&target->thread.fpsimd_state.fpsr !=
+		end - start);
+
+	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+				  &target->thread.fpsimd_state.fpsr,
+				  start, end);
+	if (ret)
+		return ret;
+
+	start = end;
+	end = (SVE_PT_SIZE(SVE_VQ_MAX, SVE_PT_REGS_SVE) + 15) / 16 * 16;
+	BUG_ON(end < start);
+
+	return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
+					start, end);
+}
+
+static int sve_set(struct task_struct *target,
+		     const struct user_regset *regset,
+		     unsigned int pos, unsigned int count,
+		     const void *kbuf, const void __user *ubuf)
+{
+	int ret;
+	struct user_sve_header header;
+	unsigned int vq;
+	unsigned long start, end;
+
+	if (!(elf_hwcap & HWCAP_SVE))
+		return -EINVAL;
+
+	/* Header */
+	if (count < sizeof(header))
+		return -EINVAL;
+	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &header,
+				 0, sizeof(header));
+	if (ret)
+		goto out;
+
+	if (header.vl != sve_get_vl())
+		return -EINVAL;
+
+	BUG_ON(!sve_vl_valid(header.vl));
+	vq = sve_vq_from_vl(header.vl);
+
+	if (header.flags & ~SVE_PT_REGS_MASK)
+		return -EINVAL;
+
+	/* Registers: FPSIMD-only case */
+
+	BUILD_BUG_ON(SVE_PT_FPSIMD_OFFSET != sizeof(header));
+
+	if ((header.flags & SVE_PT_REGS_MASK) == SVE_PT_REGS_FPSIMD) {
+		sve_sync_to_fpsimd(target);
+
+		ret = __fpr_set(target, regset, pos, count, kbuf, ubuf,
+				SVE_PT_FPSIMD_OFFSET);
+		clear_tsk_thread_flag(target, TIF_SVE);
+		goto out;
+	}
+
+	/* Otherwise: full SVE case */
+
+	fpsimd_sync_to_sve(target);
+	set_tsk_thread_flag(target, TIF_SVE);
+
+	BUILD_BUG_ON(SVE_PT_SVE_OFFSET != sizeof(header));
+
+	start = SVE_PT_SVE_OFFSET;
+	end = SVE_PT_SVE_FFR_OFFSET(vq) + SVE_PT_SVE_FFR_SIZE(vq);
+
+	BUG_ON((char *)__sve_state(target) < (char *)target);
+	BUG_ON(end < start);
+	BUG_ON(arch_task_struct_size < end - start);
+	BUG_ON((char *)__sve_state(target) - (char *)target >
+	       arch_task_struct_size - (end - start));
+	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+				 __sve_state(target),
+				 start, end);
+	if (ret)
+		goto out;
+
+	start = end;
+	end = SVE_PT_SVE_FPSR_OFFSET(vq);
+
+	BUG_ON(end < start);
+	ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
+					start, end);
+	if (ret)
+		goto out;
+
+	start = end;
+	end = SVE_PT_SVE_FPCR_OFFSET(vq) + SVE_PT_SVE_FPCR_SIZE;
+
+	BUG_ON((char *)(&target->thread.fpsimd_state.fpcr + 1) <
+		(char *)&target->thread.fpsimd_state.fpsr);
+	BUG_ON(end < start);
+	BUG_ON((char *)(&target->thread.fpsimd_state.fpcr + 1) -
+	       (char *)&target->thread.fpsimd_state.fpsr !=
+		end - start);
+
+	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+				 &target->thread.fpsimd_state.fpsr,
+				 start, end);
+
+out:
+	fpsimd_flush_task_state(target);
+	return ret;
+}
+
+#endif /* CONFIG_ARM64_SVE */
+
 enum aarch64_regset {
 	REGSET_GPR,
 	REGSET_FPR,
@@ -702,6 +927,9 @@ enum aarch64_regset {
 	REGSET_HW_WATCH,
 #endif
 	REGSET_SYSTEM_CALL,
+#ifdef CONFIG_ARM64_SVE
+	REGSET_SVE,
+#endif
 };
 
 static const struct user_regset aarch64_regsets[] = {
@@ -759,6 +987,16 @@ static const struct user_regset aarch64_regsets[] = {
 		.get = system_call_get,
 		.set = system_call_set,
 	},
+#ifdef CONFIG_ARM64_SVE
+	[REGSET_SVE] = { /* Scalable Vector Extension */
+		.core_note_type = NT_ARM_SVE,
+		.n = (SVE_PT_SIZE(SVE_VQ_MAX, SVE_PT_REGS_SVE) + 15) / 16,
+		.size = 16,
+		.align = 16,
+		.get = sve_get,
+		.set = sve_set,
+	},
+#endif
 };
 
 static const struct user_regset_view user_aarch64_view = {
diff --git a/include/uapi/linux/elf.h b/include/uapi/linux/elf.h
index b59ee07..23c6585 100644
--- a/include/uapi/linux/elf.h
+++ b/include/uapi/linux/elf.h
@@ -414,6 +414,7 @@ typedef struct elf64_shdr {
 #define NT_ARM_HW_BREAK	0x402		/* ARM hardware breakpoint registers */
 #define NT_ARM_HW_WATCH	0x403		/* ARM hardware watchpoint registers */
 #define NT_ARM_SYSTEM_CALL	0x404	/* ARM system call number */
+#define NT_ARM_SVE	0x405		/* ARM Scalable Vector Extension registers */
 #define NT_METAG_CBUF	0x500		/* Metag catch buffer registers */
 #define NT_METAG_RPIPE	0x501		/* Metag read pipeline state */
 #define NT_METAG_TLS	0x502		/* Metag TLS pointer */
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [RFC PATCH v2 28/41] arm64: KVM: Treat SVE use by guests as undefined instruction execution
  2017-03-22 14:50 ` Dave Martin
                   ` (27 preceding siblings ...)
  (?)
@ 2017-03-22 14:50 ` Dave Martin
  2017-03-22 17:06   ` Mark Rutland
  -1 siblings, 1 reply; 75+ messages in thread
From: Dave Martin @ 2017-03-22 14:50 UTC (permalink / raw)
  To: linux-arm-kernel

We don't currently support context-switching of Scalable Vector
Extension context between vcpus, and the SVE access exception is
thus left masked by default at EL2 when running a vcpu.

However, there's nothing to stop a guest trying to use SVE.  If it
does, we'll get an SVE access exception to EL2 which will cause KVM
to panic since this exception isn't yet recognised.

This patch adds knowledge to KVM about the SVE access exception,
translating it into an undefined instruction exception injected to
the vcpu.

This prevents a malicious guest from panicking the host by
attempted SVE use.

SVE-enabled guests will still not work properly for now, but they
won't take the host down.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
---
 arch/arm64/kvm/handle_exit.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c
index fa1b18e..e43b147 100644
--- a/arch/arm64/kvm/handle_exit.c
+++ b/arch/arm64/kvm/handle_exit.c
@@ -146,6 +146,13 @@ static int kvm_handle_unknown_ec(struct kvm_vcpu *vcpu, struct kvm_run *run)
 	return 1;
 }
 
+static int handle_sve(struct kvm_vcpu *vcpu, struct kvm_run *run)
+{
+	/* Until SVE is supported for guests: */
+	kvm_inject_undefined(vcpu);
+	return 1;
+}
+
 static exit_handle_fn arm_exit_handlers[] = {
 	[0 ... ESR_ELx_EC_MAX]	= kvm_handle_unknown_ec,
 	[ESR_ELx_EC_WFx]	= kvm_handle_wfx,
@@ -159,6 +166,7 @@ static exit_handle_fn arm_exit_handlers[] = {
 	[ESR_ELx_EC_HVC64]	= handle_hvc,
 	[ESR_ELx_EC_SMC64]	= handle_smc,
 	[ESR_ELx_EC_SYS64]	= kvm_handle_sys_reg,
+	[ESR_ELx_EC_SVE]	= handle_sve,
 	[ESR_ELx_EC_IABT_LOW]	= kvm_handle_guest_abort,
 	[ESR_ELx_EC_DABT_LOW]	= kvm_handle_guest_abort,
 	[ESR_ELx_EC_SOFTSTP_LOW]= kvm_handle_guest_debug,
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [RFC PATCH v2 29/41] prctl: Add skeleton for PR_SVE_{SET,GET}_VL controls
  2017-03-22 14:50 ` Dave Martin
@ 2017-03-22 14:50   ` Dave Martin
  -1 siblings, 0 replies; 75+ messages in thread
From: Dave Martin @ 2017-03-22 14:50 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Will Deacon, Catalin Marinas, Marc Zyngier, Ard Biesheuvel,
	Florian Weimer, Joseph Myers, Szabolcs Nagy, Andrew Morton,
	linux-kernel

This patch adds a do-nothing skeleton for the arm64 Scalable Vector
Extension control prctls.

These prctls are only avilable with

    CONFIG_ARM64=y
    CONFIG_ARM64_SVE=y

Otherwise they will compile out and return -EINVAL if attempted
from userspace.

The backend functions sve_{set,get}_task_vl() will be fleshed out
with actual functionality in subsequent patches.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
---
 arch/arm64/include/asm/fpsimd.h    | 16 ++++++++++++++++
 arch/arm64/include/asm/processor.h |  4 ++++
 arch/arm64/kernel/fpsimd.c         | 13 +++++++++++++
 include/uapi/linux/prctl.h         |  4 ++++
 kernel/sys.c                       | 12 ++++++++++++
 5 files changed, 49 insertions(+)

diff --git a/arch/arm64/include/asm/fpsimd.h b/arch/arm64/include/asm/fpsimd.h
index 71b94ee..7dba890 100644
--- a/arch/arm64/include/asm/fpsimd.h
+++ b/arch/arm64/include/asm/fpsimd.h
@@ -17,6 +17,7 @@
 #define __ASM_FP_H
 
 #include <asm/ptrace.h>
+#include <asm/errno.h>
 
 #ifndef __ASSEMBLY__
 
@@ -107,12 +108,27 @@ extern void fpsimd_sync_to_sve(struct task_struct *task);
 extern void sve_sync_to_fpsimd(struct task_struct *task);
 extern void sve_sync_from_fpsimd_zeropad(struct task_struct *task);
 
+extern int sve_set_task_vl(struct task_struct *task,
+			   unsigned long vector_length, unsigned long flags);
+extern int sve_get_task_vl(struct task_struct *task);
+
 #else /* ! CONFIG_ARM64_SVE */
 
 static void __maybe_unused sve_sync_to_fpsimd(struct task_struct *task) { }
 static void __maybe_unused sve_sync_from_fpsimd_zeropad(
 	struct task_struct *task) { }
 
+static int __maybe_unused sve_set_task_vl(struct task_struct *task,
+	unsigned long vector_length, unsigned long flags)
+{
+	return -EINVAL;
+}
+
+static int __maybe_unused sve_get_task_vl(struct task_struct *task)
+{
+	return -EINVAL;
+}
+
 #endif /* ! CONFIG_ARM64_SVE */
 
 #endif
diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h
index c97b8bd..865c279 100644
--- a/arch/arm64/include/asm/processor.h
+++ b/arch/arm64/include/asm/processor.h
@@ -189,4 +189,8 @@ static inline void spin_lock_prefetch(const void *ptr)
 int cpu_enable_pan(void *__unused);
 int cpu_enable_cache_maint_trap(void *__unused);
 
+#define SVE_SET_VL(task, vector_length, flags) \
+	sve_set_task_vl(task, vector_length, flags)
+#define SVE_GET_VL(task) sve_get_task_vl(task)
+
 #endif /* __ASM_PROCESSOR_H */
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index ee59325..4102d13 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -204,6 +204,19 @@ void do_sve_acc(unsigned int esr, struct pt_regs *regs)
 	task_fpsimd_load(current);
 }
 
+/* PR_SVE_SET_VL */
+int sve_set_task_vl(struct task_struct *task,
+		    unsigned long vector_length, unsigned long flags)
+{
+	return -EINVAL;
+}
+
+/* PR_SVE_GET_VL */
+int sve_get_task_vl(struct task_struct *task)
+{
+	return -EINVAL;
+}
+
 #else /* ! CONFIG_ARM64_SVE */
 
 /* Dummy declarations for usage protected with IS_ENABLED(CONFIG_ARM64_SVE): */
diff --git a/include/uapi/linux/prctl.h b/include/uapi/linux/prctl.h
index a8d0759..e32e2da 100644
--- a/include/uapi/linux/prctl.h
+++ b/include/uapi/linux/prctl.h
@@ -197,4 +197,8 @@ struct prctl_mm_map {
 # define PR_CAP_AMBIENT_LOWER		3
 # define PR_CAP_AMBIENT_CLEAR_ALL	4
 
+/* arm64 Scalable Vector Extension controls */
+#define PR_SVE_SET_VL			48	/* set task vector length */
+#define PR_SVE_GET_VL			49	/* get task vector length */
+
 #endif /* _LINUX_PRCTL_H */
diff --git a/kernel/sys.c b/kernel/sys.c
index 7ff6d1b..ea5d37e 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -110,6 +110,12 @@
 #ifndef SET_FP_MODE
 # define SET_FP_MODE(a,b)	(-EINVAL)
 #endif
+#ifndef SVE_SET_VL
+# define SVE_SET_VL(a,b,c)	(-EINVAL)
+#endif
+#ifndef SVE_GET_VL
+# define SVE_GET_VL(a)		(-EINVAL)
+#endif
 
 /*
  * this is where the system-wide overflow UID and GID are defined, for
@@ -2290,6 +2296,12 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
 	case PR_GET_FP_MODE:
 		error = GET_FP_MODE(me);
 		break;
+	case PR_SVE_SET_VL:
+		error = SVE_SET_VL(me, arg2, arg3);
+		break;
+	case PR_SVE_GET_VL:
+		error = SVE_GET_VL(me);
+		break;
 	default:
 		error = -EINVAL;
 		break;
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [RFC PATCH v2 29/41] prctl: Add skeleton for PR_SVE_{SET, GET}_VL controls
@ 2017-03-22 14:50   ` Dave Martin
  0 siblings, 0 replies; 75+ messages in thread
From: Dave Martin @ 2017-03-22 14:50 UTC (permalink / raw)
  To: linux-arm-kernel

This patch adds a do-nothing skeleton for the arm64 Scalable Vector
Extension control prctls.

These prctls are only avilable with

    CONFIG_ARM64=y
    CONFIG_ARM64_SVE=y

Otherwise they will compile out and return -EINVAL if attempted
from userspace.

The backend functions sve_{set,get}_task_vl() will be fleshed out
with actual functionality in subsequent patches.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
---
 arch/arm64/include/asm/fpsimd.h    | 16 ++++++++++++++++
 arch/arm64/include/asm/processor.h |  4 ++++
 arch/arm64/kernel/fpsimd.c         | 13 +++++++++++++
 include/uapi/linux/prctl.h         |  4 ++++
 kernel/sys.c                       | 12 ++++++++++++
 5 files changed, 49 insertions(+)

diff --git a/arch/arm64/include/asm/fpsimd.h b/arch/arm64/include/asm/fpsimd.h
index 71b94ee..7dba890 100644
--- a/arch/arm64/include/asm/fpsimd.h
+++ b/arch/arm64/include/asm/fpsimd.h
@@ -17,6 +17,7 @@
 #define __ASM_FP_H
 
 #include <asm/ptrace.h>
+#include <asm/errno.h>
 
 #ifndef __ASSEMBLY__
 
@@ -107,12 +108,27 @@ extern void fpsimd_sync_to_sve(struct task_struct *task);
 extern void sve_sync_to_fpsimd(struct task_struct *task);
 extern void sve_sync_from_fpsimd_zeropad(struct task_struct *task);
 
+extern int sve_set_task_vl(struct task_struct *task,
+			   unsigned long vector_length, unsigned long flags);
+extern int sve_get_task_vl(struct task_struct *task);
+
 #else /* ! CONFIG_ARM64_SVE */
 
 static void __maybe_unused sve_sync_to_fpsimd(struct task_struct *task) { }
 static void __maybe_unused sve_sync_from_fpsimd_zeropad(
 	struct task_struct *task) { }
 
+static int __maybe_unused sve_set_task_vl(struct task_struct *task,
+	unsigned long vector_length, unsigned long flags)
+{
+	return -EINVAL;
+}
+
+static int __maybe_unused sve_get_task_vl(struct task_struct *task)
+{
+	return -EINVAL;
+}
+
 #endif /* ! CONFIG_ARM64_SVE */
 
 #endif
diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h
index c97b8bd..865c279 100644
--- a/arch/arm64/include/asm/processor.h
+++ b/arch/arm64/include/asm/processor.h
@@ -189,4 +189,8 @@ static inline void spin_lock_prefetch(const void *ptr)
 int cpu_enable_pan(void *__unused);
 int cpu_enable_cache_maint_trap(void *__unused);
 
+#define SVE_SET_VL(task, vector_length, flags) \
+	sve_set_task_vl(task, vector_length, flags)
+#define SVE_GET_VL(task) sve_get_task_vl(task)
+
 #endif /* __ASM_PROCESSOR_H */
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index ee59325..4102d13 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -204,6 +204,19 @@ void do_sve_acc(unsigned int esr, struct pt_regs *regs)
 	task_fpsimd_load(current);
 }
 
+/* PR_SVE_SET_VL */
+int sve_set_task_vl(struct task_struct *task,
+		    unsigned long vector_length, unsigned long flags)
+{
+	return -EINVAL;
+}
+
+/* PR_SVE_GET_VL */
+int sve_get_task_vl(struct task_struct *task)
+{
+	return -EINVAL;
+}
+
 #else /* ! CONFIG_ARM64_SVE */
 
 /* Dummy declarations for usage protected with IS_ENABLED(CONFIG_ARM64_SVE): */
diff --git a/include/uapi/linux/prctl.h b/include/uapi/linux/prctl.h
index a8d0759..e32e2da 100644
--- a/include/uapi/linux/prctl.h
+++ b/include/uapi/linux/prctl.h
@@ -197,4 +197,8 @@ struct prctl_mm_map {
 # define PR_CAP_AMBIENT_LOWER		3
 # define PR_CAP_AMBIENT_CLEAR_ALL	4
 
+/* arm64 Scalable Vector Extension controls */
+#define PR_SVE_SET_VL			48	/* set task vector length */
+#define PR_SVE_GET_VL			49	/* get task vector length */
+
 #endif /* _LINUX_PRCTL_H */
diff --git a/kernel/sys.c b/kernel/sys.c
index 7ff6d1b..ea5d37e 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -110,6 +110,12 @@
 #ifndef SET_FP_MODE
 # define SET_FP_MODE(a,b)	(-EINVAL)
 #endif
+#ifndef SVE_SET_VL
+# define SVE_SET_VL(a,b,c)	(-EINVAL)
+#endif
+#ifndef SVE_GET_VL
+# define SVE_GET_VL(a)		(-EINVAL)
+#endif
 
 /*
  * this is where the system-wide overflow UID and GID are defined, for
@@ -2290,6 +2296,12 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
 	case PR_GET_FP_MODE:
 		error = GET_FP_MODE(me);
 		break;
+	case PR_SVE_SET_VL:
+		error = SVE_SET_VL(me, arg2, arg3);
+		break;
+	case PR_SVE_GET_VL:
+		error = SVE_GET_VL(me);
+		break;
 	default:
 		error = -EINVAL;
 		break;
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [RFC PATCH v2 30/41] arm64/sve: Track vector length for each task
  2017-03-22 14:50 ` Dave Martin
                   ` (29 preceding siblings ...)
  (?)
@ 2017-03-22 14:51 ` Dave Martin
  -1 siblings, 0 replies; 75+ messages in thread
From: Dave Martin @ 2017-03-22 14:51 UTC (permalink / raw)
  To: linux-arm-kernel

In preparation for allowing each task to have its own independent
vector length, this patch adds a sve_vl field to thread_struct to
track it, and interrogates this instead of interrogating the
hardware when knowledge of the task's vector length is needed.

The hardware supported vector length is not known straight out of
boot, so init_task and other kernel tasks forked early may lack
this knowledge.

We only need this knowledge when in the context of a user task that
has SVE state (or that has just trapped while attempting to have
SVE state).  So, we can hook into exec() to set task vector length
if it wasn't known at boot/fork time, before the task enters
userspace.

There is no way to change sve_vl for a task yet, so all tasks still
execute with the hardware vector length.  Subsequent patches will
enable changing the vector length for tasks.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
---
 arch/arm64/include/asm/processor.h |  1 +
 arch/arm64/kernel/fpsimd.c         | 39 +++++++++++++++++++++++++++++---------
 arch/arm64/kernel/ptrace.c         |  4 ++--
 arch/arm64/kernel/signal.c         | 15 +++++++++++----
 4 files changed, 44 insertions(+), 15 deletions(-)

diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h
index 865c279..896e972 100644
--- a/arch/arm64/include/asm/processor.h
+++ b/arch/arm64/include/asm/processor.h
@@ -83,6 +83,7 @@ struct thread_struct {
 	unsigned long		tp2_value;
 #endif
 	struct fpsimd_state	fpsimd_state;
+	u16			sve_vl;		/* SVE vector length */
 	unsigned long		fault_address;	/* fault info */
 	unsigned long		fault_code;	/* ESR_EL1 value */
 	struct debug_info	debug;		/* debugging */
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index 4102d13..d3f89ac6 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -97,6 +97,9 @@ static DEFINE_PER_CPU(struct fpsimd_state *, fpsimd_last_state);
 
 #ifdef CONFIG_ARM64_SVE
 
+/* Maximum supported vector length across all CPUs (initially poisoned) */
+int sve_max_vl = -1;
+
 void *__sve_state(struct task_struct *task)
 {
 	return (char *)task + ALIGN(sizeof(*task), 16);
@@ -104,7 +107,7 @@ void *__sve_state(struct task_struct *task)
 
 static void *sve_pffr(struct task_struct *task)
 {
-	unsigned int vl = sve_get_vl();
+	unsigned int vl = task->thread.sve_vl;
 
 	BUG_ON(!sve_vl_valid(vl));
 	return (char *)__sve_state(task) +
@@ -123,7 +126,7 @@ static void __fpsimd_to_sve(struct task_struct *task, unsigned int vq)
 
 static void fpsimd_to_sve(struct task_struct *task)
 {
-	unsigned int vl = sve_get_vl();
+	unsigned int vl = task->thread.sve_vl;
 
 	if (!(elf_hwcap & HWCAP_SVE))
 		return;
@@ -144,7 +147,7 @@ static void __sve_to_fpsimd(struct task_struct *task, unsigned int vq)
 
 static void sve_to_fpsimd(struct task_struct *task)
 {
-	unsigned int vl = sve_get_vl();
+	unsigned int vl = task->thread.sve_vl;
 
 	if (!(elf_hwcap & HWCAP_SVE))
 		return;
@@ -187,7 +190,8 @@ void sve_sync_from_fpsimd_zeropad(struct task_struct *task)
 	if (!test_tsk_thread_flag(task, TIF_SVE))
 		return;
 
-	vl = sve_get_vl();
+	vl = task->thread.sve_vl;
+	BUG_ON(!sve_vl_valid(vl));
 	__sve_sync_from_fpsimd_zeropad(task, sve_vq_from_vl(vl));
 }
 
@@ -220,6 +224,7 @@ int sve_get_task_vl(struct task_struct *task)
 #else /* ! CONFIG_ARM64_SVE */
 
 /* Dummy declarations for usage protected with IS_ENABLED(CONFIG_ARM64_SVE): */
+extern int sve_max_vl;
 extern void *sve_pffr(struct task_struct *task);
 extern void fpsimd_to_sve(struct task_struct *task);
 
@@ -370,6 +375,18 @@ void fpsimd_flush_thread(void)
 		memset(__sve_state(current), 0,
 		       arch_task_struct_size -
 		       ((char *)__sve_state(current) - (char *)current));
+
+		/*
+		 * User tasks must have a valid vector length set, but tasks
+		 * forked early (e.g., init) may not have one yet.
+		 * By now, we will know what the hardware supports, so set the
+		 * task vector length if it doesn't have one:
+		 */
+		if (!current->thread.sve_vl) {
+			BUG_ON(!sve_vl_valid(sve_max_vl));
+
+			current->thread.sve_vl = sve_max_vl;
+		}
 	}
 
 	set_thread_flag(TIF_FOREIGN_FPSTATE);
@@ -571,19 +588,23 @@ static inline void fpsimd_hotplug_init(void) { }
 
 void __init fpsimd_init_task_struct_size(void)
 {
+	unsigned int vq;
+
 	arch_task_struct_size = sizeof(struct task_struct);
 
 	if (IS_ENABLED(CONFIG_ARM64_SVE) &&
 	    ((read_cpuid(ID_AA64PFR0_EL1) >> ID_AA64PFR0_SVE_SHIFT)
 	     & 0xf) == 1) {
-		unsigned int vl = sve_get_vl();
+		/* FIXME: This should be the minimum across all CPUs */
+		sve_max_vl = sve_get_vl();
 
-		BUG_ON(!sve_vl_valid(vl));
-		arch_task_struct_size = ALIGN(sizeof(struct task_struct), 16) +
-			ALIGN(SVE_SIG_REGS_SIZE(sve_vq_from_vl(vl)), 16);
+		BUG_ON(!sve_vl_valid(sve_max_vl));
+		vq = sve_vq_from_vl(sve_max_vl);
 
+		arch_task_struct_size = ALIGN(sizeof(struct task_struct), 16) +
+			ALIGN(SVE_SIG_REGS_SIZE(vq), 16);
 		pr_info("SVE: enabled with maximum %u bits per vector\n",
-			vl * 8);
+			sve_max_vl * 8);
 	}
 }
 
diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
index 3e97e16..72b922a 100644
--- a/arch/arm64/kernel/ptrace.c
+++ b/arch/arm64/kernel/ptrace.c
@@ -746,7 +746,7 @@ static int sve_get(struct task_struct *target,
 	/* Header */
 	memset(&header, 0, sizeof(header));
 
-	header.vl = sve_get_vl();
+	header.vl = target->thread.sve_vl;
 
 	BUG_ON(!sve_vl_valid(header.vl));
 	vq = sve_vq_from_vl(header.vl);
@@ -845,7 +845,7 @@ static int sve_set(struct task_struct *target,
 	if (ret)
 		goto out;
 
-	if (header.vl != sve_get_vl())
+	if (header.vl != target->thread.sve_vl)
 		return -EINVAL;
 
 	BUG_ON(!sve_vl_valid(header.vl));
diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c
index 20bc312..45f0c2c 100644
--- a/arch/arm64/kernel/signal.c
+++ b/arch/arm64/kernel/signal.c
@@ -222,8 +222,11 @@ static int preserve_sve_context(struct sve_context __user *ctx)
 {
 	int err = 0;
 	u16 reserved[ARRAY_SIZE(ctx->__reserved)];
-	unsigned int vl = sve_get_vl();
-	unsigned int vq = sve_vq_from_vl(vl);
+	unsigned int vl = current->thread.sve_vl;
+	unsigned int vq;
+
+	BUG_ON(!sve_vl_valid(vl));
+	vq = sve_vq_from_vl(vl);
 
 	memset(reserved, 0, sizeof(reserved));
 
@@ -253,7 +256,7 @@ static int __restore_sve_fpsimd_context(struct user_ctxs *user,
 		__sve_state(current);
 	struct fpsimd_state fpsimd;
 
-	if (vl != sve_get_vl())
+	if (vl != current->thread.sve_vl)
 		return -EINVAL;
 
 	fpsimd_flush_task_state(current);
@@ -545,7 +548,11 @@ static int setup_sigframe_layout(struct rt_sigframe_user_layout *user)
 	}
 
 	if (IS_ENABLED(CONFIG_ARM64_SVE) && test_thread_flag(TIF_SVE)) {
-		unsigned int vq = sve_vq_from_vl(sve_get_vl());
+		unsigned int vl = current->thread.sve_vl;
+		unsigned int vq;
+
+		BUG_ON(!sve_vl_valid(vl));
+		vq = sve_vq_from_vl(vl);
 
 		BUG_ON(!(elf_hwcap & HWCAP_SVE));
 
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [RFC PATCH v2 31/41] arm64/sve: Set CPU vector length to match current task
  2017-03-22 14:50 ` Dave Martin
                   ` (30 preceding siblings ...)
  (?)
@ 2017-03-22 14:51 ` Dave Martin
  -1 siblings, 0 replies; 75+ messages in thread
From: Dave Martin @ 2017-03-22 14:51 UTC (permalink / raw)
  To: linux-arm-kernel

This patch adds the necessary code to configure the CPU for the
task's vector length, whenever SVE state is loaded for a task.

No special action is needed on sched-out: only user tasks with SVE
state care what the CPU's VL is set to.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
---
 arch/arm64/include/asm/fpsimd.h       |  3 ++-
 arch/arm64/include/asm/fpsimdmacros.h |  7 ++++++-
 arch/arm64/kernel/entry-fpsimd.S      |  2 +-
 arch/arm64/kernel/fpsimd.c            | 10 +++++++---
 4 files changed, 16 insertions(+), 6 deletions(-)

diff --git a/arch/arm64/include/asm/fpsimd.h b/arch/arm64/include/asm/fpsimd.h
index 7dba890..557e755 100644
--- a/arch/arm64/include/asm/fpsimd.h
+++ b/arch/arm64/include/asm/fpsimd.h
@@ -97,7 +97,8 @@ extern void fpsimd_save_partial_state(struct fpsimd_partial_state *state,
 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 void sve_load_state(void const *state, u32 const *pfpsr,
+			   unsigned long vq_minus_1);
 extern unsigned int sve_get_vl(void);
 extern void __init fpsimd_init_task_struct_size(void);
 extern void *__sve_state(struct task_struct *task);
diff --git a/arch/arm64/include/asm/fpsimdmacros.h b/arch/arm64/include/asm/fpsimdmacros.h
index e2bb032..4586468 100644
--- a/arch/arm64/include/asm/fpsimdmacros.h
+++ b/arch/arm64/include/asm/fpsimdmacros.h
@@ -254,7 +254,12 @@
 	.purgem savep
 .endm
 
-.macro sve_load nb, xpfpsr, ntmp
+.macro sve_load nb, xpfpsr, xvqminus1 ntmp
+	mrs_s	x\ntmp, SYS_ZCR_EL1
+	bic	x\ntmp, x\ntmp, ZCR_EL1_LEN_MASK
+	orr	x\ntmp, x\ntmp, \xvqminus1
+	msr_s	SYS_ZCR_EL1, x\ntmp	// self-synchronising
+
 	.macro loadz n
 		_zldrv	\n, \nb, (\n) - 34
 	.endm
diff --git a/arch/arm64/kernel/entry-fpsimd.S b/arch/arm64/kernel/entry-fpsimd.S
index 5dcec55..0a3fdcb 100644
--- a/arch/arm64/kernel/entry-fpsimd.S
+++ b/arch/arm64/kernel/entry-fpsimd.S
@@ -73,7 +73,7 @@ ENTRY(sve_save_state)
 ENDPROC(sve_save_state)
 
 ENTRY(sve_load_state)
-	sve_load 0, x1, 2
+	sve_load 0, x1, x2, 3
 	ret
 ENDPROC(sve_load_state)
 
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index d3f89ac6..09d3d23 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -272,10 +272,14 @@ void do_fpsimd_exc(unsigned int esr, struct pt_regs *regs)
 static void task_fpsimd_load(struct task_struct *task)
 {
 	if (IS_ENABLED(CONFIG_ARM64_SVE) &&
-	    test_tsk_thread_flag(task, TIF_SVE))
+	    test_tsk_thread_flag(task, TIF_SVE)) {
+		unsigned int vl = task->thread.sve_vl;
+
+		BUG_ON(!sve_vl_valid(vl));
 		sve_load_state(sve_pffr(task),
-			       &task->thread.fpsimd_state.fpsr);
-	else
+			       &task->thread.fpsimd_state.fpsr,
+			       sve_vq_from_vl(vl) - 1);
+	} else
 		fpsimd_load_state(&task->thread.fpsimd_state);
 
 	/*
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [RFC PATCH v2 32/41] arm64/sve: Factor out clearing of tasks' SVE regs
  2017-03-22 14:50 ` Dave Martin
                   ` (31 preceding siblings ...)
  (?)
@ 2017-03-22 14:51 ` Dave Martin
  -1 siblings, 0 replies; 75+ messages in thread
From: Dave Martin @ 2017-03-22 14:51 UTC (permalink / raw)
  To: linux-arm-kernel

The patch factors out the code that clears a task's SVE regs on
exec(), so that we can reuse it in subsequent patches.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
---
 arch/arm64/kernel/fpsimd.c | 22 +++++++++++++++-------
 1 file changed, 15 insertions(+), 7 deletions(-)

diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index 09d3d23..daceeae 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -105,6 +105,19 @@ void *__sve_state(struct task_struct *task)
 	return (char *)task + ALIGN(sizeof(*task), 16);
 }
 
+static void clear_sve_regs(struct task_struct *task)
+{
+	BUG_ON(task == current && preemptible());
+
+	BUG_ON((char *)__sve_state(task) < (char *)task);
+	BUG_ON(arch_task_struct_size <
+	       ((char *)__sve_state(task) - (char *)task));
+
+	memset(__sve_state(task), 0,
+	       arch_task_struct_size -
+			((char *)__sve_state(task) - (char *)task));
+}
+
 static void *sve_pffr(struct task_struct *task)
 {
 	unsigned int vl = task->thread.sve_vl;
@@ -225,6 +238,7 @@ int sve_get_task_vl(struct task_struct *task)
 
 /* Dummy declarations for usage protected with IS_ENABLED(CONFIG_ARM64_SVE): */
 extern int sve_max_vl;
+extern void clear_sve_regs(struct task_struct *task);
 extern void *sve_pffr(struct task_struct *task);
 extern void fpsimd_to_sve(struct task_struct *task);
 
@@ -372,13 +386,7 @@ void fpsimd_flush_thread(void)
 	memset(&current->thread.fpsimd_state, 0, sizeof(struct fpsimd_state));
 
 	if (IS_ENABLED(CONFIG_ARM64_SVE) && (elf_hwcap & HWCAP_SVE)) {
-		BUG_ON((char *)__sve_state(current) < (char *)current);
-		BUG_ON(arch_task_struct_size <
-		       ((char *)__sve_state(current) - (char *)current));
-
-		memset(__sve_state(current), 0,
-		       arch_task_struct_size -
-		       ((char *)__sve_state(current) - (char *)current));
+		clear_sve_regs(current);
 
 		/*
 		 * User tasks must have a valid vector length set, but tasks
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [RFC PATCH v2 33/41] arm64/sve: Wire up vector length control prctl() calls
  2017-03-22 14:50 ` Dave Martin
@ 2017-03-22 14:51   ` Dave Martin
  -1 siblings, 0 replies; 75+ messages in thread
From: Dave Martin @ 2017-03-22 14:51 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Will Deacon, Catalin Marinas, Marc Zyngier, Ard Biesheuvel,
	Florian Weimer, Joseph Myers, Szabolcs Nagy, Andrew Morton,
	linux-kernel

This patch provides implementation for the PR_SVE_SET_VL and
PR_SVE_GET_VL prctls, which allow a task to set and query its
vector length and associated control flags (although no flags are
defined in this patch).

Currently any thread can set its VL, allowing a mix of VLs within
a single process -- this behaviour will be refined in susequent
patches.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
---
 arch/arm64/include/asm/fpsimd.h |  3 ++
 arch/arm64/kernel/fpsimd.c      | 65 +++++++++++++++++++++++++++++++++++++++--
 2 files changed, 66 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/include/asm/fpsimd.h b/arch/arm64/include/asm/fpsimd.h
index 557e755..764da0f 100644
--- a/arch/arm64/include/asm/fpsimd.h
+++ b/arch/arm64/include/asm/fpsimd.h
@@ -109,6 +109,9 @@ extern void fpsimd_sync_to_sve(struct task_struct *task);
 extern void sve_sync_to_fpsimd(struct task_struct *task);
 extern void sve_sync_from_fpsimd_zeropad(struct task_struct *task);
 
+extern int sve_set_vector_length(struct task_struct *task,
+				 unsigned long vl, unsigned long flags);
+
 extern int sve_set_task_vl(struct task_struct *task,
 			   unsigned long vector_length, unsigned long flags);
 extern int sve_get_task_vl(struct task_struct *task);
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index daceeae..c9934bb 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -221,17 +221,78 @@ void do_sve_acc(unsigned int esr, struct pt_regs *regs)
 	task_fpsimd_load(current);
 }
 
+int sve_set_vector_length(struct task_struct *task,
+			  unsigned long vl, unsigned long flags)
+{
+	BUG_ON(task == current && preemptible());
+
+	if (flags)
+		return -EINVAL; /* No flags defined yet */
+
+	if (!sve_vl_valid(vl))
+		return -EINVAL;
+
+	if (vl > sve_max_vl) {
+		BUG_ON(!sve_vl_valid(sve_max_vl));
+		vl = sve_max_vl;
+	}
+
+	/*
+	 * To ensure the FPSIMD bits of the SVE vector registers are preserved,
+	 * write any live register state back to task_struct, and convert to a
+	 * non-SVE thread.
+	 */
+	if (vl != task->thread.sve_vl) {
+		if (task == current &&
+		    !test_and_set_thread_flag(TIF_FOREIGN_FPSTATE))
+			task_fpsimd_save(current);
+
+		if (test_and_clear_tsk_thread_flag(task, TIF_SVE))
+			sve_to_fpsimd(task);
+
+		/*
+		 * To avoid surprises, also zero out the SVE regs storage.
+		 * This means that the P-regs, FFR and high bits of Z-regs
+		 * will read as zero on next access:
+		 */
+		clear_sve_regs(task);
+	}
+
+	task->thread.sve_vl = vl;
+
+	fpsimd_flush_task_state(task);
+
+	return 0;
+}
+
 /* PR_SVE_SET_VL */
 int sve_set_task_vl(struct task_struct *task,
 		    unsigned long vector_length, unsigned long flags)
 {
-	return -EINVAL;
+	int ret;
+
+	if (!(elf_hwcap & HWCAP_SVE))
+		return -EINVAL;
+
+	BUG_ON(task != current);
+
+	preempt_disable();
+	ret = sve_set_vector_length(current, vector_length, flags);
+	preempt_enable();
+
+	if (ret)
+		return ret;
+
+	return task->thread.sve_vl;
 }
 
 /* PR_SVE_GET_VL */
 int sve_get_task_vl(struct task_struct *task)
 {
-	return -EINVAL;
+	if (!(elf_hwcap & HWCAP_SVE))
+		return -EINVAL;
+
+	return task->thread.sve_vl;
 }
 
 #else /* ! CONFIG_ARM64_SVE */
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [RFC PATCH v2 33/41] arm64/sve: Wire up vector length control prctl() calls
@ 2017-03-22 14:51   ` Dave Martin
  0 siblings, 0 replies; 75+ messages in thread
From: Dave Martin @ 2017-03-22 14:51 UTC (permalink / raw)
  To: linux-arm-kernel

This patch provides implementation for the PR_SVE_SET_VL and
PR_SVE_GET_VL prctls, which allow a task to set and query its
vector length and associated control flags (although no flags are
defined in this patch).

Currently any thread can set its VL, allowing a mix of VLs within
a single process -- this behaviour will be refined in susequent
patches.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
---
 arch/arm64/include/asm/fpsimd.h |  3 ++
 arch/arm64/kernel/fpsimd.c      | 65 +++++++++++++++++++++++++++++++++++++++--
 2 files changed, 66 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/include/asm/fpsimd.h b/arch/arm64/include/asm/fpsimd.h
index 557e755..764da0f 100644
--- a/arch/arm64/include/asm/fpsimd.h
+++ b/arch/arm64/include/asm/fpsimd.h
@@ -109,6 +109,9 @@ extern void fpsimd_sync_to_sve(struct task_struct *task);
 extern void sve_sync_to_fpsimd(struct task_struct *task);
 extern void sve_sync_from_fpsimd_zeropad(struct task_struct *task);
 
+extern int sve_set_vector_length(struct task_struct *task,
+				 unsigned long vl, unsigned long flags);
+
 extern int sve_set_task_vl(struct task_struct *task,
 			   unsigned long vector_length, unsigned long flags);
 extern int sve_get_task_vl(struct task_struct *task);
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index daceeae..c9934bb 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -221,17 +221,78 @@ void do_sve_acc(unsigned int esr, struct pt_regs *regs)
 	task_fpsimd_load(current);
 }
 
+int sve_set_vector_length(struct task_struct *task,
+			  unsigned long vl, unsigned long flags)
+{
+	BUG_ON(task == current && preemptible());
+
+	if (flags)
+		return -EINVAL; /* No flags defined yet */
+
+	if (!sve_vl_valid(vl))
+		return -EINVAL;
+
+	if (vl > sve_max_vl) {
+		BUG_ON(!sve_vl_valid(sve_max_vl));
+		vl = sve_max_vl;
+	}
+
+	/*
+	 * To ensure the FPSIMD bits of the SVE vector registers are preserved,
+	 * write any live register state back to task_struct, and convert to a
+	 * non-SVE thread.
+	 */
+	if (vl != task->thread.sve_vl) {
+		if (task == current &&
+		    !test_and_set_thread_flag(TIF_FOREIGN_FPSTATE))
+			task_fpsimd_save(current);
+
+		if (test_and_clear_tsk_thread_flag(task, TIF_SVE))
+			sve_to_fpsimd(task);
+
+		/*
+		 * To avoid surprises, also zero out the SVE regs storage.
+		 * This means that the P-regs, FFR and high bits of Z-regs
+		 * will read as zero on next access:
+		 */
+		clear_sve_regs(task);
+	}
+
+	task->thread.sve_vl = vl;
+
+	fpsimd_flush_task_state(task);
+
+	return 0;
+}
+
 /* PR_SVE_SET_VL */
 int sve_set_task_vl(struct task_struct *task,
 		    unsigned long vector_length, unsigned long flags)
 {
-	return -EINVAL;
+	int ret;
+
+	if (!(elf_hwcap & HWCAP_SVE))
+		return -EINVAL;
+
+	BUG_ON(task != current);
+
+	preempt_disable();
+	ret = sve_set_vector_length(current, vector_length, flags);
+	preempt_enable();
+
+	if (ret)
+		return ret;
+
+	return task->thread.sve_vl;
 }
 
 /* PR_SVE_GET_VL */
 int sve_get_task_vl(struct task_struct *task)
 {
-	return -EINVAL;
+	if (!(elf_hwcap & HWCAP_SVE))
+		return -EINVAL;
+
+	return task->thread.sve_vl;
 }
 
 #else /* ! CONFIG_ARM64_SVE */
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [RFC PATCH v2 34/41] arm64/sve: Disallow VL setting for individual threads by default
  2017-03-22 14:50 ` Dave Martin
                   ` (33 preceding siblings ...)
  (?)
@ 2017-03-22 14:51 ` Dave Martin
  -1 siblings, 0 replies; 75+ messages in thread
From: Dave Martin @ 2017-03-22 14:51 UTC (permalink / raw)
  To: linux-arm-kernel

General-purpose code in userspace is not expected to work correctly
if multiple threads are allowed to run concurrently with different
vector lengths in a single process.

This patch adds an explicit flag PR_SVE_SET_VL_THREAD to request
this behaviour.  Without the flag, vector length setting is
permitted only for a single-threaded process (which matches the
expected usage model of setting the vector length at process
startup).

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
---
 arch/arm64/kernel/fpsimd.c | 12 +++++++++++-
 include/uapi/linux/prctl.h |  1 +
 2 files changed, 12 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index c9934bb..ab00e9f 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -21,6 +21,7 @@
 #include <linux/cpu_pm.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/prctl.h>
 #include <linux/sched/signal.h>
 #include <linux/signal.h>
 #include <linux/hardirq.h>
@@ -226,8 +227,17 @@ int sve_set_vector_length(struct task_struct *task,
 {
 	BUG_ON(task == current && preemptible());
 
+	/*
+	 * To avoid accidents, forbid setting for individual threads of a
+	 * multithreaded process.  User code that knows what it's doing can
+	 * pass PR_SVE_SET_VL_THREAD to override this restriction:
+	 */
+	if (!(flags & PR_SVE_SET_VL_THREAD) && get_nr_threads(task) != 1)
+		return -EINVAL;
+
+	flags &= ~(unsigned long)PR_SVE_SET_VL_THREAD;
 	if (flags)
-		return -EINVAL; /* No flags defined yet */
+		return -EINVAL; /* No other flags defined yet */
 
 	if (!sve_vl_valid(vl))
 		return -EINVAL;
diff --git a/include/uapi/linux/prctl.h b/include/uapi/linux/prctl.h
index e32e2da..c55530b 100644
--- a/include/uapi/linux/prctl.h
+++ b/include/uapi/linux/prctl.h
@@ -199,6 +199,7 @@ struct prctl_mm_map {
 
 /* arm64 Scalable Vector Extension controls */
 #define PR_SVE_SET_VL			48	/* set task vector length */
+# define PR_SVE_SET_VL_THREAD		(1 << 1) /* set just this thread */
 #define PR_SVE_GET_VL			49	/* get task vector length */
 
 #endif /* _LINUX_PRCTL_H */
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [RFC PATCH v2 35/41] arm64/sve: Add vector length inheritance control
  2017-03-22 14:50 ` Dave Martin
                   ` (34 preceding siblings ...)
  (?)
@ 2017-03-22 14:51 ` Dave Martin
  -1 siblings, 0 replies; 75+ messages in thread
From: Dave Martin @ 2017-03-22 14:51 UTC (permalink / raw)
  To: linux-arm-kernel

Currently the vector length is inherited across both fork() and
exec().

Inheritance across fork() is desirable both for creating a copy of
a process (traditional fork) or creating a thread (where we want
all threads to share the same VL by default).

Inheritance across exec() is less desirable, because of the ABI
impact of large vector lengths on the size of the signal frame --
when running a new binary, there is no guarantee that the new
binary is compatible with these ABI changes.

This flag makes the vector length non-inherited by default.
Instead, the vector length is reset to a system default value,
unless the THREAD_VL_INHERIT flag has been set for the thread.

In order to permit clean launching of a new binary with a different
vector length, this patch also adds a prctl flag
PR_SVE_SET_VL_ONEXEC which causes the effect of the change to be
deferred until the calling thread's next exec.  This behaviour is
implemented by storing a shadow vector length in
thread_struct.sve_vl_onexec, which gets activated at exec.

Subsequent vl changes by the thread (if any) before the exec will
override such a pending change.

Without PR_SVE_SET_VL_ONEXEC, the effect of the change will be
immediate.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
---
 arch/arm64/include/asm/processor.h |  8 +++++
 arch/arm64/kernel/fpsimd.c         | 61 ++++++++++++++++++++++++++++++--------
 include/uapi/linux/prctl.h         |  6 ++++
 3 files changed, 63 insertions(+), 12 deletions(-)

diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h
index 896e972..424fa5d 100644
--- a/arch/arm64/include/asm/processor.h
+++ b/arch/arm64/include/asm/processor.h
@@ -27,6 +27,7 @@
 
 #ifdef __KERNEL__
 
+#include <linux/prctl.h>
 #include <linux/string.h>
 
 #include <asm/alternative.h>
@@ -84,11 +85,18 @@ struct thread_struct {
 #endif
 	struct fpsimd_state	fpsimd_state;
 	u16			sve_vl;		/* SVE vector length */
+	u16			sve_vl_onexec;	/* SVE vl after next exec */
+	u16			sve_flags;	/* SVE related flags */
 	unsigned long		fault_address;	/* fault info */
 	unsigned long		fault_code;	/* ESR_EL1 value */
 	struct debug_info	debug;		/* debugging */
 };
 
+/* Flags for sve_flags (intentionally defined to match the prctl flags) */
+
+/* Inherit sve_vl and sve_flags across execve(): */
+#define THREAD_VL_INHERIT	PR_SVE_SET_VL_INHERIT
+
 #ifdef CONFIG_COMPAT
 #define task_user_tls(t)						\
 ({									\
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index ab00e9f..982b1d7 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -234,10 +234,11 @@ int sve_set_vector_length(struct task_struct *task,
 	 */
 	if (!(flags & PR_SVE_SET_VL_THREAD) && get_nr_threads(task) != 1)
 		return -EINVAL;
-
 	flags &= ~(unsigned long)PR_SVE_SET_VL_THREAD;
-	if (flags)
-		return -EINVAL; /* No other flags defined yet */
+
+	if (flags & ~(unsigned long)(PR_SVE_SET_VL_INHERIT |
+				     PR_SVE_SET_VL_ONEXEC))
+		return -EINVAL;
 
 	if (!sve_vl_valid(vl))
 		return -EINVAL;
@@ -247,6 +248,17 @@ int sve_set_vector_length(struct task_struct *task,
 		vl = sve_max_vl;
 	}
 
+	if (flags & (PR_SVE_SET_VL_ONEXEC |
+		     PR_SVE_SET_VL_INHERIT))
+		task->thread.sve_vl_onexec = vl;
+	else
+		/* Reset VL to system default on next exec: */
+		task->thread.sve_vl_onexec = 0;
+
+	/* Only actually set the VL if not deferred: */
+	if (flags & PR_SVE_SET_VL_ONEXEC)
+		goto out;
+
 	/*
 	 * To ensure the FPSIMD bits of the SVE vector registers are preserved,
 	 * write any live register state back to task_struct, and convert to a
@@ -272,9 +284,26 @@ int sve_set_vector_length(struct task_struct *task,
 
 	fpsimd_flush_task_state(task);
 
+out:
+	/* The THREAD_VL_* flag encodings match the relevant PR_* flags: */
+	task->thread.sve_flags = flags & PR_SVE_SET_VL_INHERIT;
+
 	return 0;
 }
 
+/*
+ * Encode the current vector length and flags for return.
+ * This is only required for prctl(): ptrace has separate fields
+ */
+static int sve_prctl_status(struct task_struct const *task)
+{
+	int ret = task->thread.sve_vl;
+
+	ret |= task->thread.sve_flags << 16;
+
+	return ret;
+}
+
 /* PR_SVE_SET_VL */
 int sve_set_task_vl(struct task_struct *task,
 		    unsigned long vector_length, unsigned long flags)
@@ -293,7 +322,7 @@ int sve_set_task_vl(struct task_struct *task,
 	if (ret)
 		return ret;
 
-	return task->thread.sve_vl;
+	return sve_prctl_status(task);
 }
 
 /* PR_SVE_GET_VL */
@@ -302,7 +331,7 @@ int sve_get_task_vl(struct task_struct *task)
 	if (!(elf_hwcap & HWCAP_SVE))
 		return -EINVAL;
 
-	return task->thread.sve_vl;
+	return sve_prctl_status(task);
 }
 
 #else /* ! CONFIG_ARM64_SVE */
@@ -459,17 +488,25 @@ void fpsimd_flush_thread(void)
 	if (IS_ENABLED(CONFIG_ARM64_SVE) && (elf_hwcap & HWCAP_SVE)) {
 		clear_sve_regs(current);
 
+		current->thread.sve_vl = current->thread.sve_vl_onexec ?
+			current->thread.sve_vl_onexec : sve_max_vl;
+
 		/*
 		 * User tasks must have a valid vector length set, but tasks
-		 * forked early (e.g., init) may not have one yet.
-		 * By now, we will know what the hardware supports, so set the
-		 * task vector length if it doesn't have one:
+		 * forked early (e.g., init) may not initially have one.
+		 * By now, we will know what the hardware supports, so
+		 * sve_max_vl should be valid, and thus the above
+		 * assignment should ensure a valid VL for the task.
+		 * If not, something went badly wrong.
 		 */
-		if (!current->thread.sve_vl) {
-			BUG_ON(!sve_vl_valid(sve_max_vl));
+		BUG_ON(!sve_vl_valid(current->thread.sve_vl));
 
-			current->thread.sve_vl = sve_max_vl;
-		}
+		/*
+		 * If the task is not set to inherit, ensure that the vector
+		 * length will be reset by a subsequent exec:
+		 */
+		if (!(current->thread.sve_flags & THREAD_VL_INHERIT))
+			current->thread.sve_vl_onexec = 0;
 	}
 
 	set_thread_flag(TIF_FOREIGN_FPSTATE);
diff --git a/include/uapi/linux/prctl.h b/include/uapi/linux/prctl.h
index c55530b..d56c447 100644
--- a/include/uapi/linux/prctl.h
+++ b/include/uapi/linux/prctl.h
@@ -200,6 +200,12 @@ struct prctl_mm_map {
 /* arm64 Scalable Vector Extension controls */
 #define PR_SVE_SET_VL			48	/* set task vector length */
 # define PR_SVE_SET_VL_THREAD		(1 << 1) /* set just this thread */
+# define PR_SVE_SET_VL_INHERIT		(1 << 2) /* inherit across exec */
+# define PR_SVE_SET_VL_ONEXEC		(1 << 3) /* defer effect until exec */
 #define PR_SVE_GET_VL			49	/* get task vector length */
+/* Decode helpers for the return value from PR_SVE_GET_VL: */
+# define PR_SVE_GET_VL_LEN(ret)		((ret) & 0x3fff) /* vector length */
+# define PR_SVE_GET_VL_INHERIT		(PR_SVE_SET_VL_INHERIT << 16)
+/* For conveinence, PR_SVE_SET_VL returns the result in the same encoding */
 
 #endif /* _LINUX_PRCTL_H */
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [RFC PATCH v2 36/41] arm64/sve: ptrace: Wire up vector length control and reporting
  2017-03-22 14:50 ` Dave Martin
                   ` (35 preceding siblings ...)
  (?)
@ 2017-03-22 14:51 ` Dave Martin
  -1 siblings, 0 replies; 75+ messages in thread
From: Dave Martin @ 2017-03-22 14:51 UTC (permalink / raw)
  To: linux-arm-kernel

This patch adds support for manipulating a task's vector length at
runtime via ptrace.

As a simplification, we turn the task back into an FPSIMD-only task
when changing the vector length.  If the register data is written
too, we then turn the task back into an SVE task, with changed
task_struct layout for the SVE data, before the actual data writing
is done.

Because the vector length is now variable, sve_get() now needs to
return the real maximum for user_sve_header.max_vl, since .vl may
be less than this (that's the whole point).

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
---
 arch/arm64/include/asm/fpsimd.h      |  2 ++
 arch/arm64/include/uapi/asm/ptrace.h |  6 ++++++
 arch/arm64/kernel/ptrace.c           | 25 +++++++++++++++----------
 3 files changed, 23 insertions(+), 10 deletions(-)

diff --git a/arch/arm64/include/asm/fpsimd.h b/arch/arm64/include/asm/fpsimd.h
index 764da0f..385ef226 100644
--- a/arch/arm64/include/asm/fpsimd.h
+++ b/arch/arm64/include/asm/fpsimd.h
@@ -105,6 +105,8 @@ extern void *__sve_state(struct task_struct *task);
 
 #ifdef CONFIG_ARM64_SVE
 
+extern int sve_max_vl;
+
 extern void fpsimd_sync_to_sve(struct task_struct *task);
 extern void sve_sync_to_fpsimd(struct task_struct *task);
 extern void sve_sync_from_fpsimd_zeropad(struct task_struct *task);
diff --git a/arch/arm64/include/uapi/asm/ptrace.h b/arch/arm64/include/uapi/asm/ptrace.h
index f26b68e..69a2700 100644
--- a/arch/arm64/include/uapi/asm/ptrace.h
+++ b/arch/arm64/include/uapi/asm/ptrace.h
@@ -64,6 +64,8 @@
 
 #ifndef __ASSEMBLY__
 
+#include <linux/prctl.h>
+
 /*
  * User structures for general purpose, floating point and debug registers.
  */
@@ -108,6 +110,10 @@ struct user_sve_header {
 #define SVE_PT_REGS_FPSIMD		0
 #define SVE_PT_REGS_SVE			SVE_PT_REGS_MASK
 
+#define SVE_PT_VL_THREAD		PR_SVE_SET_VL_THREAD
+#define SVE_PT_VL_INHERIT		PR_SVE_SET_VL_INHERIT
+#define SVE_PT_VL_ONEXEC		PR_SVE_SET_VL_ONEXEC
+
 
 /*
  * The remainder of the SVE state follows struct user_sve_header.  The
diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
index 72b922a..02d3265 100644
--- a/arch/arm64/kernel/ptrace.c
+++ b/arch/arm64/kernel/ptrace.c
@@ -751,14 +751,15 @@ static int sve_get(struct task_struct *target,
 	BUG_ON(!sve_vl_valid(header.vl));
 	vq = sve_vq_from_vl(header.vl);
 
-	/* Until runtime or per-task vector length changing is supported: */
-	header.max_vl = header.vl;
+	BUG_ON(!sve_vl_valid(sve_max_vl));
+	header.max_vl = sve_max_vl;
 
 	header.flags = test_tsk_thread_flag(target, TIF_SVE) ?
 		SVE_PT_REGS_SVE : SVE_PT_REGS_FPSIMD;
 
 	header.size = SVE_PT_SIZE(vq, header.flags);
-	header.max_size = SVE_PT_SIZE(vq, SVE_PT_REGS_SVE);
+	header.max_size = SVE_PT_SIZE(sve_vq_from_vl(header.max_vl),
+				      SVE_PT_REGS_SVE);
 
 	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &header,
 				  0, sizeof(header));
@@ -845,14 +846,18 @@ static int sve_set(struct task_struct *target,
 	if (ret)
 		goto out;
 
-	if (header.vl != target->thread.sve_vl)
-		return -EINVAL;
-
-	BUG_ON(!sve_vl_valid(header.vl));
-	vq = sve_vq_from_vl(header.vl);
+	/*
+	 * Apart from PT_SVE_REGS_MASK, all PT_SVE_* flags are consumed by
+	 * sve_set_vector_length(), which will also validate them for us:
+	 */
+	ret = sve_set_vector_length(target, header.vl,
+				    header.flags & ~SVE_PT_REGS_MASK);
+	if (ret)
+		goto out;
 
-	if (header.flags & ~SVE_PT_REGS_MASK)
-		return -EINVAL;
+	/* Actual VL set may be less than the user asked for: */
+	BUG_ON(!sve_vl_valid(target->thread.sve_vl));
+	vq = sve_vq_from_vl(target->thread.sve_vl);
 
 	/* Registers: FPSIMD-only case */
 
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [RFC PATCH v2 37/41] arm64/sve: Enable default vector length control via procfs
  2017-03-22 14:50 ` Dave Martin
                   ` (36 preceding siblings ...)
  (?)
@ 2017-03-22 14:51 ` Dave Martin
  -1 siblings, 0 replies; 75+ messages in thread
From: Dave Martin @ 2017-03-22 14:51 UTC (permalink / raw)
  To: linux-arm-kernel

This patch makes the default SVE vector length at exec() for user tasks
controllable via procfs, in /proc/cpu/sve_default_vector_length.

Limited effort is made to return sensible errors when writing the
procfs file, and anyway the value gets silently clamped to the
maximum VL supported by the platform: users should close and reopen
the file and read back to see the result.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
---
 arch/arm64/kernel/fpsimd.c | 162 ++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 160 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index 982b1d7..ddb651a 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -22,8 +22,12 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/prctl.h>
+#include <linux/proc_fs.h>
 #include <linux/sched/signal.h>
+#include <linux/seq_file.h>
 #include <linux/signal.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
 #include <linux/hardirq.h>
 
 #include <asm/fpsimd.h>
@@ -100,6 +104,8 @@ static DEFINE_PER_CPU(struct fpsimd_state *, fpsimd_last_state);
 
 /* Maximum supported vector length across all CPUs (initially poisoned) */
 int sve_max_vl = -1;
+/* Default VL for tasks that don't set it explicitly: */
+int sve_default_vl = -1;
 
 void *__sve_state(struct task_struct *task)
 {
@@ -334,13 +340,154 @@ int sve_get_task_vl(struct task_struct *task)
 	return sve_prctl_status(task);
 }
 
+#ifdef CONFIG_PROC_FS
+
+struct default_vl_write_state {
+	bool invalid;
+	size_t len;
+	char buf[40];	/* enough for "0x" + 64-bit hex integer + NUL */
+};
+
+static int sve_default_vl_show(struct seq_file *s, void *data)
+{
+	seq_printf(s, "%d\n", sve_default_vl);
+	return 0;
+}
+
+static ssize_t sve_default_vl_write(struct file *f, const char __user *buf,
+				    size_t size, loff_t *pos)
+{
+	struct default_vl_write_state *state =
+		((struct seq_file *)f->private_data)->private;
+	long ret;
+
+	if (!size)
+		return 0;
+
+	if (*pos > sizeof(state->buf) ||
+	    size >= sizeof(state->buf) - *pos) {
+		ret = -ENOSPC;
+		goto error;
+	}
+
+	ret = copy_from_user(state->buf + *pos, buf, size);
+	if (ret > 0)
+		ret = -EINVAL;
+	if (ret)
+		goto error;
+
+	*pos += size;
+	if (*pos > state->len)
+		state->len = *pos;
+
+	return size;
+
+error:
+	state->invalid = true;
+	return ret;
+}
+
+static int sve_default_vl_release(struct inode *i, struct file *f)
+{
+	int ret = 0;
+	int t;
+	unsigned long value;
+	struct default_vl_write_state *state =
+		((struct seq_file *)f->private_data)->private;
+
+	if (!(f->f_mode & FMODE_WRITE))
+		goto out;
+
+	if (state->invalid)
+		goto out;
+
+	if (state->len >= sizeof(state->buf)) {
+		WARN_ON(1);
+		state->len = sizeof(state->buf) - 1;
+	}
+
+	state->buf[state->len] = '\0';
+	t = kstrtoul(state->buf, 0, &value);
+	if (t)
+		ret = t;
+
+	if (!sve_vl_valid(value))
+		ret = -EINVAL;
+
+	if (!sve_vl_valid(sve_max_vl)) {
+		WARN_ON(1);
+		ret = -EINVAL;
+	}
+
+	if (value > sve_max_vl)
+		value = sve_max_vl;
+
+	if (!ret)
+		sve_default_vl = value;
+
+out:
+	t = seq_release_private(i, f);
+	return ret ? ret : t;
+}
+
+static int sve_default_vl_open(struct inode *i, struct file *f)
+{
+	struct default_vl_write_state *data = NULL;
+	int ret;
+
+	if (f->f_mode & FMODE_WRITE) {
+		data = kzalloc(sizeof(*data), GFP_KERNEL);
+		if (!data)
+			return -ENOMEM;
+
+		data->invalid = false;
+		data->len = 0;
+	}
+
+	ret = single_open(f, sve_default_vl_show, data);
+	if (ret)
+		kfree(data);
+
+	return ret;
+}
+
+static const struct file_operations sve_default_vl_fops = {
+	.open		= sve_default_vl_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= sve_default_vl_release,
+	.write		= sve_default_vl_write,
+};
+
+static int __init sve_procfs_init(void)
+{
+	struct proc_dir_entry *dir;
+
+	/* This should be moved elsewhere is anything else ever uses it: */
+	dir = proc_mkdir("cpu", NULL);
+	if (!dir)
+		return -ENOMEM;
+
+	if (!proc_create("sve_default_vector_length",
+			 S_IRUGO | S_IWUSR, dir, &sve_default_vl_fops))
+		return -ENOMEM;
+
+	return 0;
+}
+
+#else /* ! CONFIG_PROC_FS && CONFIG_ARM64_SVE */
+static int __init sve_procfs_init(void) { return 0; }
+#endif /* ! CONFIG_PROC_FS && CONFIG_ARM64_SVE */
+
 #else /* ! CONFIG_ARM64_SVE */
 
 /* Dummy declarations for usage protected with IS_ENABLED(CONFIG_ARM64_SVE): */
 extern int sve_max_vl;
+extern int sve_default_vl;
 extern void clear_sve_regs(struct task_struct *task);
 extern void *sve_pffr(struct task_struct *task);
 extern void fpsimd_to_sve(struct task_struct *task);
+extern int __init sve_procfs_init(void);
 
 /* Functions that map to no-ops without SVE: */
 static void sve_to_fpsimd(struct task_struct *task __always_unused) { }
@@ -489,13 +636,13 @@ void fpsimd_flush_thread(void)
 		clear_sve_regs(current);
 
 		current->thread.sve_vl = current->thread.sve_vl_onexec ?
-			current->thread.sve_vl_onexec : sve_max_vl;
+			current->thread.sve_vl_onexec : sve_default_vl;
 
 		/*
 		 * User tasks must have a valid vector length set, but tasks
 		 * forked early (e.g., init) may not initially have one.
 		 * By now, we will know what the hardware supports, so
-		 * sve_max_vl should be valid, and thus the above
+		 * sve_default_vl should be valid, and thus the above
 		 * assignment should ensure a valid VL for the task.
 		 * If not, something went badly wrong.
 		 */
@@ -717,6 +864,14 @@ void __init fpsimd_init_task_struct_size(void)
 	     & 0xf) == 1) {
 		/* FIXME: This should be the minimum across all CPUs */
 		sve_max_vl = sve_get_vl();
+		sve_default_vl = sve_max_vl;
+
+		/*
+		 * To avoid enlarging the signal frame by default, clamp to
+		 * 512 bits until/unless overridden by userspace:
+		 */
+		if (sve_default_vl > 512 / 8)
+			sve_default_vl = 512 / 8;
 
 		BUG_ON(!sve_vl_valid(sve_max_vl));
 		vq = sve_vq_from_vl(sve_max_vl);
@@ -746,6 +901,9 @@ static int __init fpsimd_init(void)
 	if (!(elf_hwcap & HWCAP_SVE))
 		pr_info("Scalable Vector Extension available\n");
 
+	if (IS_ENABLED(CONFIG_ARM64_SVE) && (elf_hwcap & HWCAP_SVE))
+		return sve_procfs_init();
+
 	return 0;
 }
 late_initcall(fpsimd_init);
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [RFC PATCH v2 38/41] arm64/sve: Detect SVE via the cpufeature framework
  2017-03-22 14:50 ` Dave Martin
                   ` (37 preceding siblings ...)
  (?)
@ 2017-03-22 14:51 ` Dave Martin
  2017-03-23 14:11   ` Suzuki K Poulose
  -1 siblings, 1 reply; 75+ messages in thread
From: Dave Martin @ 2017-03-22 14:51 UTC (permalink / raw)
  To: linux-arm-kernel

For robust feature detection and appropriate handling of feature
mismatches between CPUs, this patch adds knowledge of the new
feature fields and new registers ZCR_EL1 and ID_AA64ZFR0_EL1 to the
cpufeature framework.

ZCR_EL1 is not architecturally an ID register, but for smoother
integration with the cpufeatures code, this patch pretends that it
is: the LEN field is populated with the maximum supported value.
The minimum can then be taken across all CPUs and used later on to
configure the default and supported set of vector lengths for the
system.

For now, this must coexist with (and overrides) and early
initialisation done by init_task_struct_size(), which may allocate
more space in task_struct that we really need.  This will be
addressed in subsequent patches.

No fields are yet defined in ID_AA64ZFR0_EL1, and if zeros don't
stick to any of the RES0 bits in ZCR_EL1, that likely indicates
something won't work the way the kernel expects: this patch follows
the established policy of warning about mismatches and treating the
affected register or fields as zero for feature determination
purposes.

The SVE field in AA64PFR0 is made visible visible to userspace MRS
emulation.  This should make sense for future architecture
extensions.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
---
 arch/arm64/include/asm/cpu.h        |  3 +++
 arch/arm64/include/asm/cpucaps.h    |  3 ++-
 arch/arm64/include/asm/cpufeature.h | 12 ++++++++++++
 arch/arm64/include/asm/fpsimd.h     |  4 ++++
 arch/arm64/include/asm/sysreg.h     |  4 ++++
 arch/arm64/kernel/cpufeature.c      | 38 ++++++++++++++++++++++++++++++++++++-
 arch/arm64/kernel/cpuinfo.c         | 13 +++++++++++++
 arch/arm64/kernel/fpsimd.c          | 23 +++++++++++++++++++---
 8 files changed, 95 insertions(+), 5 deletions(-)

diff --git a/arch/arm64/include/asm/cpu.h b/arch/arm64/include/asm/cpu.h
index 889226b..2318914 100644
--- a/arch/arm64/include/asm/cpu.h
+++ b/arch/arm64/include/asm/cpu.h
@@ -41,6 +41,7 @@ struct cpuinfo_arm64 {
 	u64		reg_id_aa64mmfr2;
 	u64		reg_id_aa64pfr0;
 	u64		reg_id_aa64pfr1;
+	u64		reg_id_aa64zfr0;
 
 	u32		reg_id_dfr0;
 	u32		reg_id_isar0;
@@ -59,6 +60,8 @@ struct cpuinfo_arm64 {
 	u32		reg_mvfr0;
 	u32		reg_mvfr1;
 	u32		reg_mvfr2;
+
+	u64		reg_zcr;
 };
 
 DECLARE_PER_CPU(struct cpuinfo_arm64, cpu_data);
diff --git a/arch/arm64/include/asm/cpucaps.h b/arch/arm64/include/asm/cpucaps.h
index fb78a5d..cebb602 100644
--- a/arch/arm64/include/asm/cpucaps.h
+++ b/arch/arm64/include/asm/cpucaps.h
@@ -37,7 +37,8 @@
 #define ARM64_HAS_NO_FPSIMD			16
 #define ARM64_WORKAROUND_REPEAT_TLBI		17
 #define ARM64_WORKAROUND_QCOM_FALKOR_E1003	18
+#define ARM64_SVE				19
 
-#define ARM64_NCAPS				19
+#define ARM64_NCAPS				20
 
 #endif /* __ASM_CPUCAPS_H */
diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h
index f31c48d..90e4b79 100644
--- a/arch/arm64/include/asm/cpufeature.h
+++ b/arch/arm64/include/asm/cpufeature.h
@@ -215,6 +215,13 @@ static inline bool id_aa64pfr0_32bit_el0(u64 pfr0)
 	return val == ID_AA64PFR0_EL0_32BIT_64BIT;
 }
 
+static inline bool id_aa64pfr0_sve(u64 pfr0)
+{
+	u32 val = cpuid_feature_extract_unsigned_field(pfr0, ID_AA64PFR0_SVE_SHIFT);
+
+	return val > 0;
+}
+
 void __init setup_cpu_features(void);
 
 void update_cpu_capabilities(const struct arm64_cpu_capabilities *caps,
@@ -254,6 +261,11 @@ static inline bool system_uses_ttbr0_pan(void)
 		!cpus_have_const_cap(ARM64_HAS_PAN);
 }
 
+static inline bool system_supports_sve(void)
+{
+	return cpus_have_const_cap(ARM64_SVE);
+}
+
 #endif /* __ASSEMBLY__ */
 
 #endif
diff --git a/arch/arm64/include/asm/fpsimd.h b/arch/arm64/include/asm/fpsimd.h
index 385ef226..4a50139 100644
--- a/arch/arm64/include/asm/fpsimd.h
+++ b/arch/arm64/include/asm/fpsimd.h
@@ -118,6 +118,8 @@ extern int sve_set_task_vl(struct task_struct *task,
 			   unsigned long vector_length, unsigned long flags);
 extern int sve_get_task_vl(struct task_struct *task);
 
+extern void __init sve_setup(void);
+
 #else /* ! CONFIG_ARM64_SVE */
 
 static void __maybe_unused sve_sync_to_fpsimd(struct task_struct *task) { }
@@ -135,6 +137,8 @@ static int __maybe_unused sve_get_task_vl(struct task_struct *task)
 	return -EINVAL;
 }
 
+static void __maybe_unused sve_setup(void) { }
+
 #endif /* ! CONFIG_ARM64_SVE */
 
 #endif
diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index 9c4a2cc..9bfe156 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -107,6 +107,7 @@
 
 #define SYS_ID_AA64PFR0_EL1		sys_reg(3, 0, 0, 4, 0)
 #define SYS_ID_AA64PFR1_EL1		sys_reg(3, 0, 0, 4, 1)
+#define SYS_ID_AA64ZFR0_EL1		sys_reg(3, 0, 0, 4, 4)
 
 #define SYS_ID_AA64DFR0_EL1		sys_reg(3, 0, 0, 5, 0)
 #define SYS_ID_AA64DFR1_EL1		sys_reg(3, 0, 0, 5, 1)
@@ -169,6 +170,7 @@
 #define ID_AA64PFR0_EL1_SHIFT		4
 #define ID_AA64PFR0_EL0_SHIFT		0
 
+#define ID_AA64PFR0_SVE			0x1
 #define ID_AA64PFR0_FP_NI		0xf
 #define ID_AA64PFR0_FP_SUPPORTED	0x0
 #define ID_AA64PFR0_ASIMD_NI		0xf
@@ -270,6 +272,8 @@
 #endif
 
 
+#define ZCR_EL1_LEN_SHIFT	0
+#define ZCR_EL1_LEN_SIZE	9
 #define ZCR_EL1_LEN_MASK	0x1ff
 
 #define CPACR_EL1_ZEN_EL1EN	(1 << 16)
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index 707dfdb..83c1999 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -27,6 +27,7 @@
 #include <asm/cpu.h>
 #include <asm/cpufeature.h>
 #include <asm/cpu_ops.h>
+#include <asm/fpsimd.h>
 #include <asm/mmu_context.h>
 #include <asm/processor.h>
 #include <asm/sysreg.h>
@@ -98,6 +99,7 @@ static const struct arm64_ftr_bits ftr_id_aa64isar0[] = {
 };
 
 static const struct arm64_ftr_bits ftr_id_aa64pfr0[] = {
+	ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_SVE_SHIFT, 4, 0),
 	ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_EXACT, ID_AA64PFR0_GIC_SHIFT, 4, 0),
 	S_ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_ASIMD_SHIFT, 4, ID_AA64PFR0_ASIMD_NI),
 	S_ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_FP_SHIFT, 4, ID_AA64PFR0_FP_NI),
@@ -241,6 +243,12 @@ static const struct arm64_ftr_bits ftr_id_dfr0[] = {
 	ARM64_FTR_END,
 };
 
+static const struct arm64_ftr_bits ftr_zcr[] = {
+	ARM64_FTR_BITS(FTR_HIDDEN, FTR_NONSTRICT, FTR_LOWER_SAFE,
+		ZCR_EL1_LEN_SHIFT, ZCR_EL1_LEN_SIZE, 0),	/* LEN */
+	ARM64_FTR_END,
+};
+
 /*
  * Common ftr bits for a 32bit register with all hidden, strict
  * attributes, with 4bit feature fields and a default safe value of
@@ -307,6 +315,7 @@ static const struct __ftr_reg_entry {
 	/* Op1 = 0, CRn = 0, CRm = 4 */
 	ARM64_FTR_REG(SYS_ID_AA64PFR0_EL1, ftr_id_aa64pfr0),
 	ARM64_FTR_REG(SYS_ID_AA64PFR1_EL1, ftr_raz),
+	ARM64_FTR_REG(SYS_ID_AA64ZFR0_EL1, ftr_raz),
 
 	/* Op1 = 0, CRn = 0, CRm = 5 */
 	ARM64_FTR_REG(SYS_ID_AA64DFR0_EL1, ftr_id_aa64dfr0),
@@ -321,6 +330,9 @@ static const struct __ftr_reg_entry {
 	ARM64_FTR_REG(SYS_ID_AA64MMFR1_EL1, ftr_id_aa64mmfr1),
 	ARM64_FTR_REG(SYS_ID_AA64MMFR2_EL1, ftr_id_aa64mmfr2),
 
+	/* Op1 = 0, CRn = 1, CRm = 2 */
+	ARM64_FTR_REG(SYS_ZCR_EL1, ftr_zcr),
+
 	/* Op1 = 3, CRn = 0, CRm = 0 */
 	{ SYS_CTR_EL0, &arm64_ftr_reg_ctrel0 },
 	ARM64_FTR_REG(SYS_DCZID_EL0, ftr_dczid),
@@ -458,6 +470,7 @@ void __init init_cpu_features(struct cpuinfo_arm64 *info)
 	init_cpu_ftr_reg(SYS_ID_AA64MMFR2_EL1, info->reg_id_aa64mmfr2);
 	init_cpu_ftr_reg(SYS_ID_AA64PFR0_EL1, info->reg_id_aa64pfr0);
 	init_cpu_ftr_reg(SYS_ID_AA64PFR1_EL1, info->reg_id_aa64pfr1);
+	init_cpu_ftr_reg(SYS_ID_AA64ZFR0_EL1, info->reg_id_aa64zfr0);
 
 	if (id_aa64pfr0_32bit_el0(info->reg_id_aa64pfr0)) {
 		init_cpu_ftr_reg(SYS_ID_DFR0_EL1, info->reg_id_dfr0);
@@ -478,6 +491,8 @@ void __init init_cpu_features(struct cpuinfo_arm64 *info)
 		init_cpu_ftr_reg(SYS_MVFR2_EL1, info->reg_mvfr2);
 	}
 
+	if (id_aa64pfr0_sve(info->reg_id_aa64pfr0))
+		init_cpu_ftr_reg(SYS_ZCR_EL1, info->reg_zcr);
 }
 
 static void update_cpu_ftr_reg(struct arm64_ftr_reg *reg, u64 new)
@@ -581,6 +596,9 @@ void update_cpu_features(int cpu,
 	taint |= check_update_ftr_reg(SYS_ID_AA64PFR1_EL1, cpu,
 				      info->reg_id_aa64pfr1, boot->reg_id_aa64pfr1);
 
+	taint |= check_update_ftr_reg(SYS_ID_AA64ZFR0_EL1, cpu,
+				      info->reg_id_aa64zfr0, boot->reg_id_aa64zfr0);
+
 	/*
 	 * If we have AArch32, we care about 32-bit features for compat.
 	 * If the system doesn't support AArch32, don't update them.
@@ -628,6 +646,10 @@ void update_cpu_features(int cpu,
 					info->reg_mvfr2, boot->reg_mvfr2);
 	}
 
+	if (id_aa64pfr0_sve(info->reg_id_aa64pfr0))
+		taint |= check_update_ftr_reg(SYS_ZCR_EL1, cpu,
+					info->reg_zcr, boot->reg_zcr);
+
 	/*
 	 * Mismatched CPU features are a recipe for disaster. Don't even
 	 * pretend to support them.
@@ -860,6 +882,18 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
 		.min_field_value = 0,
 		.matches = has_no_fpsimd,
 	},
+#ifdef CONFIG_ARM64_SVE
+	{
+		.desc = "Scalable Vector Extension",
+		.capability = ARM64_SVE,
+		.def_scope = SCOPE_SYSTEM,
+		.sys_reg = SYS_ID_AA64PFR0_EL1,
+		.sign = FTR_UNSIGNED,
+		.field_pos = ID_AA64PFR0_SVE_SHIFT,
+		.min_field_value = ID_AA64PFR0_SVE,
+		.matches = has_cpuid_feature,
+	},
+#endif /* CONFIG_ARM64_SVE */
 	{},
 };
 
@@ -889,7 +923,7 @@ static const struct arm64_cpu_capabilities arm64_elf_hwcaps[] = {
 	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),
+	HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_SVE_SHIFT, FTR_UNSIGNED, ID_AA64PFR0_SVE, CAP_HWCAP, HWCAP_SVE),
 #endif
 	{},
 };
@@ -1120,6 +1154,8 @@ void __init setup_cpu_features(void)
 	if (system_supports_32bit_el0())
 		setup_elf_hwcaps(compat_elf_hwcaps);
 
+	sve_setup();
+
 	/* Advertise that we have computed the system capabilities */
 	set_sys_caps_initialised();
 
diff --git a/arch/arm64/kernel/cpuinfo.c b/arch/arm64/kernel/cpuinfo.c
index 8dd410e..cb3b0dd 100644
--- a/arch/arm64/kernel/cpuinfo.c
+++ b/arch/arm64/kernel/cpuinfo.c
@@ -19,6 +19,7 @@
 #include <asm/cpu.h>
 #include <asm/cputype.h>
 #include <asm/cpufeature.h>
+#include <asm/fpsimd.h>
 
 #include <linux/bitops.h>
 #include <linux/bug.h>
@@ -325,6 +326,7 @@ static void __cpuinfo_store_cpu(struct cpuinfo_arm64 *info)
 	info->reg_id_aa64mmfr2 = read_cpuid(ID_AA64MMFR2_EL1);
 	info->reg_id_aa64pfr0 = read_cpuid(ID_AA64PFR0_EL1);
 	info->reg_id_aa64pfr1 = read_cpuid(ID_AA64PFR1_EL1);
+	info->reg_id_aa64zfr0 = read_cpuid(ID_AA64ZFR0_EL1);
 
 	/* Update the 32bit ID registers only if AArch32 is implemented */
 	if (id_aa64pfr0_32bit_el0(info->reg_id_aa64pfr0)) {
@@ -347,6 +349,17 @@ static void __cpuinfo_store_cpu(struct cpuinfo_arm64 *info)
 		info->reg_mvfr2 = read_cpuid(MVFR2_EL1);
 	}
 
+	if (id_aa64pfr0_sve(info->reg_id_aa64pfr0)) {
+		u64 zcr;
+
+		write_sysreg_s(ZCR_EL1_LEN_MASK, SYS_ZCR_EL1);
+		zcr = read_sysreg_s(SYS_ZCR_EL1);
+		zcr &= ~(u64)ZCR_EL1_LEN_MASK;
+		zcr |= sve_get_vl() / 16 - 1;
+
+		info->reg_zcr = zcr;
+	}
+
 	cpuinfo_detect_icache_policy(info);
 }
 
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index ddb651a..34ec75e 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -340,6 +340,26 @@ int sve_get_task_vl(struct task_struct *task)
 	return sve_prctl_status(task);
 }
 
+void __init sve_setup(void)
+{
+	u64 zcr;
+
+	if (!system_supports_sve())
+		return;
+
+	zcr = read_system_reg(SYS_ZCR_EL1);
+
+	BUG_ON(((zcr & ZCR_EL1_LEN_MASK) + 1) * 16 > sve_max_vl);
+
+	sve_max_vl = ((zcr & ZCR_EL1_LEN_MASK) + 1) * 16;
+	sve_default_vl = sve_max_vl > 64 ? 64 : sve_max_vl;
+
+	pr_info("SVE: maximum available vector length %u bytes per vector\n",
+		sve_max_vl);
+	pr_info("SVE: default vector length %u bytes per vector\n",
+		sve_default_vl);
+}
+
 #ifdef CONFIG_PROC_FS
 
 struct default_vl_write_state {
@@ -898,9 +918,6 @@ static int __init fpsimd_init(void)
 	if (!(elf_hwcap & HWCAP_ASIMD))
 		pr_notice("Advanced SIMD is not implemented\n");
 
-	if (!(elf_hwcap & HWCAP_SVE))
-		pr_info("Scalable Vector Extension available\n");
-
 	if (IS_ENABLED(CONFIG_ARM64_SVE) && (elf_hwcap & HWCAP_SVE))
 		return sve_procfs_init();
 
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [RFC PATCH v2 39/41] arm64/sve: Migrate to cpucap based detection for runtime SVE code
  2017-03-22 14:50 ` Dave Martin
                   ` (38 preceding siblings ...)
  (?)
@ 2017-03-22 14:51 ` Dave Martin
  -1 siblings, 0 replies; 75+ messages in thread
From: Dave Martin @ 2017-03-22 14:51 UTC (permalink / raw)
  To: linux-arm-kernel

Checking elf_hwcap multiple times on the context switch path is an
unnecessary cost.

Because the cpufeature framework allows for more efficient
decisions by branch patching, it will be more efficient to test for
the ARM64_SVE CPU capability using cpus_have_const_cap() instead.

The test is guarded with IS_ENABLED() so that SVE-dependent code
can still be optimised out if CONFIG_ARM64_SVE is not set.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
---
 arch/arm64/include/asm/cpufeature.h |  3 ++-
 arch/arm64/kernel/fpsimd.c          | 26 ++++++++++++--------------
 arch/arm64/kernel/ptrace.c          |  5 +++--
 arch/arm64/kernel/signal.c          | 14 +++++---------
 4 files changed, 22 insertions(+), 26 deletions(-)

diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h
index 90e4b79..e8d4857 100644
--- a/arch/arm64/include/asm/cpufeature.h
+++ b/arch/arm64/include/asm/cpufeature.h
@@ -263,7 +263,8 @@ static inline bool system_uses_ttbr0_pan(void)
 
 static inline bool system_supports_sve(void)
 {
-	return cpus_have_const_cap(ARM64_SVE);
+	return IS_ENABLED(CONFIG_ARM64_SVE) &&
+		cpus_have_const_cap(ARM64_SVE);
 }
 
 #endif /* __ASSEMBLY__ */
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index 34ec75e..2b9def0 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -148,7 +148,7 @@ static void fpsimd_to_sve(struct task_struct *task)
 {
 	unsigned int vl = task->thread.sve_vl;
 
-	if (!(elf_hwcap & HWCAP_SVE))
+	if (!system_supports_sve())
 		return;
 
 	BUG_ON(!sve_vl_valid(vl));
@@ -169,7 +169,7 @@ static void sve_to_fpsimd(struct task_struct *task)
 {
 	unsigned int vl = task->thread.sve_vl;
 
-	if (!(elf_hwcap & HWCAP_SVE))
+	if (!system_supports_sve())
 		return;
 
 	BUG_ON(!sve_vl_valid(vl));
@@ -316,7 +316,7 @@ int sve_set_task_vl(struct task_struct *task,
 {
 	int ret;
 
-	if (!(elf_hwcap & HWCAP_SVE))
+	if (!system_supports_sve())
 		return -EINVAL;
 
 	BUG_ON(task != current);
@@ -334,7 +334,7 @@ int sve_set_task_vl(struct task_struct *task,
 /* PR_SVE_GET_VL */
 int sve_get_task_vl(struct task_struct *task)
 {
-	if (!(elf_hwcap & HWCAP_SVE))
+	if (!system_supports_sve())
 		return -EINVAL;
 
 	return sve_prctl_status(task);
@@ -552,8 +552,7 @@ void do_fpsimd_exc(unsigned int esr, struct pt_regs *regs)
 
 static void task_fpsimd_load(struct task_struct *task)
 {
-	if (IS_ENABLED(CONFIG_ARM64_SVE) &&
-	    test_tsk_thread_flag(task, TIF_SVE)) {
+	if (system_supports_sve() && test_tsk_thread_flag(task, TIF_SVE)) {
 		unsigned int vl = task->thread.sve_vl;
 
 		BUG_ON(!sve_vl_valid(vl));
@@ -567,7 +566,7 @@ static void task_fpsimd_load(struct task_struct *task)
 	 * Flip SVE enable for userspace if it doesn't match the
 	 * current_task.
 	 */
-	if (IS_ENABLED(CONFIG_ARM64_SVE) && (elf_hwcap & HWCAP_SVE)) {
+	if (system_supports_sve()) {
 		unsigned int tmp, flags;
 
 		asm ("mrs %0, cpacr_el1" : "=r" (tmp));
@@ -586,7 +585,7 @@ static void task_fpsimd_save(struct task_struct *task)
 	/* FIXME: remove task argument? */
 	BUG_ON(task != current);
 
-	if (IS_ENABLED(CONFIG_ARM64_SVE) &&
+	if (system_supports_sve() &&
 	    task_pt_regs(task)->syscallno != ~0UL &&
 	    test_tsk_thread_flag(task, TIF_SVE)) {
 		unsigned long tmp;
@@ -603,8 +602,7 @@ static void task_fpsimd_save(struct task_struct *task)
 		);
 	}
 
-	if (IS_ENABLED(CONFIG_ARM64_SVE) &&
-	    test_tsk_thread_flag(task, TIF_SVE))
+	if (system_supports_sve() && test_tsk_thread_flag(task, TIF_SVE))
 		sve_save_state(sve_pffr(task),
 			       &task->thread.fpsimd_state.fpsr);
 	else
@@ -652,7 +650,7 @@ void fpsimd_flush_thread(void)
 
 	memset(&current->thread.fpsimd_state, 0, sizeof(struct fpsimd_state));
 
-	if (IS_ENABLED(CONFIG_ARM64_SVE) && (elf_hwcap & HWCAP_SVE)) {
+	if (system_supports_sve()) {
 		clear_sve_regs(current);
 
 		current->thread.sve_vl = current->thread.sve_vl_onexec ?
@@ -733,7 +731,7 @@ void fpsimd_update_current_state(struct fpsimd_state *state)
 		return;
 	preempt_disable();
 
-	if (IS_ENABLED(CONFIG_ARM64_SVE) && test_thread_flag(TIF_SVE)) {
+	if (system_supports_sve() && test_thread_flag(TIF_SVE)) {
 		current->thread.fpsimd_state = *state;
 		fpsimd_to_sve(current);
 	}
@@ -777,7 +775,7 @@ void kernel_neon_begin_partial(u32 num_regs)
 	 * interrupt context, so always save the userland SVE state
 	 * if there is any, even for interrupts.
 	 */
-	if (IS_ENABLED(CONFIG_ARM64_SVE) &&
+	if (system_supports_sve() &&
 	    test_thread_flag(TIF_SVE) && current->mm &&
 	    !test_and_set_thread_flag(TIF_FOREIGN_FPSTATE)) {
 		fpsimd_save_state(&current->thread.fpsimd_state);
@@ -918,7 +916,7 @@ static int __init fpsimd_init(void)
 	if (!(elf_hwcap & HWCAP_ASIMD))
 		pr_notice("Advanced SIMD is not implemented\n");
 
-	if (IS_ENABLED(CONFIG_ARM64_SVE) && (elf_hwcap & HWCAP_SVE))
+	if (system_supports_sve())
 		return sve_procfs_init();
 
 	return 0;
diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
index 02d3265..bbb8e38 100644
--- a/arch/arm64/kernel/ptrace.c
+++ b/arch/arm64/kernel/ptrace.c
@@ -42,6 +42,7 @@
 #include <linux/elf.h>
 
 #include <asm/compat.h>
+#include <asm/cpufeature.h>
 #include <asm/debug-monitors.h>
 #include <asm/pgtable.h>
 #include <asm/syscall.h>
@@ -740,7 +741,7 @@ static int sve_get(struct task_struct *target,
 	unsigned int vq;
 	unsigned long start, end;
 
-	if (!(elf_hwcap & HWCAP_SVE))
+	if (!system_supports_sve())
 		return -EINVAL;
 
 	/* Header */
@@ -835,7 +836,7 @@ static int sve_set(struct task_struct *target,
 	unsigned int vq;
 	unsigned long start, end;
 
-	if (!(elf_hwcap & HWCAP_SVE))
+	if (!system_supports_sve())
 		return -EINVAL;
 
 	/* Header */
diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c
index 45f0c2c..e3810e2 100644
--- a/arch/arm64/kernel/signal.c
+++ b/arch/arm64/kernel/signal.c
@@ -378,10 +378,7 @@ static int parse_user_sigframe(struct user_ctxs *user,
 			break;
 
 		case SVE_MAGIC:
-			if (!IS_ENABLED(CONFIG_ARM64_SVE))
-				goto invalid;
-
-			if (!(elf_hwcap & HWCAP_SVE))
+			if (!system_supports_sve())
 				goto invalid;
 
 			if (user->sve)
@@ -481,8 +478,7 @@ static int restore_sigframe(struct pt_regs *regs,
 			return -EINVAL;
 
 		if (user.sve) {
-			if (!IS_ENABLED(CONFIG_ARM64_SVE) ||
-			    !(elf_hwcap & HWCAP_SVE))
+			if (!system_supports_sve())
 				return -EINVAL;
 
 			err = restore_sve_fpsimd_context(&user);
@@ -547,14 +543,14 @@ static int setup_sigframe_layout(struct rt_sigframe_user_layout *user)
 			return err;
 	}
 
-	if (IS_ENABLED(CONFIG_ARM64_SVE) && test_thread_flag(TIF_SVE)) {
+	if (system_supports_sve() && test_thread_flag(TIF_SVE)) {
 		unsigned int vl = current->thread.sve_vl;
 		unsigned int vq;
 
 		BUG_ON(!sve_vl_valid(vl));
 		vq = sve_vq_from_vl(vl);
 
-		BUG_ON(!(elf_hwcap & HWCAP_SVE));
+		BUG_ON(!system_supports_sve());
 
 		err = sigframe_alloc(user, &user->sve_offset,
 				     SVE_SIG_CONTEXT_SIZE(vq));
@@ -604,7 +600,7 @@ static int setup_sigframe(struct rt_sigframe_user_layout *user,
 	}
 
 	/* Scalable Vector Extension state, if present */
-	if (IS_ENABLED(CONFIG_ARM64_SVE) && err == 0 && user->sve_offset) {
+	if (system_supports_sve() && err == 0 && user->sve_offset) {
 		struct sve_context __user *sve_ctx =
 			apply_user_offset(user, user->sve_offset);
 		err |= preserve_sve_context(sve_ctx);
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [RFC PATCH v2 40/41] arm64/sve: Allocate task SVE context storage dynamically
  2017-03-22 14:50 ` Dave Martin
                   ` (39 preceding siblings ...)
  (?)
@ 2017-03-22 14:51 ` Dave Martin
  -1 siblings, 0 replies; 75+ messages in thread
From: Dave Martin @ 2017-03-22 14:51 UTC (permalink / raw)
  To: linux-arm-kernel

Currently, space is allocated at the end of task_struct to store a
task's SVE registers.

Because the size of task_struct is common to all tasks and must be
fixed early during boot, it is necessary to reserve space for the
maximum possible SVE state size for every task, irrespective of
which tasks use SVE or what vector length they are using.

The need to commit to a particular size for the SVE state early
during boot also makes it more difficult to deal sensibly with
systems where the maximum SVE vector length supported by the
hardware may differ between CPUs.

In order to address these issues, this patch allocates each task's
SVE register storage on demand from the kernel heap instead of
reserving space up-front in task_struct.  This means that there is
no need to allocate this storage for tasks that do not use SVE, and
no need to allocate more storage than a task needs for its
configured SVE vector length.

This has particular implications for:

fork/clone:

Immediately after task_struct is copied, the two tasks have the
same sve_state pointer, which would causes the tasks' SVE state to
alias, which would be bad.

To reslove this, the child task's sve_state is NULLed: this is not
a leak, because the parent still has its pointer.  The child's SVE
state will be allocated on first use, with zeroed contents.  This
is consistent with the effect of discarding SVE state (which is
already done for all syscalls).

exec:

Since exec starts the execution of a new binary, there's a fair
chance that SVE won't be used by the task subsequently.  Even if
the new task does use SVE, we want to ensure that its SVE register
contents start off zeroed.

These are achieved by freeing the task's sve_state (if any) at
exec.  If subsequently reused, the state will get reallocated,
filled with zeros.  Freeing the state at exec ensures that programs
that never use SVE will not have sve_state allocated for any of
their threads.

vector length change:

Whenever a task changes its vector length, sve_state is freed.  On
next use (by any mechanism) the state will then reallocated to the
appropriate new size.  This ensures correct sizing.  Enforcing this
here ensures that when sve_state is non-NULL then it is always the
correct size for the task's vector length.  This is widely assumed
elsewhere.

Strictly speaking, this behaviour is more destructive than the SVE
architecture specifies for the analogous situation of EL1 changing
its vector length by writing ZCR_EL1.LEN.  However, the task is
either making a prctl syscall here (in which case it is legitimate
to discard and/or zero the SVE state) or is being manipulated by a
debugger through ptrace.  In the latter case the debugger is
unlikely to benefit much from "architecturally authentic"
behaviour: the debugger can get the that effect by constructing the
new SVE register explicitly if needed.

This design avoids the kernel needing to contain code to convert
SVE registers from one vector length to another -- something for
which we have no other use at present.

ptrace, rt_sigreturn etc.:

Other interfaces that allow userspace to update or replace the SVE
registers, such as ptrace and rt_sigreturn, now allocate sve_state
for the task as needed, if it is not allocated beforehand.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
---
 arch/arm64/Kconfig                 |   1 -
 arch/arm64/include/asm/fpsimd.h    |  12 ++++
 arch/arm64/include/asm/processor.h |   1 +
 arch/arm64/kernel/fpsimd.c         | 112 ++++++++++++++++++++-----------------
 arch/arm64/kernel/process.c        |   4 ++
 arch/arm64/kernel/ptrace.c         |  15 ++---
 arch/arm64/kernel/setup.c          |   2 -
 arch/arm64/kernel/signal.c         |  12 ++--
 8 files changed, 88 insertions(+), 71 deletions(-)

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 593d2db..10295b6 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -23,7 +23,6 @@ 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 4a50139..24c4109 100644
--- a/arch/arm64/include/asm/fpsimd.h
+++ b/arch/arm64/include/asm/fpsimd.h
@@ -21,6 +21,8 @@
 
 #ifndef __ASSEMBLY__
 
+#include <linux/stddef.h>
+
 /*
  * FP/SIMD storage area has:
  *  - FPSR and FPCR
@@ -107,6 +109,12 @@ extern void *__sve_state(struct task_struct *task);
 
 extern int sve_max_vl;
 
+extern size_t sve_state_size(struct task_struct const *task);
+
+extern void sve_alloc(struct task_struct *task);
+extern void fpsimd_release_thread(struct task_struct *task);
+extern void fpsimd_dup_sve(struct task_struct *dst,
+			   struct task_struct const *src);
 extern void fpsimd_sync_to_sve(struct task_struct *task);
 extern void sve_sync_to_fpsimd(struct task_struct *task);
 extern void sve_sync_from_fpsimd_zeropad(struct task_struct *task);
@@ -122,6 +130,10 @@ extern void __init sve_setup(void);
 
 #else /* ! CONFIG_ARM64_SVE */
 
+static void __maybe_unused sve_alloc(struct task_struct *task) { }
+static void __maybe_unused fpsimd_release_thread(struct task_struct *task) { }
+static void __maybe_unused fpsimd_dup_sve(struct task_struct *dst,
+					  struct task_struct const *src) { }
 static void __maybe_unused sve_sync_to_fpsimd(struct task_struct *task) { }
 static void __maybe_unused sve_sync_from_fpsimd_zeropad(
 	struct task_struct *task) { }
diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h
index 424fa5d..9371680 100644
--- a/arch/arm64/include/asm/processor.h
+++ b/arch/arm64/include/asm/processor.h
@@ -84,6 +84,7 @@ struct thread_struct {
 	unsigned long		tp2_value;
 #endif
 	struct fpsimd_state	fpsimd_state;
+	void			*sve_state;	/* SVE registers, if any */
 	u16			sve_vl;		/* SVE vector length */
 	u16			sve_vl_onexec;	/* SVE vl after next exec */
 	u16			sve_flags;	/* SVE related flags */
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index 2b9def0..c2f4d59 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -107,36 +107,48 @@ int sve_max_vl = -1;
 /* Default VL for tasks that don't set it explicitly: */
 int sve_default_vl = -1;
 
-void *__sve_state(struct task_struct *task)
+size_t sve_state_size(struct task_struct const *task)
 {
-	return (char *)task + ALIGN(sizeof(*task), 16);
+	unsigned int vl = task->thread.sve_vl;
+
+	BUG_ON(!sve_vl_valid(vl));
+	return SVE_SIG_REGS_SIZE(sve_vq_from_vl(vl));
 }
 
-static void clear_sve_regs(struct task_struct *task)
+static void sve_free(struct task_struct *task)
 {
-	BUG_ON(task == current && preemptible());
+	kfree(task->thread.sve_state);
+	task->thread.sve_state = NULL;
+}
 
-	BUG_ON((char *)__sve_state(task) < (char *)task);
-	BUG_ON(arch_task_struct_size <
-	       ((char *)__sve_state(task) - (char *)task));
+void sve_alloc(struct task_struct *task)
+{
+	if (task->thread.sve_state)
+		return;
+
+	/* This is a small allocation (maximum ~8KB) and Should Not Fail. */
+	task->thread.sve_state =
+		kzalloc(sve_state_size(task), GFP_KERNEL);
 
-	memset(__sve_state(task), 0,
-	       arch_task_struct_size -
-			((char *)__sve_state(task) - (char *)task));
+	/*
+	 * If future SVE revisions can have larger vectors though,
+	 * this may cease to be true:
+	 */
+	BUG_ON(!task->thread.sve_state);
 }
 
 static void *sve_pffr(struct task_struct *task)
 {
 	unsigned int vl = task->thread.sve_vl;
 
-	BUG_ON(!sve_vl_valid(vl));
-	return (char *)__sve_state(task) +
+	BUG_ON(!sve_vl_valid(vl) || !task->thread.sve_state);
+	return (char *)task->thread.sve_state +
 		(SVE_SIG_FFR_OFFSET(sve_vq_from_vl(vl)) - SVE_SIG_REGS_OFFSET);
 }
 
 static void __fpsimd_to_sve(struct task_struct *task, unsigned int vq)
 {
-	struct sve_struct fpsimd_sve_state(vq) *sst = __sve_state(task);
+	struct sve_struct fpsimd_sve_state(vq) *sst = task->thread.sve_state;
 	struct fpsimd_state *fst = &task->thread.fpsimd_state;
 	unsigned int i;
 
@@ -157,7 +169,7 @@ static void fpsimd_to_sve(struct task_struct *task)
 
 static void __sve_to_fpsimd(struct task_struct *task, unsigned int vq)
 {
-	struct sve_struct fpsimd_sve_state(vq) *sst = __sve_state(task);
+	struct sve_struct fpsimd_sve_state(vq) *sst = task->thread.sve_state;
 	struct fpsimd_state *fst = &task->thread.fpsimd_state;
 	unsigned int i;
 
@@ -191,7 +203,7 @@ void sve_sync_to_fpsimd(struct task_struct *task)
 static void __sve_sync_from_fpsimd_zeropad(struct task_struct *task,
 					   unsigned int vq)
 {
-	struct sve_struct fpsimd_sve_state(vq) *sst = __sve_state(task);
+	struct sve_struct fpsimd_sve_state(vq) *sst = task->thread.sve_state;
 	struct fpsimd_state *fst = &task->thread.fpsimd_state;
 	unsigned int i;
 
@@ -221,6 +233,7 @@ void do_sve_acc(unsigned int esr, struct pt_regs *regs)
 
 	task_fpsimd_save(current);
 
+	sve_alloc(current);
 	fpsimd_to_sve(current);
 	if (test_and_set_thread_flag(TIF_SVE))
 		BUG(); /* We shouldn't trap if SVE was already enabled! */
@@ -228,6 +241,28 @@ void do_sve_acc(unsigned int esr, struct pt_regs *regs)
 	task_fpsimd_load(current);
 }
 
+/*
+ * Handle SVE state across fork():
+ *
+ * dst and src must not end up with aliases of the same sve_state.
+ * Because a task cannot fork except in a syscall, we can discard SVE
+ * state for dst here: reallocation will be deferred until dst tries
+ * to use SVE.
+ */
+void fpsimd_dup_sve(struct task_struct *dst, struct task_struct const *src)
+{
+	BUG_ON(task_pt_regs(dst)->syscallno == ~0UL);
+
+	preempt_disable(); /* unnecessary? */
+
+	if (test_and_clear_tsk_thread_flag(dst, TIF_SVE)) {
+		sve_to_fpsimd(dst);
+		dst->thread.sve_state = NULL;
+	}
+
+	preempt_enable();
+}
+
 int sve_set_vector_length(struct task_struct *task,
 			  unsigned long vl, unsigned long flags)
 {
@@ -279,11 +314,10 @@ int sve_set_vector_length(struct task_struct *task,
 			sve_to_fpsimd(task);
 
 		/*
-		 * To avoid surprises, also zero out the SVE regs storage.
-		 * This means that the P-regs, FFR and high bits of Z-regs
-		 * will read as zero on next access:
+		 * Force reallocation of task SVE state to the correct size
+		 * on next use:
 		 */
-		clear_sve_regs(task);
+		sve_free(task);
 	}
 
 	task->thread.sve_vl = vl;
@@ -499,12 +533,17 @@ static int __init sve_procfs_init(void)
 static int __init sve_procfs_init(void) { return 0; }
 #endif /* ! CONFIG_PROC_FS && CONFIG_ARM64_SVE */
 
+void fpsimd_release_thread(struct task_struct *dead_task)
+{
+	sve_free(dead_task);
+}
+
 #else /* ! CONFIG_ARM64_SVE */
 
 /* Dummy declarations for usage protected with IS_ENABLED(CONFIG_ARM64_SVE): */
 extern int sve_max_vl;
 extern int sve_default_vl;
-extern void clear_sve_regs(struct task_struct *task);
+extern void sve_free(struct task_struct *task);
 extern void *sve_pffr(struct task_struct *task);
 extern void fpsimd_to_sve(struct task_struct *task);
 extern int __init sve_procfs_init(void);
@@ -651,7 +690,8 @@ void fpsimd_flush_thread(void)
 	memset(&current->thread.fpsimd_state, 0, sizeof(struct fpsimd_state));
 
 	if (system_supports_sve()) {
-		clear_sve_regs(current);
+		clear_thread_flag(TIF_SVE);
+		sve_free(current);
 
 		current->thread.sve_vl = current->thread.sve_vl_onexec ?
 			current->thread.sve_vl_onexec : sve_default_vl;
@@ -871,36 +911,6 @@ static inline void fpsimd_hotplug_init(void)
 static inline void fpsimd_hotplug_init(void) { }
 #endif
 
-void __init fpsimd_init_task_struct_size(void)
-{
-	unsigned int vq;
-
-	arch_task_struct_size = sizeof(struct task_struct);
-
-	if (IS_ENABLED(CONFIG_ARM64_SVE) &&
-	    ((read_cpuid(ID_AA64PFR0_EL1) >> ID_AA64PFR0_SVE_SHIFT)
-	     & 0xf) == 1) {
-		/* FIXME: This should be the minimum across all CPUs */
-		sve_max_vl = sve_get_vl();
-		sve_default_vl = sve_max_vl;
-
-		/*
-		 * To avoid enlarging the signal frame by default, clamp to
-		 * 512 bits until/unless overridden by userspace:
-		 */
-		if (sve_default_vl > 512 / 8)
-			sve_default_vl = 512 / 8;
-
-		BUG_ON(!sve_vl_valid(sve_max_vl));
-		vq = sve_vq_from_vl(sve_max_vl);
-
-		arch_task_struct_size = ALIGN(sizeof(struct task_struct), 16) +
-			ALIGN(SVE_SIG_REGS_SIZE(vq), 16);
-		pr_info("SVE: enabled with maximum %u bits per vector\n",
-			sve_max_vl * 8);
-	}
-}
-
 /*
  * FP/SIMD support code initialisation.
  */
diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c
index 717dd0f..01c51fd 100644
--- a/arch/arm64/kernel/process.c
+++ b/arch/arm64/kernel/process.c
@@ -240,6 +240,7 @@ void flush_thread(void)
 
 void release_thread(struct task_struct *dead_task)
 {
+	fpsimd_release_thread(dead_task);
 }
 
 int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
@@ -247,6 +248,9 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
 	if (current->mm)
 		fpsimd_preserve_current_state();
 	memcpy(dst, src, arch_task_struct_size);
+
+	fpsimd_dup_sve(dst, src);
+
 	return 0;
 }
 
diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
index bbb8e38..a290352 100644
--- a/arch/arm64/kernel/ptrace.c
+++ b/arch/arm64/kernel/ptrace.c
@@ -782,13 +782,10 @@ static int sve_get(struct task_struct *target,
 	start = SVE_PT_SVE_OFFSET;
 	end = SVE_PT_SVE_FFR_OFFSET(vq) + SVE_PT_SVE_FFR_SIZE(vq);
 
-	BUG_ON((char *)__sve_state(target) < (char *)target);
 	BUG_ON(end < start);
-	BUG_ON(arch_task_struct_size < end - start);
-	BUG_ON((char *)__sve_state(target) - (char *)target >
-	       arch_task_struct_size - (end - start));
+	BUG_ON(end - start > sve_state_size(target));
 	ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
-				  __sve_state(target),
+				  target->thread.sve_state,
 				  start, end);
 	if (ret)
 		return ret;
@@ -875,6 +872,7 @@ static int sve_set(struct task_struct *target,
 
 	/* Otherwise: full SVE case */
 
+	sve_alloc(target);
 	fpsimd_sync_to_sve(target);
 	set_tsk_thread_flag(target, TIF_SVE);
 
@@ -883,13 +881,10 @@ static int sve_set(struct task_struct *target,
 	start = SVE_PT_SVE_OFFSET;
 	end = SVE_PT_SVE_FFR_OFFSET(vq) + SVE_PT_SVE_FFR_SIZE(vq);
 
-	BUG_ON((char *)__sve_state(target) < (char *)target);
 	BUG_ON(end < start);
-	BUG_ON(arch_task_struct_size < end - start);
-	BUG_ON((char *)__sve_state(target) - (char *)target >
-	       arch_task_struct_size - (end - start));
+	BUG_ON(end - start > sve_state_size(target));
 	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
-				 __sve_state(target),
+				 target->thread.sve_state,
 				 start, end);
 	if (ret)
 		goto out;
diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c
index 1412a35..a9e052e 100644
--- a/arch/arm64/kernel/setup.c
+++ b/arch/arm64/kernel/setup.c
@@ -237,8 +237,6 @@ void __init setup_arch(char **cmdline_p)
 
 	sprintf(init_utsname()->machine, UTS_MACHINE);
 
-	fpsimd_init_task_struct_size();
-
 	init_mm.start_code = (unsigned long) _text;
 	init_mm.end_code   = (unsigned long) _etext;
 	init_mm.end_data   = (unsigned long) _edata;
diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c
index e3810e2..1c94b3e 100644
--- a/arch/arm64/kernel/signal.c
+++ b/arch/arm64/kernel/signal.c
@@ -241,8 +241,9 @@ static int preserve_sve_context(struct sve_context __user *ctx)
 	 * This assumes that the SVE state has already been saved to
 	 * the task struct by calling preserve_fpsimd_context().
 	 */
+	BUG_ON(SVE_SIG_REGS_SIZE(vq) != sve_state_size(current));
 	err |= copy_to_user((char __user *)ctx + SVE_SIG_REGS_OFFSET,
-			    __sve_state(current),
+			    current->thread.sve_state,
 			    SVE_SIG_REGS_SIZE(vq));
 
 	return err ? -EFAULT : 0;
@@ -252,8 +253,7 @@ static int __restore_sve_fpsimd_context(struct user_ctxs *user,
 					unsigned int vl, unsigned int vq)
 {
 	int err;
-	struct fpsimd_sve_state(vq) *task_sve_regs =
-		__sve_state(current);
+	struct fpsimd_sve_state(vq) *task_sve_regs = current->thread.sve_state;
 	struct fpsimd_state fpsimd;
 
 	if (vl != current->thread.sve_vl)
@@ -264,10 +264,8 @@ static int __restore_sve_fpsimd_context(struct user_ctxs *user,
 	set_thread_flag(TIF_FOREIGN_FPSTATE);
 	barrier();
 
-	BUG_ON(SVE_SIG_REGS_SIZE(vq) > sizeof(*task_sve_regs));
-	BUG_ON(round_up(SVE_SIG_REGS_SIZE(vq), 16) < sizeof(*task_sve_regs));
-	BUG_ON(SVE_SIG_FFR_OFFSET(vq) - SVE_SIG_REGS_OFFSET !=
-	       (char *)&task_sve_regs->ffr - (char *)task_sve_regs);
+	sve_alloc(current);
+	BUG_ON(SVE_SIG_REGS_SIZE(vq) != sve_state_size(current));
 	err = __copy_from_user(task_sve_regs,
 			       (char __user const *)user->sve +
 					SVE_SIG_REGS_OFFSET,
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [RFC PATCH v2 41/41] arm64/sve: Documentation: Add overview of the SVE userspace ABI
  2017-03-22 14:50 ` Dave Martin
@ 2017-03-22 14:51   ` Dave Martin
  -1 siblings, 0 replies; 75+ messages in thread
From: Dave Martin @ 2017-03-22 14:51 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Will Deacon, Catalin Marinas, Marc Zyngier, Ard Biesheuvel,
	Florian Weimer, Joseph Myers, Szabolcs Nagy, Andrew Morton,
	linux-kernel, Alan Hayward, Yao Qi, gdb, Christoffer Dall,
	libc-alpha, Richard Sandiford, Torvald Riegel

This patch adds initial documentation of the ABI provided by the
kernel to enable userspace software to make use of SVE.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
---
 Documentation/arm64/sve.txt | 475 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 475 insertions(+)
 create mode 100644 Documentation/arm64/sve.txt

diff --git a/Documentation/arm64/sve.txt b/Documentation/arm64/sve.txt
new file mode 100644
index 0000000..f82fbf8
--- /dev/null
+++ b/Documentation/arm64/sve.txt
@@ -0,0 +1,475 @@
+            Scalable Vector Extension support for AArch64 Linux
+            ===================================================
+
+Author: Dave Martin <Dave.Martin@arm.com>
+Date:   20 March 2017
+
+This document outlines briefly the interface provided to userspace by Linux in
+order to support use of the ARM Scalable Vector Extension (SVE).
+
+This is an outline of the most important features and issues only and not
+intended to be exhaustive.
+
+This document does not aim to describe the SVE architecture or programmer's
+model.  To aid understanding, a minimal description of relevant programmer's
+model features for SVE is included in Appendix A.
+
+
+1.  General
+-----------
+
+* SVE registers Z0..Z31, P0..P15 and FFR and the current vector length VL, are
+  tracked per-thread.
+
+* The presence of SVE is reported to userspace via HWCAP_SVE in the aux vector
+  AT_HWCAP entry.  SVE is reported in /proc/cpuinfo as "sve".
+
+
+2.  Vector length terminology
+-----------------------------
+
+The size of an SVE vector (Z) register is referred to as the "vector length".
+
+To avoid confusion about the units used to express vector length, the kernel
+adopts the following conventions:
+
+* Vector length (VL) = size of a Z-register in bytes
+
+* Vector quadwords (VQ) = size of a Z-register in units of 128 bits
+
+(So, VL = 16 * VQ.)
+
+The VQ convention is used where the underlying granularity is important, such
+as in data structure definitions.  In most other situations, the VL convention
+is used.  This is consistent with the meaning of the "VL" pseudo-register in
+the SVE instruction set architecture.
+
+
+3.  System call behaviour
+-------------------------
+
+* On syscall, V0..V31 are preserved (as without SVE).  Thus, bits [127:0] of
+  Z0..Z31 are preserved.  All other bits of Z0..Z31, and all of P0..P15 and FFR
+  become unspecified on return from a syscall.
+
+* The SVE registers are not used to pass arguments to or receive results from
+  any syscall.
+
+* In practice the affected registers/bits will be preserved or will be replaced
+  with zeros on return from a syscall, but userspace should not make
+  assumptions about this.  The kernel behaviour may vary on a case-by-case
+  basis.
+
+
+4.  Signal handling
+-------------------
+
+* A new signal frame record sve_context encodes the SVE registers on signal
+  delivery. [1]
+
+* This record is supplementary to fpsimd_context.  The FPSR and FPCR registers
+  are only present in fpsimd_context.  For convenience, the content of V0..V31
+  is duplicated between sve_context and fpsimd_context.
+
+* The sve_context record is included if and only if the SVE registers are live
+  at the time of signal delivery.
+
+If the sve_context record is present in the signal frame:
+
+* sve_context.vl encodes the current vector length of the thread.
+
+* The remainder of the data has a vl-dependent size and layout.  Macros
+  SIG_SVE_* are defined [1] to facilitate access to the members.
+
+* If the SVE context is too big to fit in sigcontext.__reserved[], then extra
+  space is allocated on the stack, an extra_context record is written in
+  __reserved[] referencing this space.  sve_context is then written in the
+  extra space.  Refer to [1] for further details about this mechanism.
+
+
+5.  Signal return
+-----------------
+
+When returning from a signal handler:
+
+* If there is no sve_context record in the signal frame, the SVE registers/bits
+  become non-live and unspecified.  (In practice, this is likely to mean that
+  these bits become zero, but software should not make assumptions about this.)
+
+* If sve_context is present in the signal frame, the SVE registers become live
+  and are populated appropriately.  However, for backward compatibility
+  reasons, bits [127:0] of Z0..Z31 are always restored from the corresponding
+  members of fpsimd_context.vregs[] and not from sve_context.  The remaining
+  bits are restored from sve_context.
+
+* Inclusion of fpsimd_context in the signal frame remains mandatory,
+  irrespective of whether sve_context is present or not.
+
+* The vector length cannot be changed via signal return.  If sve_context.vl in
+  the signal frame does not match the current vector length, the signal return
+  attempt is treated as illegal, resulting in a forced SIGSEGV.
+
+
+6.  prctl extensions
+--------------------
+
+Some new prctl() calls are added to allow programs to manage the SVE vector
+length:
+
+prctl(PR_SVE_SET_VL, unsigned long vl, unsigned long flags)
+
+    Sets the vector length of the calling thread.
+
+    flags:
+
+	PR_SVE_SET_VL_THREAD
+
+	    Permit setting even if the calling process has multiple threads.
+	    This is otherwise forbidden in order to prevent accidents.
+
+	    Worker threads with different vector lengths can be created in this
+	    way, within a single process.
+
+	    General-purpose userspace code may not work correctly unless all
+	    threads have the same vector length.
+
+	PR_SVE_SET_VL_INHERIT
+
+	    Inherit the current vector length across execve().  Otherwise, the
+	    vector length is reset to the system default at execve().  (See
+	    Section 9.)
+
+	PR_SVE_SET_VL_ONEXEC
+
+	    Defer the requested vector length change until the next execve().
+	    This allows launching of a new program with a different vector
+	    length, while avoiding runtime side effects in the caller.
+
+	    This also overrides the effect of PR_SVE_SET_VL_INHERIT for the
+	    first execve().
+
+	    Without PR_SVE_SET_VL_ONEXEC, any outstanding deferred vector
+	    length change is cancelled.
+
+    Return value: a nonnegative on success, or a negative value on error:
+	EINVAL: SVE not supported, invalid vector length requested, or
+	    invalid flags.
+
+    The returned value describes the resulting configuration, encoded as for
+    PR_SVE_GET_VL.
+
+    Changing the vector length causes all of P0..P15, FFR and all bits of
+    Z0..V31 except for Z0 bits [127:0] .. Z31 bits [127:0] to become
+    unspecified.  Calling PR_SVE_SET_VL with vl equal to the thread's current
+    vector length does not constitute a change to the vector length for this
+    purpose.
+
+    If vl is greater than the maximum vector length supported by the system,
+    the vector length is set to the maximum supported vector length.
+
+
+prctl(PR_SVE_GET_VL)
+
+    Gets the vector length of the calling thread.
+
+    The following flag may be OR-ed into the result:
+
+	PR_SVE_SET_VL_INHERIT
+
+	    Vector length will be inherited across execve().
+
+    There is no way to determine whether there is an outstanding deferred
+    vector length change (which would only normally be the case between a
+    fork() or vfork() and the corresponding execve() in typical use).
+
+    To extract the vector length from the result, use PR_SVE_GET_VL_LEN().
+
+    Return value: a nonnegative value on success, or a negative value on error:
+	EINVAL: SVE not supported.
+
+
+prctl(PR_GET_MINSIGSTKSZ)
+
+    Returns the minimum amount of stack space in bytes required for guaranteed
+    signal delivery.
+
+    The returned value is analogous to the POSIX macro MINSIGSTKSZ, except that
+    expansion of the signal frame is taken into account.  This allows correct
+    allocation of stacks even for large vector lengths.
+
+    Return value: a nonnegative value on success, or a negative value on error:
+	EINVAL: Function not implemented.
+
+    If this call fails, the value provided for MINSIGSTKSZ by [1] can be
+    assumed.
+
+
+7.  ptrace extensions
+---------------------
+
+* A new regset NT_ARM_SVE is defined for use with PTRACE_GETREGSET and
+  PTRACE_SETREGSET.
+
+  Refer to [2] for definitions.
+
+The regset data starts with struct user_sve_header, containing:
+
+    size
+
+	Size of the complete regset, in bytes.
+	This depends on vl and possibly on other things in the future.
+
+	If a call to PTRACE_GETREGSET requests less data than the value of
+	size, the caller can allocate a larger buffer and retry in order to
+	read the complete regset.
+
+    max_size
+
+	Maximum size in bytes that the regset can grow to for the target
+	thread.  The regset won't grow bigger than this even if the target
+	thread changes its vector length etc.
+
+    vl
+
+	Target thread's current vector length, in bytes.
+
+    max_vl
+
+	Maximum possible vector length for the target thread.
+
+    flags
+
+	either
+
+	    SVE_PT_REGS_FPSIMD
+
+		SVE registers are not live (GETREGSET) or are to be made
+		non-live (SETREGSET).
+
+		The payload is of type struct user_fpsimd_state, with the same
+		meaning as for NT_PRFPREG, starting at offset
+		SVE_PT_FPSIMD_OFFSET from the start of user_sve_header.
+
+		Extra data might be appended in the future: the size of the
+		payload should be obtained using SVE_PT_FPSIMD_SIZE(vq, flags).
+
+		vq should be obtained using sve_vq_from_vl(vl).
+
+		or
+
+	    SVE_PT_REGS_SVE
+
+		SVE registers are live (GETREGSET) or are to be made live
+		(SETREGSET).
+
+		The payload contains the SVE register data, starting at offset
+		SVE_PT_SVE_OFFSET from the start of user_sve_header, and with
+		size SVE_PT_SVE_SIZE(vq, flags);
+
+	... OR-ed with zero or more of the following flags, which have the same
+	meaning and behaviour as the corresponding PR_SET_VL_* flags:
+
+	    SVE_PT_VL_THREAD (SETREGSET only)
+
+	    SVE_PT_VL_INHERIT
+
+	    SVE_PT_VL_ONEXEC (SETREGSET only).
+
+* The effects of changing the vector length and/or flags are equivalent to
+  those documented for PR_SVE_SET_VL.
+
+* In the SVE_PT_REGS_SVE case, the size and layout of the payload depends on
+  the header fields.  The SVE_PT_SVE_*() macros are provided to facilitate
+  access to the members.
+
+* In either case, for SETREGSET it is permissible to omit the payload, in which
+  case only the vector length and flags are changed (along with any
+  consequences of those changes).
+
+  The effect of writing a partial, incomplete payload is unspecified.
+
+
+8.  ELF coredump extensions
+---------------------------
+
+* A NT_ARM_SVE note will be added to each coredump for each thread of the
+  dumped process.  The contents will be equivalent to the data that would have
+  been read if a PTRACE_GETREGSET of NT_ARM_SVE were executed for each thread
+  when the coredump was generated.
+
+  Each of these notes may be padded up to a larger size: if so, the surplus
+  data should be ignored when parsing the coredump.
+
+
+9.  System runtime configuration
+--------------------------------
+
+* To mitigate the ABI impact of expansion of the signal frame, a policy
+  mechanism is provided for administrators, distro maintainers and developers
+  to set the default vector length for userspace processes:
+
+/proc/cpu/sve_default_vector_length
+
+    Writing the text representation of an integer to this file sets the system
+    default vector length to the specified value, unless the value is greater
+    than the maximum vector length supported by the system in which case the
+    default vector length is set to that maximum.
+
+    The result can be determined by reopening the file and reading its
+    contents.
+
+    At boot, the default vector length is initially set to 64 or the maximum
+    supported vector length, whichever is smaller.  This determines the initial
+    vector length of the init process (PID 1).
+
+    Reading this file returns the current system default vector length.
+
+* At every execve() call, the new vector length of the new process is set to
+  the system default vector length, unless
+
+    * PR_SVE_SET_VL_INHERIT (or equivalently SVE_PT_VL_INHERIT) is set for the
+      calling thread, or
+
+    * a deferred vector length change is pending, established via the
+      PR_SVE_SET_VL_ONEXEC flag (or SVE_PT_VL_ONEXEC).
+
+* Modifying the system default vector length does not affect the vector length
+  of any existing process or thread that does not make an execve() call.
+
+
+Appendix A.  SVE programmer's model (informative)
+=================================================
+
+This section provides a minimal description of the additions made by SVE to the
+ARMv8-A programmer's model that are relevant to this document.
+
+Note: This section is for information only and not intended to be complete or
+to replace any architectural specification.
+
+A.1.  Registers
+---------------
+
+In A64 state, SVE adds the following:
+
+* 32 8VL-bit vector registers Z0..Z31
+  For each Zn, Zn bits [127:0] alias the ARMv8-A vector register Vn.
+
+  A register write using a Vn register name zeros all bits of the corresponding
+  Zn except for bits [127:0].
+
+* 16 VL-bit predicate registers P0..P15
+
+* 1 VL-bit special-purpose predicate register FFR (the "first-fault register")
+
+* a VL "pseudo-register" that determines the size of each vector register
+
+  The SVE instruction set architecture provides no way to write VL directly.
+  Instead, it can be modified only by EL1 and above, by writing appropriate
+  system registers.
+
+* The value of VL can be configured at runtime by EL1 and above:
+  16 <= VL <= VLmax, where VL must be a multiple of 16.
+
+* The maximum vector length is determined by the hardware:
+  16 <= VLmax <= 256.
+
+  (The SVE architecture specifies 256, but permits future architecture
+  revisions to raise this limit.)
+
+* FPSR and FPCR are retained from ARMv8-A, and interact with SVE floating-point
+  operations in a similar way to the way in which they interact with ARMv8
+  floating-point operations.
+
+         8VL-1                       128               0  bit index
+        +----          ////            -----------------+
+     Z0 |                               :       V0      |
+      :                                          :
+     Z7 |                               :       V7      |
+     Z8 |                               :     * V8      |
+      :                                       :  :
+    Z15 |                               :     *V15      |
+    Z16 |                               :      V16      |
+      :                                          :
+    Z31 |                               :      V31      |
+        +----          ////            -----------------+
+                                                 31    0
+         VL-1                  0                +-------+
+        +----       ////      --+          FPSR |       |
+     P0 |                       |               +-------+
+      : |                       |         *FPCR |       |
+    P15 |                       |               +-------+
+        +----       ////      --+
+    FFR |                       |               +-----+
+        +----       ////      --+            VL |     |
+                                                +-----+
+
+(*) callee-save:
+    This only applies to bits [63:0] of Z-/V-registers.
+    FPCR contains callee-save and caller-save bits.  See [3] for details.
+
+
+A.2.  Procedure call standard
+-----------------------------
+
+The ARMv8-A base procedure call standard is extended as follows with respect to
+the additional SVE register state:
+
+* All SVE register bits that are not shared with FP/SIMD are caller-save.
+
+* Z8 bits [63:0] .. Z15 bits [63:0] are callee-save.
+
+  This follows from the way these bits are mapped to V8..V15, which are caller-
+  save in the base procedure call standard.
+
+
+Appendix B.  ARMv8-A FP/SIMD programmer's model
+===============================================
+
+Note: This section is for information only and not intended to be complete or
+to replace any architectural specification.
+
+Refer to [3] for for more information.
+
+ARMv8-A defines the following floating-point / SIMD register state:
+
+* 32 128-bit vector registers V0..V31
+* 2 32-bit status/control registers FPSR, FPCR
+
+         127           0  bit index
+        +---------------+
+     V0 |               |
+      : :               :
+     V7 |               |
+   * V8 |               |
+   :  : :               :
+   *V15 |               |
+    V16 |               |
+      : :               :
+    V31 |               |
+        +---------------+
+
+                 31    0
+                +-------+
+           FPSR |       |
+                +-------+
+          *FPCR |       |
+                +-------+
+
+(*) callee-save:
+    This only applies to bits [63:0] of V-registers.
+    FPCR contains a mixture of callee-save and caller-save bits.
+
+
+References
+==========
+
+[1] arch/arm64/include/uapi/asm/sigcontext.h
+    AArch64 Linux signal ABI definitions
+
+[2] arch/arm64/include/uapi/asm/ptrace.h
+    AArch64 Linux ptrace ABI definitions
+
+[3] ARM IHI0055C
+    http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055c/IHI0055C_beta_aapcs64.pdf
+    http://infocenter.arm.com/help/topic/com.arm.doc.subset.swdev.abi/index.html
+    Procedure Call Standard for the ARM 64-bit Architecture (AArch64)
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 75+ messages in thread

* [RFC PATCH v2 41/41] arm64/sve: Documentation: Add overview of the SVE userspace ABI
@ 2017-03-22 14:51   ` Dave Martin
  0 siblings, 0 replies; 75+ messages in thread
From: Dave Martin @ 2017-03-22 14:51 UTC (permalink / raw)
  To: linux-arm-kernel

This patch adds initial documentation of the ABI provided by the
kernel to enable userspace software to make use of SVE.

Signed-off-by: Dave Martin <Dave.Martin@arm.com>
---
 Documentation/arm64/sve.txt | 475 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 475 insertions(+)
 create mode 100644 Documentation/arm64/sve.txt

diff --git a/Documentation/arm64/sve.txt b/Documentation/arm64/sve.txt
new file mode 100644
index 0000000..f82fbf8
--- /dev/null
+++ b/Documentation/arm64/sve.txt
@@ -0,0 +1,475 @@
+            Scalable Vector Extension support for AArch64 Linux
+            ===================================================
+
+Author: Dave Martin <Dave.Martin@arm.com>
+Date:   20 March 2017
+
+This document outlines briefly the interface provided to userspace by Linux in
+order to support use of the ARM Scalable Vector Extension (SVE).
+
+This is an outline of the most important features and issues only and not
+intended to be exhaustive.
+
+This document does not aim to describe the SVE architecture or programmer's
+model.  To aid understanding, a minimal description of relevant programmer's
+model features for SVE is included in Appendix A.
+
+
+1.  General
+-----------
+
+* SVE registers Z0..Z31, P0..P15 and FFR and the current vector length VL, are
+  tracked per-thread.
+
+* The presence of SVE is reported to userspace via HWCAP_SVE in the aux vector
+  AT_HWCAP entry.  SVE is reported in /proc/cpuinfo as "sve".
+
+
+2.  Vector length terminology
+-----------------------------
+
+The size of an SVE vector (Z) register is referred to as the "vector length".
+
+To avoid confusion about the units used to express vector length, the kernel
+adopts the following conventions:
+
+* Vector length (VL) = size of a Z-register in bytes
+
+* Vector quadwords (VQ) = size of a Z-register in units of 128 bits
+
+(So, VL = 16 * VQ.)
+
+The VQ convention is used where the underlying granularity is important, such
+as in data structure definitions.  In most other situations, the VL convention
+is used.  This is consistent with the meaning of the "VL" pseudo-register in
+the SVE instruction set architecture.
+
+
+3.  System call behaviour
+-------------------------
+
+* On syscall, V0..V31 are preserved (as without SVE).  Thus, bits [127:0] of
+  Z0..Z31 are preserved.  All other bits of Z0..Z31, and all of P0..P15 and FFR
+  become unspecified on return from a syscall.
+
+* The SVE registers are not used to pass arguments to or receive results from
+  any syscall.
+
+* In practice the affected registers/bits will be preserved or will be replaced
+  with zeros on return from a syscall, but userspace should not make
+  assumptions about this.  The kernel behaviour may vary on a case-by-case
+  basis.
+
+
+4.  Signal handling
+-------------------
+
+* A new signal frame record sve_context encodes the SVE registers on signal
+  delivery. [1]
+
+* This record is supplementary to fpsimd_context.  The FPSR and FPCR registers
+  are only present in fpsimd_context.  For convenience, the content of V0..V31
+  is duplicated between sve_context and fpsimd_context.
+
+* The sve_context record is included if and only if the SVE registers are live
+  at the time of signal delivery.
+
+If the sve_context record is present in the signal frame:
+
+* sve_context.vl encodes the current vector length of the thread.
+
+* The remainder of the data has a vl-dependent size and layout.  Macros
+  SIG_SVE_* are defined [1] to facilitate access to the members.
+
+* If the SVE context is too big to fit in sigcontext.__reserved[], then extra
+  space is allocated on the stack, an extra_context record is written in
+  __reserved[] referencing this space.  sve_context is then written in the
+  extra space.  Refer to [1] for further details about this mechanism.
+
+
+5.  Signal return
+-----------------
+
+When returning from a signal handler:
+
+* If there is no sve_context record in the signal frame, the SVE registers/bits
+  become non-live and unspecified.  (In practice, this is likely to mean that
+  these bits become zero, but software should not make assumptions about this.)
+
+* If sve_context is present in the signal frame, the SVE registers become live
+  and are populated appropriately.  However, for backward compatibility
+  reasons, bits [127:0] of Z0..Z31 are always restored from the corresponding
+  members of fpsimd_context.vregs[] and not from sve_context.  The remaining
+  bits are restored from sve_context.
+
+* Inclusion of fpsimd_context in the signal frame remains mandatory,
+  irrespective of whether sve_context is present or not.
+
+* The vector length cannot be changed via signal return.  If sve_context.vl in
+  the signal frame does not match the current vector length, the signal return
+  attempt is treated as illegal, resulting in a forced SIGSEGV.
+
+
+6.  prctl extensions
+--------------------
+
+Some new prctl() calls are added to allow programs to manage the SVE vector
+length:
+
+prctl(PR_SVE_SET_VL, unsigned long vl, unsigned long flags)
+
+    Sets the vector length of the calling thread.
+
+    flags:
+
+	PR_SVE_SET_VL_THREAD
+
+	    Permit setting even if the calling process has multiple threads.
+	    This is otherwise forbidden in order to prevent accidents.
+
+	    Worker threads with different vector lengths can be created in this
+	    way, within a single process.
+
+	    General-purpose userspace code may not work correctly unless all
+	    threads have the same vector length.
+
+	PR_SVE_SET_VL_INHERIT
+
+	    Inherit the current vector length across execve().  Otherwise, the
+	    vector length is reset to the system default at execve().  (See
+	    Section 9.)
+
+	PR_SVE_SET_VL_ONEXEC
+
+	    Defer the requested vector length change until the next execve().
+	    This allows launching of a new program with a different vector
+	    length, while avoiding runtime side effects in the caller.
+
+	    This also overrides the effect of PR_SVE_SET_VL_INHERIT for the
+	    first execve().
+
+	    Without PR_SVE_SET_VL_ONEXEC, any outstanding deferred vector
+	    length change is cancelled.
+
+    Return value: a nonnegative on success, or a negative value on error:
+	EINVAL: SVE not supported, invalid vector length requested, or
+	    invalid flags.
+
+    The returned value describes the resulting configuration, encoded as for
+    PR_SVE_GET_VL.
+
+    Changing the vector length causes all of P0..P15, FFR and all bits of
+    Z0..V31 except for Z0 bits [127:0] .. Z31 bits [127:0] to become
+    unspecified.  Calling PR_SVE_SET_VL with vl equal to the thread's current
+    vector length does not constitute a change to the vector length for this
+    purpose.
+
+    If vl is greater than the maximum vector length supported by the system,
+    the vector length is set to the maximum supported vector length.
+
+
+prctl(PR_SVE_GET_VL)
+
+    Gets the vector length of the calling thread.
+
+    The following flag may be OR-ed into the result:
+
+	PR_SVE_SET_VL_INHERIT
+
+	    Vector length will be inherited across execve().
+
+    There is no way to determine whether there is an outstanding deferred
+    vector length change (which would only normally be the case between a
+    fork() or vfork() and the corresponding execve() in typical use).
+
+    To extract the vector length from the result, use PR_SVE_GET_VL_LEN().
+
+    Return value: a nonnegative value on success, or a negative value on error:
+	EINVAL: SVE not supported.
+
+
+prctl(PR_GET_MINSIGSTKSZ)
+
+    Returns the minimum amount of stack space in bytes required for guaranteed
+    signal delivery.
+
+    The returned value is analogous to the POSIX macro MINSIGSTKSZ, except that
+    expansion of the signal frame is taken into account.  This allows correct
+    allocation of stacks even for large vector lengths.
+
+    Return value: a nonnegative value on success, or a negative value on error:
+	EINVAL: Function not implemented.
+
+    If this call fails, the value provided for MINSIGSTKSZ by [1] can be
+    assumed.
+
+
+7.  ptrace extensions
+---------------------
+
+* A new regset NT_ARM_SVE is defined for use with PTRACE_GETREGSET and
+  PTRACE_SETREGSET.
+
+  Refer to [2] for definitions.
+
+The regset data starts with struct user_sve_header, containing:
+
+    size
+
+	Size of the complete regset, in bytes.
+	This depends on vl and possibly on other things in the future.
+
+	If a call to PTRACE_GETREGSET requests less data than the value of
+	size, the caller can allocate a larger buffer and retry in order to
+	read the complete regset.
+
+    max_size
+
+	Maximum size in bytes that the regset can grow to for the target
+	thread.  The regset won't grow bigger than this even if the target
+	thread changes its vector length etc.
+
+    vl
+
+	Target thread's current vector length, in bytes.
+
+    max_vl
+
+	Maximum possible vector length for the target thread.
+
+    flags
+
+	either
+
+	    SVE_PT_REGS_FPSIMD
+
+		SVE registers are not live (GETREGSET) or are to be made
+		non-live (SETREGSET).
+
+		The payload is of type struct user_fpsimd_state, with the same
+		meaning as for NT_PRFPREG, starting at offset
+		SVE_PT_FPSIMD_OFFSET from the start of user_sve_header.
+
+		Extra data might be appended in the future: the size of the
+		payload should be obtained using SVE_PT_FPSIMD_SIZE(vq, flags).
+
+		vq should be obtained using sve_vq_from_vl(vl).
+
+		or
+
+	    SVE_PT_REGS_SVE
+
+		SVE registers are live (GETREGSET) or are to be made live
+		(SETREGSET).
+
+		The payload contains the SVE register data, starting at offset
+		SVE_PT_SVE_OFFSET from the start of user_sve_header, and with
+		size SVE_PT_SVE_SIZE(vq, flags);
+
+	... OR-ed with zero or more of the following flags, which have the same
+	meaning and behaviour as the corresponding PR_SET_VL_* flags:
+
+	    SVE_PT_VL_THREAD (SETREGSET only)
+
+	    SVE_PT_VL_INHERIT
+
+	    SVE_PT_VL_ONEXEC (SETREGSET only).
+
+* The effects of changing the vector length and/or flags are equivalent to
+  those documented for PR_SVE_SET_VL.
+
+* In the SVE_PT_REGS_SVE case, the size and layout of the payload depends on
+  the header fields.  The SVE_PT_SVE_*() macros are provided to facilitate
+  access to the members.
+
+* In either case, for SETREGSET it is permissible to omit the payload, in which
+  case only the vector length and flags are changed (along with any
+  consequences of those changes).
+
+  The effect of writing a partial, incomplete payload is unspecified.
+
+
+8.  ELF coredump extensions
+---------------------------
+
+* A NT_ARM_SVE note will be added to each coredump for each thread of the
+  dumped process.  The contents will be equivalent to the data that would have
+  been read if a PTRACE_GETREGSET of NT_ARM_SVE were executed for each thread
+  when the coredump was generated.
+
+  Each of these notes may be padded up to a larger size: if so, the surplus
+  data should be ignored when parsing the coredump.
+
+
+9.  System runtime configuration
+--------------------------------
+
+* To mitigate the ABI impact of expansion of the signal frame, a policy
+  mechanism is provided for administrators, distro maintainers and developers
+  to set the default vector length for userspace processes:
+
+/proc/cpu/sve_default_vector_length
+
+    Writing the text representation of an integer to this file sets the system
+    default vector length to the specified value, unless the value is greater
+    than the maximum vector length supported by the system in which case the
+    default vector length is set to that maximum.
+
+    The result can be determined by reopening the file and reading its
+    contents.
+
+    At boot, the default vector length is initially set to 64 or the maximum
+    supported vector length, whichever is smaller.  This determines the initial
+    vector length of the init process (PID 1).
+
+    Reading this file returns the current system default vector length.
+
+* At every execve() call, the new vector length of the new process is set to
+  the system default vector length, unless
+
+    * PR_SVE_SET_VL_INHERIT (or equivalently SVE_PT_VL_INHERIT) is set for the
+      calling thread, or
+
+    * a deferred vector length change is pending, established via the
+      PR_SVE_SET_VL_ONEXEC flag (or SVE_PT_VL_ONEXEC).
+
+* Modifying the system default vector length does not affect the vector length
+  of any existing process or thread that does not make an execve() call.
+
+
+Appendix A.  SVE programmer's model (informative)
+=================================================
+
+This section provides a minimal description of the additions made by SVE to the
+ARMv8-A programmer's model that are relevant to this document.
+
+Note: This section is for information only and not intended to be complete or
+to replace any architectural specification.
+
+A.1.  Registers
+---------------
+
+In A64 state, SVE adds the following:
+
+* 32 8VL-bit vector registers Z0..Z31
+  For each Zn, Zn bits [127:0] alias the ARMv8-A vector register Vn.
+
+  A register write using a Vn register name zeros all bits of the corresponding
+  Zn except for bits [127:0].
+
+* 16 VL-bit predicate registers P0..P15
+
+* 1 VL-bit special-purpose predicate register FFR (the "first-fault register")
+
+* a VL "pseudo-register" that determines the size of each vector register
+
+  The SVE instruction set architecture provides no way to write VL directly.
+  Instead, it can be modified only by EL1 and above, by writing appropriate
+  system registers.
+
+* The value of VL can be configured at runtime by EL1 and above:
+  16 <= VL <= VLmax, where VL must be a multiple of 16.
+
+* The maximum vector length is determined by the hardware:
+  16 <= VLmax <= 256.
+
+  (The SVE architecture specifies 256, but permits future architecture
+  revisions to raise this limit.)
+
+* FPSR and FPCR are retained from ARMv8-A, and interact with SVE floating-point
+  operations in a similar way to the way in which they interact with ARMv8
+  floating-point operations.
+
+         8VL-1                       128               0  bit index
+        +----          ////            -----------------+
+     Z0 |                               :       V0      |
+      :                                          :
+     Z7 |                               :       V7      |
+     Z8 |                               :     * V8      |
+      :                                       :  :
+    Z15 |                               :     *V15      |
+    Z16 |                               :      V16      |
+      :                                          :
+    Z31 |                               :      V31      |
+        +----          ////            -----------------+
+                                                 31    0
+         VL-1                  0                +-------+
+        +----       ////      --+          FPSR |       |
+     P0 |                       |               +-------+
+      : |                       |         *FPCR |       |
+    P15 |                       |               +-------+
+        +----       ////      --+
+    FFR |                       |               +-----+
+        +----       ////      --+            VL |     |
+                                                +-----+
+
+(*) callee-save:
+    This only applies to bits [63:0] of Z-/V-registers.
+    FPCR contains callee-save and caller-save bits.  See [3] for details.
+
+
+A.2.  Procedure call standard
+-----------------------------
+
+The ARMv8-A base procedure call standard is extended as follows with respect to
+the additional SVE register state:
+
+* All SVE register bits that are not shared with FP/SIMD are caller-save.
+
+* Z8 bits [63:0] .. Z15 bits [63:0] are callee-save.
+
+  This follows from the way these bits are mapped to V8..V15, which are caller-
+  save in the base procedure call standard.
+
+
+Appendix B.  ARMv8-A FP/SIMD programmer's model
+===============================================
+
+Note: This section is for information only and not intended to be complete or
+to replace any architectural specification.
+
+Refer to [3] for for more information.
+
+ARMv8-A defines the following floating-point / SIMD register state:
+
+* 32 128-bit vector registers V0..V31
+* 2 32-bit status/control registers FPSR, FPCR
+
+         127           0  bit index
+        +---------------+
+     V0 |               |
+      : :               :
+     V7 |               |
+   * V8 |               |
+   :  : :               :
+   *V15 |               |
+    V16 |               |
+      : :               :
+    V31 |               |
+        +---------------+
+
+                 31    0
+                +-------+
+           FPSR |       |
+                +-------+
+          *FPCR |       |
+                +-------+
+
+(*) callee-save:
+    This only applies to bits [63:0] of V-registers.
+    FPCR contains a mixture of callee-save and caller-save bits.
+
+
+References
+==========
+
+[1] arch/arm64/include/uapi/asm/sigcontext.h
+    AArch64 Linux signal ABI definitions
+
+[2] arch/arm64/include/uapi/asm/ptrace.h
+    AArch64 Linux ptrace ABI definitions
+
+[3] ARM IHI0055C
+    http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055c/IHI0055C_beta_aapcs64.pdf
+    http://infocenter.arm.com/help/topic/com.arm.doc.subset.swdev.abi/index.html
+    Procedure Call Standard for the ARM 64-bit Architecture (AArch64)
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 75+ 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 11/41] arm64/sve: Expand task_struct for Scalable Vector Extension state Dave Martin
@ 2017-03-22 16:20   ` Mark Rutland
  2017-03-23 10:49     ` Dave Martin
  0 siblings, 1 reply; 75+ messages in thread
From: Mark Rutland @ 2017-03-22 16:20 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Mar 22, 2017 at 02:50:41PM +0000, Dave Martin wrote:
> This patch expands task_struct to accommodate the Scalable Vector
> Extension state.
> 
> The extra space is not used for anything yet.

[...]

> +#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;
> +}

Can we mnemonicise the magic numbers for these?

That, and some comment regarding how the task_struct and sve state are
organised in memory, as that's painful to reverse-engineer.

> +
> +#else /* ! CONFIG_ARM64_SVE */
> +
> +/* Dummy declarations for usage protected with IS_ENABLED(CONFIG_ARM64_SVE): */
> +extern void *__sve_state(struct task_struct *task);
> +extern void *sve_pffr(struct task_struct *task);
> +
> +#endif /* ! CONFIG_ARM64_SVE */

The usual pattern is to make these static inlines, with a BUILD_BUG() if
calls are expected/required to be optimised away entirely.

Thanks,
Mark.

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [RFC PATCH v2 21/41] arm64/sve: Enable SVE on demand for userspace
  2017-03-22 14:50 ` [RFC PATCH v2 21/41] arm64/sve: Enable SVE on demand for userspace Dave Martin
@ 2017-03-22 16:48   ` Mark Rutland
  2017-03-23 11:24     ` Dave Martin
  0 siblings, 1 reply; 75+ messages in thread
From: Mark Rutland @ 2017-03-22 16:48 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On Wed, Mar 22, 2017 at 02:50:51PM +0000, Dave Martin wrote:
> This patch tracks whether a task has ever attempted to use the
> Scalable Vector Extension.  If and only if SVE is in use by a task,
> it will be enabled for userspace when scheduling the task in.  For
> other tasks, SVE is disabled when scheduling in.

>  #define TIF_SYSCALL_AUDIT	9
>  #define TIF_SYSCALL_TRACEPOINT	10
>  #define TIF_SECCOMP		11
> +#define TIF_SVE			17	/* Scalable Vector Extension in use */

Please don't skip ahead to bit 17. I see why you're doing that, but I
don't think that's a good idea. More on that below.

> +void do_sve_acc(unsigned int esr, struct pt_regs *regs)
> +{
> +	unsigned long tmp;
> +
> +	if (test_and_set_thread_flag(TIF_SVE))
> +		BUG();
> +
> +	asm ("mrs %0, cpacr_el1" : "=r" (tmp));
> +	asm volatile ("msr cpacr_el1, %0" :: "r" (tmp | (1 << 17)));

Please de-magic the number, e.g. with something like:

#define CPACR_SVE_EN	(1 << 17)

... in <asm/sysreg.h>.

Please also use {read,write}_sysreg(), e.g.

	val = read_sysreg(cpacr_el1);
	tmp |= CPACR_SVE_EN;
	write_sysreg(tmp, cpacr_el1);

[...]

> +		if (IS_ENABLED(CONFIG_ARM64_SVE)) {
> +			/*
> +			 * Flip SVE enable for userspace if it doesn't
> +			 * match the current_task.
> +			 */
> +			asm ("mrs %0, cpacr_el1" : "=r" (tmp));
> +			flags = current_thread_info()->flags;
> +			if ((tmp ^ (unsigned long)flags) & (1 << 17)) {
> +				tmp ^= 1 << 17;
> +				asm volatile ("msr cpacr_el1, %0" :: "r" (tmp));
> +			}

I think it's a bad idea to rely on the TIF flag and CPACR bit to have
the same index. It makes this painful to read, and it leaves us fragile
if the TIF bits are reorganised.

How about:

	unsigned long cpacr = read_sysreg(cpacr_el1);
	bool hw_enabled = !!(cpacr & CPACR_SVE_EN);
	bool sw_enabled = test_thread_flag(TIF_SVE);

	/*
	 * Flip SVE enable for userspace if it doesn't
	 * match the current_task.
	 */
	if (hw_enabled != sw_enabled) {
		cpacr ^= CPACR_SVE_EN;
		write_sysreg(cpacr, cpacr_el1);
	}

Thanks,
Mark.

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [RFC PATCH v2 23/41] arm64/sve: Move ZEN handling to the common task_fpsimd_load() path
  2017-03-22 14:50 ` [RFC PATCH v2 23/41] arm64/sve: Move ZEN handling to the common task_fpsimd_load() path Dave Martin
@ 2017-03-22 16:55   ` Mark Rutland
  2017-03-23 11:52     ` Dave Martin
  0 siblings, 1 reply; 75+ messages in thread
From: Mark Rutland @ 2017-03-22 16:55 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On Wed, Mar 22, 2017 at 02:50:53PM +0000, Dave Martin wrote:
>  void do_sve_acc(unsigned int esr, struct pt_regs *regs)
>  {
> -	unsigned long tmp;
> +	if (test_and_set_thread_flag(TIF_SVE)) {
> +		unsigned long tmp;
>  
> -	if (test_and_set_thread_flag(TIF_SVE))
> +		asm ("mrs %0, cpacr_el1" : "=r" (tmp));

Please use read_sysreg().

> +
> +		printk(KERN_INFO "%s: Strange, ZEN=%u\n",
> +		       __func__, (unsigned int)((tmp >> 16) & 3));
>  		BUG();

Given we're about to BUG(), I guess it would make more sense to use
pr_err() here, and be a bit more informative. e.g.

	pr_crit("SVE trap taken unexpectedly. CPACR_EL1.ZEN is %u\n",
		(unsigned int)((tmp >> 16) & 3));
	BUG();

... my usual comments w.r.t. magic numbers apply.

[...]

> +		BUILD_BUG_ON(_TIF_SVE != CPACR_EL1_ZEN_EL0EN);

As previously, I do not think this is a good idea. Treating these as
separate values is not difficult, and IMO far easier to reason about.

Thanks,
Mark.

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [RFC PATCH v2 24/41] arm64/sve: Discard SVE state on system call
  2017-03-22 14:50 ` [RFC PATCH v2 24/41] arm64/sve: Discard SVE state on system call Dave Martin
@ 2017-03-22 17:03   ` Mark Rutland
  2017-03-23 11:59     ` Dave Martin
  0 siblings, 1 reply; 75+ messages in thread
From: Mark Rutland @ 2017-03-22 17:03 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Mar 22, 2017 at 02:50:54PM +0000, Dave Martin wrote:
> The base procedure call standard for the Scalable Vector Extension
> defines all of the SVE programmer's model state (Z0-31, P0-15, FFR)
> as caller-save, except for that subset of the state that aliases
> FPSIMD state.
> 
> System calls from userspace will almost always be made through C
> library wrappers -- as a consequence of the PCS there will thus
> rarely if ever be any live SVE state at syscall entry in practice.
> 
> This gives us an opportinity to make SVE explicitly caller-save
> around SVC and so stop carrying around the SVE state for tasks that
> use SVE only occasionally (say, by calling a library).
> 
> Note that FPSIMD state will still be preserved around SVC.
> 
> As a crude heuristic to avoid pathological cases where a thread
> that uses SVE frequently has to fault back into the kernel again to
> re-enable SVE after a syscall, we switch the thread back to
> FPSIMD-only context tracking only if the context is actually
> switched out before returning to userspace.
> 
> Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> ---
>  arch/arm64/kernel/fpsimd.c | 17 +++++++++++++++++
>  1 file changed, 17 insertions(+)
> 
> diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
> index 5fb5585..8c18384 100644
> --- a/arch/arm64/kernel/fpsimd.c
> +++ b/arch/arm64/kernel/fpsimd.c
> @@ -250,6 +250,23 @@ static void task_fpsimd_save(struct task_struct *task)
>  	BUG_ON(task != current);
>  
>  	if (IS_ENABLED(CONFIG_ARM64_SVE) &&
> +	    task_pt_regs(task)->syscallno != ~0UL &&
> +	    test_tsk_thread_flag(task, TIF_SVE)) {
> +		unsigned long tmp;
> +
> +		clear_tsk_thread_flag(task, TIF_SVE);
> +
> +		/* Trap if the task tries to use SVE again: */
> +		asm volatile (
> +			"mrs	%[tmp], cpacr_el1\n\t"
> +			"bic	%[tmp], %[tmp], %[mask]\n\t"
> +			"msr	cpacr_el1, %[tmp]"
> +			: [tmp] "=r" (tmp)
> +			: [mask] "i" (CPACR_EL1_ZEN_EL0EN)
> +		);

Given we're poking this bit in a few places, I think it would make more
sense to add enable/disable helpers. Those can also subsume the lazy
writeback used for the context switch, e.g.

static inline void sve_el0_enable(void)
}
	unsigned long cpacr = read_sysreg(cpacr_el1);
	if ((cpacr & CPACR_EL1_ZEN_EL0EN)
		return;

	cpacr |= CPACR_EL1_ZEN_EL0EN;
	write_sysreg(cpacr, cpacr_el1);
}

static inline void sve_el0_disable(void)
{
	unsigned long cpacr = read_sysreg(cpacr_el1);
	if (!(cpacr & CPACR_EL1_ZEN_EL0EN)
		return;

	cpacr &= ~CPACR_EL1_ZEN_EL0EN;
	write_sysreg(cpacr, cpacr_el1);
}

Thanks,
Mark.

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [RFC PATCH v2 28/41] arm64: KVM: Treat SVE use by guests as undefined instruction execution
  2017-03-22 14:50 ` [RFC PATCH v2 28/41] arm64: KVM: Treat SVE use by guests as undefined instruction execution Dave Martin
@ 2017-03-22 17:06   ` Mark Rutland
  2017-03-23 12:10     ` Dave Martin
  0 siblings, 1 reply; 75+ messages in thread
From: Mark Rutland @ 2017-03-22 17:06 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

On Wed, Mar 22, 2017 at 02:50:58PM +0000, Dave Martin wrote:
> We don't currently support context-switching of Scalable Vector
> Extension context between vcpus, and the SVE access exception is
> thus left masked by default at EL2 when running a vcpu.
> 
> However, there's nothing to stop a guest trying to use SVE.  If it
> does, we'll get an SVE access exception to EL2 which will cause KVM
> to panic since this exception isn't yet recognised.
> 
> This patch adds knowledge to KVM about the SVE access exception,
> translating it into an undefined instruction exception injected to
> the vcpu.
> 
> This prevents a malicious guest from panicking the host by
> attempted SVE use.
> 
> SVE-enabled guests will still not work properly for now, but they
> won't take the host down.
> 
> Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> ---
>  arch/arm64/kvm/handle_exit.c | 8 ++++++++
>  1 file changed, 8 insertions(+)

As a heads-up, this is handled implicitly by kvm_handle_unknown_ec()
since commit ba4dd156eabdca93 ("arm64: KVM: Survive unknown traps from
guests"). That also logs a (ratelimited) warning regarding the
unimplemented trap handling.

Given that, I think we can drop this patch until actual support lands.

Thanks,
Mark.

> 
> diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c
> index fa1b18e..e43b147 100644
> --- a/arch/arm64/kvm/handle_exit.c
> +++ b/arch/arm64/kvm/handle_exit.c
> @@ -146,6 +146,13 @@ static int kvm_handle_unknown_ec(struct kvm_vcpu *vcpu, struct kvm_run *run)
>  	return 1;
>  }
>  
> +static int handle_sve(struct kvm_vcpu *vcpu, struct kvm_run *run)
> +{
> +	/* Until SVE is supported for guests: */
> +	kvm_inject_undefined(vcpu);
> +	return 1;
> +}
> +
>  static exit_handle_fn arm_exit_handlers[] = {
>  	[0 ... ESR_ELx_EC_MAX]	= kvm_handle_unknown_ec,
>  	[ESR_ELx_EC_WFx]	= kvm_handle_wfx,
> @@ -159,6 +166,7 @@ static exit_handle_fn arm_exit_handlers[] = {
>  	[ESR_ELx_EC_HVC64]	= handle_hvc,
>  	[ESR_ELx_EC_SMC64]	= handle_smc,
>  	[ESR_ELx_EC_SYS64]	= kvm_handle_sys_reg,
> +	[ESR_ELx_EC_SVE]	= handle_sve,
>  	[ESR_ELx_EC_IABT_LOW]	= kvm_handle_guest_abort,
>  	[ESR_ELx_EC_DABT_LOW]	= kvm_handle_guest_abort,
>  	[ESR_ELx_EC_SOFTSTP_LOW]= kvm_handle_guest_debug,
> -- 
> 2.1.4
> 
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [RFC PATCH v2 11/41] arm64/sve: Expand task_struct for Scalable Vector Extension state
  2017-03-22 16:20   ` Mark Rutland
@ 2017-03-23 10:49     ` Dave Martin
  2017-03-23 11:26       ` Mark Rutland
  0 siblings, 1 reply; 75+ messages in thread
From: Dave Martin @ 2017-03-23 10:49 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Mar 22, 2017 at 04:20:35PM +0000, Mark Rutland wrote:
> On Wed, Mar 22, 2017 at 02:50:41PM +0000, Dave Martin wrote:
> > This patch expands task_struct to accommodate the Scalable Vector
> > Extension state.
> > 
> > The extra space is not used for anything yet.
> 
> [...]
> 
> > +#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;
> > +}
> 
> Can we mnemonicise the magic numbers for these?
> 
> That, and some comment regarding how the task_struct and sve state are
> organised in memory, as that's painful to reverse-engineer.

See patch 16.  The signal frame layout becomes the canonical source of
this magic (since I deliberately want to be able to copy directly to/
from task_struct).

That patch also abstracts the vl validity check so we don't have to
spell that out everywhere.

> 
> > +
> > +#else /* ! CONFIG_ARM64_SVE */
> > +
> > +/* Dummy declarations for usage protected with IS_ENABLED(CONFIG_ARM64_SVE): */
> > +extern void *__sve_state(struct task_struct *task);
> > +extern void *sve_pffr(struct task_struct *task);
> > +
> > +#endif /* ! CONFIG_ARM64_SVE */
> 
> The usual pattern is to make these static inlines, with a BUILD_BUG() if
> calls are expected/required to be optimised away entirely.

Not sure where I got this idiom from -- there is precedent in e.g.,
arch/arm/include/asm/cmpxchg.h, but I don't think I got it from
there...

I was concerned about false positives with BUILD_BUG(), but it's
unavoidable either way.  The compiler is never going to give an absolute
promise to remove unused code.

The "missing extern" approach seems no less valid, except potential
namespace pollution, but I don't have a problem with changing these.

Cheers
---Dave

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [RFC PATCH v2 21/41] arm64/sve: Enable SVE on demand for userspace
  2017-03-22 16:48   ` Mark Rutland
@ 2017-03-23 11:24     ` Dave Martin
  2017-03-23 11:30       ` Suzuki K Poulose
  0 siblings, 1 reply; 75+ messages in thread
From: Dave Martin @ 2017-03-23 11:24 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Mar 22, 2017 at 04:48:10PM +0000, Mark Rutland wrote:
> Hi,
> 
> On Wed, Mar 22, 2017 at 02:50:51PM +0000, Dave Martin wrote:
> > This patch tracks whether a task has ever attempted to use the
> > Scalable Vector Extension.  If and only if SVE is in use by a task,
> > it will be enabled for userspace when scheduling the task in.  For
> > other tasks, SVE is disabled when scheduling in.
> 
> >  #define TIF_SYSCALL_AUDIT	9
> >  #define TIF_SYSCALL_TRACEPOINT	10
> >  #define TIF_SECCOMP		11
> > +#define TIF_SVE			17	/* Scalable Vector Extension in use */
> 
> Please don't skip ahead to bit 17. I see why you're doing that, but I
> don't think that's a good idea. More on that below.

Well, a comment here to explain the dependency would have been a good
idea, but I agree it's better to drop this trickery...

> > +void do_sve_acc(unsigned int esr, struct pt_regs *regs)
> > +{
> > +	unsigned long tmp;
> > +
> > +	if (test_and_set_thread_flag(TIF_SVE))
> > +		BUG();
> > +
> > +	asm ("mrs %0, cpacr_el1" : "=r" (tmp));
> > +	asm volatile ("msr cpacr_el1, %0" :: "r" (tmp | (1 << 17)));
> 
> Please de-magic the number, e.g. with something like:
> 
> #define CPACR_SVE_EN	(1 << 17)
> 
> ... in <asm/sysreg.h>.
> 
> Please also use {read,write}_sysreg(), e.g.

TBH, I was confused about the status of these macros at the time I
wrote this code.

The naming clash with the cpufeature functions is unfortunate.  In my
head these names all became associated with "do something behind the
scenes that may or may not really read the underlying system reg".

Would it be reasonable to rename read_system_reg() to something more
different, like read_kernel_sysreg(), read_system_id(),
read_sanitised_id_reg(), etc.?

The purpose of these functions is very different: in the
read_system_reg() case we aren't reading an architectural system reg,
but something invented by Linux that is derived from, but semantically
different from, what the architecture specifies.

Happy to propose a patch (though I'll decouple it from this series).


For this code, I'm not a strong believer in hiding asms just for the
sake of it.

But in this case I agree that read_sysreg() would make the code more
readable and get rid of some cruft.  The code I wrote here, and the
TIF_SVE encoding trick, are needlessly obscure and could certainly use a
cleanup, so

> 
> 	val = read_sysreg(cpacr_el1);
> 	tmp |= CPACR_SVE_EN;
> 	write_sysreg(tmp, cpacr_el1);
> 
> [...]
> 
> > +		if (IS_ENABLED(CONFIG_ARM64_SVE)) {
> > +			/*
> > +			 * Flip SVE enable for userspace if it doesn't
> > +			 * match the current_task.
> > +			 */
> > +			asm ("mrs %0, cpacr_el1" : "=r" (tmp));
> > +			flags = current_thread_info()->flags;
> > +			if ((tmp ^ (unsigned long)flags) & (1 << 17)) {
> > +				tmp ^= 1 << 17;
> > +				asm volatile ("msr cpacr_el1, %0" :: "r" (tmp));
> > +			}
> 
> I think it's a bad idea to rely on the TIF flag and CPACR bit to have
> the same index. It makes this painful to read, and it leaves us fragile
> if the TIF bits are reorganised.
> 
> How about:
> 
> 	unsigned long cpacr = read_sysreg(cpacr_el1);
> 	bool hw_enabled = !!(cpacr & CPACR_SVE_EN);
> 	bool sw_enabled = test_thread_flag(TIF_SVE);
> 
> 	/*
> 	 * Flip SVE enable for userspace if it doesn't
> 	 * match the current_task.
> 	 */
> 	if (hw_enabled != sw_enabled) {
> 		cpacr ^= CPACR_SVE_EN;
> 		write_sysreg(cpacr, cpacr_el1);
> 	}

... I'm happy to clean things up along these lines.

I will probably ditch the ^ here (another obscurism) too in favour of
|.  CPACR_EL1_ZEN_EL0EN clear is a precondition for this code, without
which we won't take the trap, and it needs to be _set_ on return, not
just different from the initial value.

Cheers
---Dave

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [RFC PATCH v2 11/41] arm64/sve: Expand task_struct for Scalable Vector Extension state
  2017-03-23 10:49     ` Dave Martin
@ 2017-03-23 11:26       ` Mark Rutland
  0 siblings, 0 replies; 75+ messages in thread
From: Mark Rutland @ 2017-03-23 11:26 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Mar 23, 2017 at 10:49:30AM +0000, Dave Martin wrote:
> On Wed, Mar 22, 2017 at 04:20:35PM +0000, Mark Rutland wrote:
> > On Wed, Mar 22, 2017 at 02:50:41PM +0000, Dave Martin wrote:

> > > +	return (char *)task + ALIGN(sizeof(*task), 16);

> > > +	BUG_ON(vl % 16);
> > > +	return (char *)__sve_state(task) + 34 * vl;

> > Can we mnemonicise the magic numbers for these?
> > 
> > That, and some comment regarding how the task_struct and sve state are
> > organised in memory, as that's painful to reverse-engineer.
> 
> See patch 16.  The signal frame layout becomes the canonical source of
> this magic (since I deliberately want to be able to copy directly to/
> from task_struct).
> 
> That patch also abstracts the vl validity check so we don't have to
> spell that out everywhere.

Ah, sorry for the noise there.

[...]

> > > +#else /* ! CONFIG_ARM64_SVE */
> > > +
> > > +/* Dummy declarations for usage protected with IS_ENABLED(CONFIG_ARM64_SVE): */
> > > +extern void *__sve_state(struct task_struct *task);
> > > +extern void *sve_pffr(struct task_struct *task);
> > > +
> > > +#endif /* ! CONFIG_ARM64_SVE */
> > 
> > The usual pattern is to make these static inlines, with a BUILD_BUG() if
> > calls are expected/required to be optimised away entirely.
> 
> Not sure where I got this idiom from -- there is precedent in e.g.,
> arch/arm/include/asm/cmpxchg.h, but I don't think I got it from
> there...
> 
> I was concerned about false positives with BUILD_BUG(), but it's
> unavoidable either way.  The compiler is never going to give an absolute
> promise to remove unused code.
> 
> The "missing extern" approach seems no less valid, except potential
> namespace pollution, but I don't have a problem with changing these.

Sure. The other option is to have the inline do nothing, which avoids a
build problen either way.

Thanks,
Mark.

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [RFC PATCH v2 21/41] arm64/sve: Enable SVE on demand for userspace
  2017-03-23 11:24     ` Dave Martin
@ 2017-03-23 11:30       ` Suzuki K Poulose
  2017-03-23 11:52         ` Mark Rutland
  0 siblings, 1 reply; 75+ messages in thread
From: Suzuki K Poulose @ 2017-03-23 11:30 UTC (permalink / raw)
  To: linux-arm-kernel

On 23/03/17 11:24, Dave Martin wrote:
> On Wed, Mar 22, 2017 at 04:48:10PM +0000, Mark Rutland wrote:
>> Hi,
>>
>> On Wed, Mar 22, 2017 at 02:50:51PM +0000, Dave Martin wrote:
>>> This patch tracks whether a task has ever attempted to use the
>>> Scalable Vector Extension.  If and only if SVE is in use by a task,
>>> it will be enabled for userspace when scheduling the task in.  For
>>> other tasks, SVE is disabled when scheduling in.
>>
>>>  #define TIF_SYSCALL_AUDIT	9
>>>  #define TIF_SYSCALL_TRACEPOINT	10
>>>  #define TIF_SECCOMP		11
>>> +#define TIF_SVE			17	/* Scalable Vector Extension in use */
>>
>> Please don't skip ahead to bit 17. I see why you're doing that, but I
>> don't think that's a good idea. More on that below.
>
> Well, a comment here to explain the dependency would have been a good
> idea, but I agree it's better to drop this trickery...
>
>>> +void do_sve_acc(unsigned int esr, struct pt_regs *regs)
>>> +{
>>> +	unsigned long tmp;
>>> +
>>> +	if (test_and_set_thread_flag(TIF_SVE))
>>> +		BUG();
>>> +
>>> +	asm ("mrs %0, cpacr_el1" : "=r" (tmp));
>>> +	asm volatile ("msr cpacr_el1, %0" :: "r" (tmp | (1 << 17)));
>>
>> Please de-magic the number, e.g. with something like:
>>
>> #define CPACR_SVE_EN	(1 << 17)
>>
>> ... in <asm/sysreg.h>.
>>
>> Please also use {read,write}_sysreg(), e.g.
>
> TBH, I was confused about the status of these macros at the time I
> wrote this code.
>
> The naming clash with the cpufeature functions is unfortunate.  In my
> head these names all became associated with "do something behind the
> scenes that may or may not really read the underlying system reg".
>
> Would it be reasonable to rename read_system_reg() to something more
> different, like read_kernel_sysreg(), read_system_id(),
> read_sanitised_id_reg(), etc.?

I agree. read_system_reg() is not quite obvious name given all the other
similar names. We could go with either read_sanitised_id_reg() or read_system_safe_reg() ?

Suzuki

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [RFC PATCH v2 21/41] arm64/sve: Enable SVE on demand for userspace
  2017-03-23 11:30       ` Suzuki K Poulose
@ 2017-03-23 11:52         ` Mark Rutland
  2017-03-23 12:07           ` Dave Martin
  0 siblings, 1 reply; 75+ messages in thread
From: Mark Rutland @ 2017-03-23 11:52 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Mar 23, 2017 at 11:30:16AM +0000, Suzuki K Poulose wrote:
> On 23/03/17 11:24, Dave Martin wrote:
> >On Wed, Mar 22, 2017 at 04:48:10PM +0000, Mark Rutland wrote:

> >>>+	asm ("mrs %0, cpacr_el1" : "=r" (tmp));
> >>>+	asm volatile ("msr cpacr_el1, %0" :: "r" (tmp | (1 << 17)));

> >>Please also use {read,write}_sysreg(), e.g.
> >
> >TBH, I was confused about the status of these macros at the time I
> >wrote this code.
> >
> >The naming clash with the cpufeature functions is unfortunate.  In my
> >head these names all became associated with "do something behind the
> >scenes that may or may not really read the underlying system reg".
> >
> >Would it be reasonable to rename read_system_reg() to something more
> >different, like read_kernel_sysreg(), read_system_id(),
> >read_sanitised_id_reg(), etc.?
> 
> I agree. read_system_reg() is not quite obvious name given all the other
> similar names. We could go with either read_sanitised_id_reg() or read_system_safe_reg() ?

I think read_sanitised_id_reg() sounds best, since "safe" cound mean a
few things, and having "id" in the name makes it clear that it's not a
general purpose sysreg accessor.

Thanks,
Mark.

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [RFC PATCH v2 23/41] arm64/sve: Move ZEN handling to the common task_fpsimd_load() path
  2017-03-22 16:55   ` Mark Rutland
@ 2017-03-23 11:52     ` Dave Martin
  0 siblings, 0 replies; 75+ messages in thread
From: Dave Martin @ 2017-03-23 11:52 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Mar 22, 2017 at 04:55:27PM +0000, Mark Rutland wrote:
> Hi,
> 
> On Wed, Mar 22, 2017 at 02:50:53PM +0000, Dave Martin wrote:
> >  void do_sve_acc(unsigned int esr, struct pt_regs *regs)
> >  {
> > -	unsigned long tmp;
> > +	if (test_and_set_thread_flag(TIF_SVE)) {
> > +		unsigned long tmp;
> >  
> > -	if (test_and_set_thread_flag(TIF_SVE))
> > +		asm ("mrs %0, cpacr_el1" : "=r" (tmp));
> 
> Please use read_sysreg().
> 
> > +
> > +		printk(KERN_INFO "%s: Strange, ZEN=%u\n",
> > +		       __func__, (unsigned int)((tmp >> 16) & 3));
> >  		BUG();
> 
> Given we're about to BUG(), I guess it would make more sense to use
> pr_err() here, and be a bit more informative. e.g.
> 
> 	pr_crit("SVE trap taken unexpectedly. CPACR_EL1.ZEN is %u\n",
> 		(unsigned int)((tmp >> 16) & 3));
> 	BUG();

This also goes away later -- it made sense for debugging, but since
do_sve_acc() is called on the back of a trap this BUG is really a check
for broken hardware.

Later, this is reduced to

	if (test_and_set_thread_flag(TIF_SVE))
		BUG();

with the CPACR manipulation moved to ret_to_user
(via task_fpsimd_load()).

> 
> ... my usual comments w.r.t. magic numbers apply.
> 
> [...]
> 
> > +		BUILD_BUG_ON(_TIF_SVE != CPACR_EL1_ZEN_EL0EN);
> 
> As previously, I do not think this is a good idea. Treating these as
> separate values is not difficult, and IMO far easier to reason about.

Agreed.

Cheers
---Dave

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [RFC PATCH v2 24/41] arm64/sve: Discard SVE state on system call
  2017-03-22 17:03   ` Mark Rutland
@ 2017-03-23 11:59     ` Dave Martin
  0 siblings, 0 replies; 75+ messages in thread
From: Dave Martin @ 2017-03-23 11:59 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Mar 22, 2017 at 05:03:30PM +0000, Mark Rutland wrote:
> On Wed, Mar 22, 2017 at 02:50:54PM +0000, Dave Martin wrote:
> > The base procedure call standard for the Scalable Vector Extension
> > defines all of the SVE programmer's model state (Z0-31, P0-15, FFR)
> > as caller-save, except for that subset of the state that aliases
> > FPSIMD state.
> > 
> > System calls from userspace will almost always be made through C
> > library wrappers -- as a consequence of the PCS there will thus
> > rarely if ever be any live SVE state at syscall entry in practice.
> > 
> > This gives us an opportinity to make SVE explicitly caller-save
> > around SVC and so stop carrying around the SVE state for tasks that
> > use SVE only occasionally (say, by calling a library).
> > 
> > Note that FPSIMD state will still be preserved around SVC.
> > 
> > As a crude heuristic to avoid pathological cases where a thread
> > that uses SVE frequently has to fault back into the kernel again to
> > re-enable SVE after a syscall, we switch the thread back to
> > FPSIMD-only context tracking only if the context is actually
> > switched out before returning to userspace.
> > 
> > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > ---
> >  arch/arm64/kernel/fpsimd.c | 17 +++++++++++++++++
> >  1 file changed, 17 insertions(+)
> > 
> > diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
> > index 5fb5585..8c18384 100644
> > --- a/arch/arm64/kernel/fpsimd.c
> > +++ b/arch/arm64/kernel/fpsimd.c
> > @@ -250,6 +250,23 @@ static void task_fpsimd_save(struct task_struct *task)
> >  	BUG_ON(task != current);
> >  
> >  	if (IS_ENABLED(CONFIG_ARM64_SVE) &&
> > +	    task_pt_regs(task)->syscallno != ~0UL &&

^ I may add a helper for this occult check (since it duplicated
elsewhere), but...

> > +	    test_tsk_thread_flag(task, TIF_SVE)) {
> > +		unsigned long tmp;
> > +
> > +		clear_tsk_thread_flag(task, TIF_SVE);
> > +
> > +		/* Trap if the task tries to use SVE again: */
> > +		asm volatile (
> > +			"mrs	%[tmp], cpacr_el1\n\t"
> > +			"bic	%[tmp], %[tmp], %[mask]\n\t"
> > +			"msr	cpacr_el1, %[tmp]"
> > +			: [tmp] "=r" (tmp)
> > +			: [mask] "i" (CPACR_EL1_ZEN_EL0EN)
> > +		);
> 
> Given we're poking this bit in a few places, I think it would make more
> sense to add enable/disable helpers. Those can also subsume the lazy
> writeback used for the context switch, e.g.
> 
> static inline void sve_el0_enable(void)
> }
> 	unsigned long cpacr = read_sysreg(cpacr_el1);
> 	if ((cpacr & CPACR_EL1_ZEN_EL0EN)
> 		return;
> 
> 	cpacr |= CPACR_EL1_ZEN_EL0EN;
> 	write_sysreg(cpacr, cpacr_el1);
> }
> 
> static inline void sve_el0_disable(void)
> {
> 	unsigned long cpacr = read_sysreg(cpacr_el1);
> 	if (!(cpacr & CPACR_EL1_ZEN_EL0EN)
> 		return;
> 
> 	cpacr &= ~CPACR_EL1_ZEN_EL0EN;
> 	write_sysreg(cpacr, cpacr_el1);
> }

... although this makes sense and I did consider it, instead I ended up
consolidating this in one place in task_fpsimd_load().   ret_to_user is
the only time we care about what EL0EN is set to, and task_fpsimd_load
is only used on that path.

With it in one place, abstraction seemed less necessary -- but I'll
still clean up the asm hacks as you suggest.

Cheers
---Dave

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [RFC PATCH v2 21/41] arm64/sve: Enable SVE on demand for userspace
  2017-03-23 11:52         ` Mark Rutland
@ 2017-03-23 12:07           ` Dave Martin
  2017-03-23 13:40             ` Mark Rutland
  0 siblings, 1 reply; 75+ messages in thread
From: Dave Martin @ 2017-03-23 12:07 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Mar 23, 2017 at 11:52:27AM +0000, Mark Rutland wrote:
> On Thu, Mar 23, 2017 at 11:30:16AM +0000, Suzuki K Poulose wrote:
> > On 23/03/17 11:24, Dave Martin wrote:
> > >On Wed, Mar 22, 2017 at 04:48:10PM +0000, Mark Rutland wrote:
> 
> > >>>+	asm ("mrs %0, cpacr_el1" : "=r" (tmp));
> > >>>+	asm volatile ("msr cpacr_el1, %0" :: "r" (tmp | (1 << 17)));
> 
> > >>Please also use {read,write}_sysreg(), e.g.
> > >
> > >TBH, I was confused about the status of these macros at the time I
> > >wrote this code.
> > >
> > >The naming clash with the cpufeature functions is unfortunate.  In my
> > >head these names all became associated with "do something behind the
> > >scenes that may or may not really read the underlying system reg".
> > >
> > >Would it be reasonable to rename read_system_reg() to something more
> > >different, like read_kernel_sysreg(), read_system_id(),
> > >read_sanitised_id_reg(), etc.?
> > 
> > I agree. read_system_reg() is not quite obvious name given all the other
> > similar names. We could go with either read_sanitised_id_reg() or read_system_safe_reg() ?
> 
> I think read_sanitised_id_reg() sounds best, since "safe" cound mean a
> few things, and having "id" in the name makes it clear that it's not a
> general purpose sysreg accessor.

OK, I'll write a separate patch proposing that.

Are we comfortable with _id_ in the name here?

My logic was that sanitisation makes no sense for anything except
read-only ID registers, and _system_ sounds too universal.


There is a sting in the tail here -- I add ZCR as an "id" reg so that we
can treat the maximum configurable length in the LEN field as if it were
an ID field.  See patch 38 (apologies Suzuki, missed your CC).

In fact, ZCR is neither read-only nor an ID register -- but the view of
it through cpufeatures does have those properties.

It might be better to rename it, but I considered it an OK compromise.
Let me know if you have concerns.

Cheers
---Dave

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [RFC PATCH v2 28/41] arm64: KVM: Treat SVE use by guests as undefined instruction execution
  2017-03-22 17:06   ` Mark Rutland
@ 2017-03-23 12:10     ` Dave Martin
  0 siblings, 0 replies; 75+ messages in thread
From: Dave Martin @ 2017-03-23 12:10 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Mar 22, 2017 at 05:06:58PM +0000, Mark Rutland wrote:
> Hi,
> 
> On Wed, Mar 22, 2017 at 02:50:58PM +0000, Dave Martin wrote:
> > We don't currently support context-switching of Scalable Vector
> > Extension context between vcpus, and the SVE access exception is
> > thus left masked by default at EL2 when running a vcpu.
> > 
> > However, there's nothing to stop a guest trying to use SVE.  If it
> > does, we'll get an SVE access exception to EL2 which will cause KVM
> > to panic since this exception isn't yet recognised.
> > 
> > This patch adds knowledge to KVM about the SVE access exception,
> > translating it into an undefined instruction exception injected to
> > the vcpu.
> > 
> > This prevents a malicious guest from panicking the host by
> > attempted SVE use.
> > 
> > SVE-enabled guests will still not work properly for now, but they
> > won't take the host down.
> > 
> > Signed-off-by: Dave Martin <Dave.Martin@arm.com>
> > ---
> >  arch/arm64/kvm/handle_exit.c | 8 ++++++++
> >  1 file changed, 8 insertions(+)
> 
> As a heads-up, this is handled implicitly by kvm_handle_unknown_ec()
> since commit ba4dd156eabdca93 ("arm64: KVM: Survive unknown traps from
> guests"). That also logs a (ratelimited) warning regarding the
> unimplemented trap handling.
> 
> Given that, I think we can drop this patch until actual support lands.

Agreed.

I wasn't sure that we wanted the verbose printks for this case, but since guests using SVE are currently broken it's better to have it.

I'll drop this pending proper KVM support.

Cheers
---Dave

> 
> Thanks,
> Mark.
> 
> > 
> > diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c
> > index fa1b18e..e43b147 100644
> > --- a/arch/arm64/kvm/handle_exit.c
> > +++ b/arch/arm64/kvm/handle_exit.c
> > @@ -146,6 +146,13 @@ static int kvm_handle_unknown_ec(struct kvm_vcpu *vcpu, struct kvm_run *run)
> >  	return 1;
> >  }
> >  
> > +static int handle_sve(struct kvm_vcpu *vcpu, struct kvm_run *run)
> > +{
> > +	/* Until SVE is supported for guests: */
> > +	kvm_inject_undefined(vcpu);
> > +	return 1;
> > +}
> > +
> >  static exit_handle_fn arm_exit_handlers[] = {
> >  	[0 ... ESR_ELx_EC_MAX]	= kvm_handle_unknown_ec,
> >  	[ESR_ELx_EC_WFx]	= kvm_handle_wfx,
> > @@ -159,6 +166,7 @@ static exit_handle_fn arm_exit_handlers[] = {
> >  	[ESR_ELx_EC_HVC64]	= handle_hvc,
> >  	[ESR_ELx_EC_SMC64]	= handle_smc,
> >  	[ESR_ELx_EC_SYS64]	= kvm_handle_sys_reg,
> > +	[ESR_ELx_EC_SVE]	= handle_sve,
> >  	[ESR_ELx_EC_IABT_LOW]	= kvm_handle_guest_abort,
> >  	[ESR_ELx_EC_DABT_LOW]	= kvm_handle_guest_abort,
> >  	[ESR_ELx_EC_SOFTSTP_LOW]= kvm_handle_guest_debug,
> > -- 
> > 2.1.4
> > 
> > 
> > _______________________________________________
> > linux-arm-kernel mailing list
> > linux-arm-kernel at lists.infradead.org
> > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [RFC PATCH v2 21/41] arm64/sve: Enable SVE on demand for userspace
  2017-03-23 12:07           ` Dave Martin
@ 2017-03-23 13:40             ` Mark Rutland
  2017-03-23 13:45               ` Dave Martin
  0 siblings, 1 reply; 75+ messages in thread
From: Mark Rutland @ 2017-03-23 13:40 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Mar 23, 2017 at 12:07:26PM +0000, Dave Martin wrote:
> On Thu, Mar 23, 2017 at 11:52:27AM +0000, Mark Rutland wrote:
> > On Thu, Mar 23, 2017 at 11:30:16AM +0000, Suzuki K Poulose wrote:
> > > On 23/03/17 11:24, Dave Martin wrote:
> > > >On Wed, Mar 22, 2017 at 04:48:10PM +0000, Mark Rutland wrote:
> > 
> > > >>>+	asm ("mrs %0, cpacr_el1" : "=r" (tmp));
> > > >>>+	asm volatile ("msr cpacr_el1, %0" :: "r" (tmp | (1 << 17)));
> > 
> > > >>Please also use {read,write}_sysreg(), e.g.
> > > >
> > > >TBH, I was confused about the status of these macros at the time I
> > > >wrote this code.
> > > >
> > > >The naming clash with the cpufeature functions is unfortunate.  In my
> > > >head these names all became associated with "do something behind the
> > > >scenes that may or may not really read the underlying system reg".
> > > >
> > > >Would it be reasonable to rename read_system_reg() to something more
> > > >different, like read_kernel_sysreg(), read_system_id(),
> > > >read_sanitised_id_reg(), etc.?
> > > 
> > > I agree. read_system_reg() is not quite obvious name given all the other
> > > similar names. We could go with either read_sanitised_id_reg() or read_system_safe_reg() ?
> > 
> > I think read_sanitised_id_reg() sounds best, since "safe" cound mean a
> > few things, and having "id" in the name makes it clear that it's not a
> > general purpose sysreg accessor.
> 
> OK, I'll write a separate patch proposing that.
> 
> Are we comfortable with _id_ in the name here?
> 
> My logic was that sanitisation makes no sense for anything except
> read-only ID registers, and _system_ sounds too universal.
> 
> There is a sting in the tail here -- I add ZCR as an "id" reg so that we
> can treat the maximum configurable length in the LEN field as if it were
> an ID field.  See patch 38 (apologies Suzuki, missed your CC).
> 
> In fact, ZCR is neither read-only nor an ID register -- but the view of
> it through cpufeatures does have those properties.
> 
> It might be better to rename it, but I considered it an OK compromise.
> Let me know if you have concerns.

FWIW, I'm fine with read_sanitised_id_reg(), even considering the ZCR
case, given we're using it for feature identification information.

At best, we only need a comment over the ZCR field definitions in
arch/arm64/kernel/cpufeature.c, explaining what's going on.

Perhaps read_sanitised_ftr_reg() covers that better? That might align
better with the existing *_ftr_reg() naming.

Thanks,
Mark.

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [RFC PATCH v2 21/41] arm64/sve: Enable SVE on demand for userspace
  2017-03-23 13:40             ` Mark Rutland
@ 2017-03-23 13:45               ` Dave Martin
  0 siblings, 0 replies; 75+ messages in thread
From: Dave Martin @ 2017-03-23 13:45 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Mar 23, 2017 at 01:40:24PM +0000, Mark Rutland wrote:
> On Thu, Mar 23, 2017 at 12:07:26PM +0000, Dave Martin wrote:

[...]

> > My logic was that sanitisation makes no sense for anything except
> > read-only ID registers, and _system_ sounds too universal.
> > 
> > There is a sting in the tail here -- I add ZCR as an "id" reg so that we
> > can treat the maximum configurable length in the LEN field as if it were
> > an ID field.  See patch 38 (apologies Suzuki, missed your CC).
> > 
> > In fact, ZCR is neither read-only nor an ID register -- but the view of
> > it through cpufeatures does have those properties.
> > 
> > It might be better to rename it, but I considered it an OK compromise.
> > Let me know if you have concerns.
> 
> FWIW, I'm fine with read_sanitised_id_reg(), even considering the ZCR
> case, given we're using it for feature identification information.
> 
> At best, we only need a comment over the ZCR field definitions in
> arch/arm64/kernel/cpufeature.c, explaining what's going on.

Could be a good idea -- I'll add a comment or two.

> Perhaps read_sanitised_ftr_reg() covers that better? That might align
> better with the existing *_ftr_reg() naming.

Happy to go with that if nobody objects.

Cheers
---Dave

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [RFC PATCH v2 38/41] arm64/sve: Detect SVE via the cpufeature framework
  2017-03-22 14:51 ` [RFC PATCH v2 38/41] arm64/sve: Detect SVE via the cpufeature framework Dave Martin
@ 2017-03-23 14:11   ` Suzuki K Poulose
  2017-03-23 14:37     ` Dave Martin
  0 siblings, 1 reply; 75+ messages in thread
From: Suzuki K Poulose @ 2017-03-23 14:11 UTC (permalink / raw)
  To: linux-arm-kernel

On 22/03/17 14:51, Dave Martin wrote:
> For robust feature detection and appropriate handling of feature
> mismatches between CPUs, this patch adds knowledge of the new
> feature fields and new registers ZCR_EL1 and ID_AA64ZFR0_EL1 to the
> cpufeature framework.

...

>
> The SVE field in AA64PFR0 is made visible visible to userspace MRS
> emulation.  This should make sense for future architecture
> extensions.

Please could you also update the following documentation :

  Documentation/arm64/cpu-feature-registers.txt

> +#ifdef CONFIG_ARM64_SVE
> +	{
> +		.desc = "Scalable Vector Extension",
> +		.capability = ARM64_SVE,
> +		.def_scope = SCOPE_SYSTEM,
> +		.sys_reg = SYS_ID_AA64PFR0_EL1,
> +		.sign = FTR_UNSIGNED,
> +		.field_pos = ID_AA64PFR0_SVE_SHIFT,
> +		.min_field_value = ID_AA64PFR0_SVE,
> +		.matches = has_cpuid_feature,
> +	},
> +#endif /* CONFIG_ARM64_SVE */
>  	{},
>  };
>
> @@ -889,7 +923,7 @@ static const struct arm64_cpu_capabilities arm64_elf_hwcaps[] = {
>  	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),
> +	HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_SVE_SHIFT, FTR_UNSIGNED, ID_AA64PFR0_SVE, CAP_HWCAP, HWCAP_SVE),

>  #endif
>  	{},
>  };
> @@ -1120,6 +1154,8 @@ void __init setup_cpu_features(void)
>  	if (system_supports_32bit_el0())
>  		setup_elf_hwcaps(compat_elf_hwcaps);
>
> +	sve_setup();
> +
>  	/* Advertise that we have computed the system capabilities */
>  	set_sys_caps_initialised();
>
> diff --git a/arch/arm64/kernel/cpuinfo.c b/arch/arm64/kernel/cpuinfo.c
> index 8dd410e..cb3b0dd 100644
> --- a/arch/arm64/kernel/cpuinfo.c
> +++ b/arch/arm64/kernel/cpuinfo.c
> @@ -19,6 +19,7 @@
>  #include <asm/cpu.h>
>  #include <asm/cputype.h>
>  #include <asm/cpufeature.h>
> +#include <asm/fpsimd.h>
>
>  #include <linux/bitops.h>
>  #include <linux/bug.h>
> @@ -325,6 +326,7 @@ static void __cpuinfo_store_cpu(struct cpuinfo_arm64 *info)
>  	info->reg_id_aa64mmfr2 = read_cpuid(ID_AA64MMFR2_EL1);
>  	info->reg_id_aa64pfr0 = read_cpuid(ID_AA64PFR0_EL1);
>  	info->reg_id_aa64pfr1 = read_cpuid(ID_AA64PFR1_EL1);
> +	info->reg_id_aa64zfr0 = read_cpuid(ID_AA64ZFR0_EL1);
>
>  	/* Update the 32bit ID registers only if AArch32 is implemented */
>  	if (id_aa64pfr0_32bit_el0(info->reg_id_aa64pfr0)) {
> @@ -347,6 +349,17 @@ static void __cpuinfo_store_cpu(struct cpuinfo_arm64 *info)
>  		info->reg_mvfr2 = read_cpuid(MVFR2_EL1);
>  	}
>
> +	if (id_aa64pfr0_sve(info->reg_id_aa64pfr0)) {
> +		u64 zcr;
> +
> +		write_sysreg_s(ZCR_EL1_LEN_MASK, SYS_ZCR_EL1);
> +		zcr = read_sysreg_s(SYS_ZCR_EL1);
> +		zcr &= ~(u64)ZCR_EL1_LEN_MASK;
> +		zcr |= sve_get_vl() / 16 - 1;
> +
> +		info->reg_zcr = zcr;
> +	}
> +
>  	cpuinfo_detect_icache_policy(info);
>  }
>
> diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
> index ddb651a..34ec75e 100644
> --- a/arch/arm64/kernel/fpsimd.c
> +++ b/arch/arm64/kernel/fpsimd.c
> @@ -340,6 +340,26 @@ int sve_get_task_vl(struct task_struct *task)
>  	return sve_prctl_status(task);
>  }
>
> +void __init sve_setup(void)
> +{
> +	u64 zcr;
> +
> +	if (!system_supports_sve())
> +		return;
> +
> +	zcr = read_system_reg(SYS_ZCR_EL1);
> +
> +	BUG_ON(((zcr & ZCR_EL1_LEN_MASK) + 1) * 16 > sve_max_vl);
> +
> +	sve_max_vl = ((zcr & ZCR_EL1_LEN_MASK) + 1) * 16;
> +	sve_default_vl = sve_max_vl > 64 ? 64 : sve_max_vl;
> +
> +	pr_info("SVE: maximum available vector length %u bytes per vector\n",
> +		sve_max_vl);
> +	pr_info("SVE: default vector length %u bytes per vector\n",
> +		sve_default_vl);

I think we may need an extra check in verify_local_cpu_capabilities() to make sure the new CPU,
which comes up late can support the SVE vector length that could possibly used, i.e, sve_max_vl.

Rest looks good to me.

Suzuki

> +}
> +
>  #ifdef CONFIG_PROC_FS
>
>  struct default_vl_write_state {
> @@ -898,9 +918,6 @@ static int __init fpsimd_init(void)
>  	if (!(elf_hwcap & HWCAP_ASIMD))
>  		pr_notice("Advanced SIMD is not implemented\n");
>
> -	if (!(elf_hwcap & HWCAP_SVE))
> -		pr_info("Scalable Vector Extension available\n");
> -
>  	if (IS_ENABLED(CONFIG_ARM64_SVE) && (elf_hwcap & HWCAP_SVE))

nit: You may use system_supports_sve() here, instead of the elf_hwcap check. Since this
is not a performance critical path it doesn't really matter, how we check it.

>  		return sve_procfs_init();
>
>

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [RFC PATCH v2 38/41] arm64/sve: Detect SVE via the cpufeature framework
  2017-03-23 14:11   ` Suzuki K Poulose
@ 2017-03-23 14:37     ` Dave Martin
  2017-03-23 14:43       ` Dave Martin
  0 siblings, 1 reply; 75+ messages in thread
From: Dave Martin @ 2017-03-23 14:37 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Mar 23, 2017 at 02:11:50PM +0000, Suzuki K Poulose wrote:
> On 22/03/17 14:51, Dave Martin wrote:
> >For robust feature detection and appropriate handling of feature
> >mismatches between CPUs, this patch adds knowledge of the new
> >feature fields and new registers ZCR_EL1 and ID_AA64ZFR0_EL1 to the
> >cpufeature framework.
> 
> ...
> 
> >
> >The SVE field in AA64PFR0 is made visible visible to userspace MRS
> >emulation.  This should make sense for future architecture
> >extensions.
> 
> Please could you also update the following documentation :
> 
>  Documentation/arm64/cpu-feature-registers.txt

Missed that, thanks.

I'll propose a comment in this file reminding people to keep the
document up to date too.

[...]

> >diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
> >index ddb651a..34ec75e 100644
> >--- a/arch/arm64/kernel/fpsimd.c
> >+++ b/arch/arm64/kernel/fpsimd.c
> >@@ -340,6 +340,26 @@ int sve_get_task_vl(struct task_struct *task)
> > 	return sve_prctl_status(task);
> > }
> >
> >+void __init sve_setup(void)
> >+{
> >+	u64 zcr;
> >+
> >+	if (!system_supports_sve())
> >+		return;
> >+
> >+	zcr = read_system_reg(SYS_ZCR_EL1);
> >+
> >+	BUG_ON(((zcr & ZCR_EL1_LEN_MASK) + 1) * 16 > sve_max_vl);
> >+
> >+	sve_max_vl = ((zcr & ZCR_EL1_LEN_MASK) + 1) * 16;
> >+	sve_default_vl = sve_max_vl > 64 ? 64 : sve_max_vl;
> >+
> >+	pr_info("SVE: maximum available vector length %u bytes per vector\n",
> >+		sve_max_vl);
> >+	pr_info("SVE: default vector length %u bytes per vector\n",
> >+		sve_default_vl);
> 
> I think we may need an extra check in verify_local_cpu_capabilities() to make sure the new CPU,
> which comes up late can support the SVE vector length that could possibly used, i.e, sve_max_vl.

You're right -- I had that in a previous draft of the code but forgot
about it when in rewrote it.

> Rest looks good to me.
> 
> Suzuki
> 
> >+}
> >+
> > #ifdef CONFIG_PROC_FS
> >
> > struct default_vl_write_state {
> >@@ -898,9 +918,6 @@ static int __init fpsimd_init(void)
> > 	if (!(elf_hwcap & HWCAP_ASIMD))
> > 		pr_notice("Advanced SIMD is not implemented\n");
> >
> >-	if (!(elf_hwcap & HWCAP_SVE))
> >-		pr_info("Scalable Vector Extension available\n");
> >-
> > 	if (IS_ENABLED(CONFIG_ARM64_SVE) && (elf_hwcap & HWCAP_SVE))
> 
> nit: You may use system_supports_sve() here, instead of the elf_hwcap check. Since this
> is not a performance critical path it doesn't really matter, how we check it.

Hmmm, this looks like a rebase weirdness that I missed.

Patch 39 migrates all instances of this check (including this one) over
to system_supports_sve().

Use of system_supports_sve() in patch 38 is a result of later cleanups
that were reordered during squashing.  I might merge the patches
together for the next round.

Otherwise, I'll clean patch 38 up to fix the inconsistency.


Thanks for the review.

Cheers
---Dave

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [RFC PATCH v2 38/41] arm64/sve: Detect SVE via the cpufeature framework
  2017-03-23 14:37     ` Dave Martin
@ 2017-03-23 14:43       ` Dave Martin
  0 siblings, 0 replies; 75+ messages in thread
From: Dave Martin @ 2017-03-23 14:43 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Mar 23, 2017 at 02:37:05PM +0000, Dave Martin wrote:
> On Thu, Mar 23, 2017 at 02:11:50PM +0000, Suzuki K Poulose wrote:

[...]

> > >The SVE field in AA64PFR0 is made visible visible to userspace MRS
> > >emulation.  This should make sense for future architecture
> > >extensions.
> > 
> > Please could you also update the following documentation :
> > 
> >  Documentation/arm64/cpu-feature-registers.txt
> 
> Missed that, thanks.
> 
> I'll propose a comment in this file reminding people to keep the
> document up to date too.

Scratch that, somebody beat me to it ;)

Cheers
---Dave

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [RFC PATCH v2 00/41] Scalable Vector Extension (SVE) core support
  2017-03-22 14:50 ` Dave Martin
@ 2017-03-31 15:28   ` Ard Biesheuvel
  -1 siblings, 0 replies; 75+ messages in thread
From: Ard Biesheuvel @ 2017-03-31 15:28 UTC (permalink / raw)
  To: Dave Martin
  Cc: linux-arm-kernel, Will Deacon, Catalin Marinas, Marc Zyngier,
	Florian Weimer, Joseph Myers, Szabolcs Nagy, Andrew Morton,
	linux-kernel, Alan Hayward, Yao Qi, gdb, Christoffer Dall,
	libc-alpha, Richard Sandiford, Torvald Riegel

On 22 March 2017 at 14:50, Dave Martin <Dave.Martin@arm.com> wrote:

Hi Dave,

> 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.
>
[...]
> 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.
>

Without having looked at the patches in detail yet, let me reiterate
my position after we discussed this when this series was sent out the
first time around.

- The primary use case for kernel mode NEON is special purpose
instructions, i.e., AES is 20x faster when using the NEON, simply
because that is how one accesses the logic gates that implement the
AES algorithm. There is nothing SIMD or FP in nature about AES.
Compare the CRC extensions, which use scalar registers and
instructions. Of course, there are a couple of exceptions in the form
of bit-slicing algorithms, but in general, like general SIMD, I don't
think it is highly likely that SVE in kernel mode is something we will
have a need for in the foreseeable future.

- The current way of repeatedly stacking/unstacking NEON register
contents in interrupt context is highly inefficient, given that we are
usually interrupting user mode, not kernel mode, and so stacking once
and unstacking when returning from the exception (which is how we
usually deal with it) would be much better. So changing the current
implementation to perform the eager stack/unstack only when a kernel
mode NEON call is already in progress is likely to improve our current
situation already, regardless of whether such a change is needed to
accommodate SVE. Note that to my knowledge, the only in-tree users of
kernel mode NEON operate in process context or softirq context, never
in hardirq context.

Given the above, I think it is perfectly reasonable to conditionally
disallow kernel mode NEON in hardirq context. The crypto routines that
rely on it can easily be fixed up (I already wrote the patches for
that). This would only be necessary on SVE systems, and the reason for
doing so is that - given how preserving and restoring the NEON
register file blows away the upper SVE part of the registers - whoever
arrives at the SVE-aware preserve routine first should be allowed to
run to completion. This does require disabling softirqs during the
time the preserved NEON state is being manipulated but that does not
strike me as a huge price to pay. Note that both restrictions
(disallowing kernel mode NEON in hardirq context, and the need to
disable softirqs while manipulating the state) could be made runtime
dependent on whether we are actually running on an SVE system.

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [RFC PATCH v2 00/41] Scalable Vector Extension (SVE) core support
@ 2017-03-31 15:28   ` Ard Biesheuvel
  0 siblings, 0 replies; 75+ messages in thread
From: Ard Biesheuvel @ 2017-03-31 15:28 UTC (permalink / raw)
  To: linux-arm-kernel

On 22 March 2017 at 14:50, Dave Martin <Dave.Martin@arm.com> wrote:

Hi Dave,

> 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.
>
[...]
> 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.
>

Without having looked at the patches in detail yet, let me reiterate
my position after we discussed this when this series was sent out the
first time around.

- The primary use case for kernel mode NEON is special purpose
instructions, i.e., AES is 20x faster when using the NEON, simply
because that is how one accesses the logic gates that implement the
AES algorithm. There is nothing SIMD or FP in nature about AES.
Compare the CRC extensions, which use scalar registers and
instructions. Of course, there are a couple of exceptions in the form
of bit-slicing algorithms, but in general, like general SIMD, I don't
think it is highly likely that SVE in kernel mode is something we will
have a need for in the foreseeable future.

- The current way of repeatedly stacking/unstacking NEON register
contents in interrupt context is highly inefficient, given that we are
usually interrupting user mode, not kernel mode, and so stacking once
and unstacking when returning from the exception (which is how we
usually deal with it) would be much better. So changing the current
implementation to perform the eager stack/unstack only when a kernel
mode NEON call is already in progress is likely to improve our current
situation already, regardless of whether such a change is needed to
accommodate SVE. Note that to my knowledge, the only in-tree users of
kernel mode NEON operate in process context or softirq context, never
in hardirq context.

Given the above, I think it is perfectly reasonable to conditionally
disallow kernel mode NEON in hardirq context. The crypto routines that
rely on it can easily be fixed up (I already wrote the patches for
that). This would only be necessary on SVE systems, and the reason for
doing so is that - given how preserving and restoring the NEON
register file blows away the upper SVE part of the registers - whoever
arrives at the SVE-aware preserve routine first should be allowed to
run to completion. This does require disabling softirqs during the
time the preserved NEON state is being manipulated but that does not
strike me as a huge price to pay. Note that both restrictions
(disallowing kernel mode NEON in hardirq context, and the need to
disable softirqs while manipulating the state) could be made runtime
dependent on whether we are actually running on an SVE system.

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [RFC PATCH v2 00/41] Scalable Vector Extension (SVE) core support
  2017-03-31 15:28   ` Ard Biesheuvel
@ 2017-04-03  9:45     ` Dave Martin
  -1 siblings, 0 replies; 75+ messages in thread
From: Dave Martin @ 2017-04-03  9:45 UTC (permalink / raw)
  To: Ard Biesheuvel
  Cc: Florian Weimer, Christoffer Dall, gdb, Marc Zyngier,
	Catalin Marinas, Yao Qi, Will Deacon, linux-kernel,
	Szabolcs Nagy, Richard Sandiford, linux-arm-kernel, Alan Hayward,
	libc-alpha, Andrew Morton, Torvald Riegel, Joseph Myers

On Fri, Mar 31, 2017 at 04:28:16PM +0100, Ard Biesheuvel wrote:
> On 22 March 2017 at 14:50, Dave Martin <Dave.Martin@arm.com> wrote:
> 
> Hi Dave,
> 
> > 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.
> >
> [...]
> > 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.
> >
> 
> Without having looked at the patches in detail yet, let me reiterate
> my position after we discussed this when this series was sent out the
> first time around.
> 
> - The primary use case for kernel mode NEON is special purpose
> instructions, i.e., AES is 20x faster when using the NEON, simply
> because that is how one accesses the logic gates that implement the
> AES algorithm. There is nothing SIMD or FP in nature about AES.
> Compare the CRC extensions, which use scalar registers and
> instructions. Of course, there are a couple of exceptions in the form
> of bit-slicing algorithms, but in general, like general SIMD, I don't
> think it is highly likely that SVE in kernel mode is something we will
> have a need for in the foreseeable future.

Certainly there is no immediate need for this, and if we decide we never
need it then that helps us avoid some complexity.

My main concern is around the extra save/restore cost, given that if
the SVE registers are live then save/restore of the full SVE vectors
is needed even if only FPSIMD is used in the meantime.

> - The current way of repeatedly stacking/unstacking NEON register
> contents in interrupt context is highly inefficient, given that we are
> usually interrupting user mode, not kernel mode, and so stacking once
> and unstacking when returning from the exception (which is how we
> usually deal with it) would be much better. So changing the current
> implementation to perform the eager stack/unstack only when a kernel
> mode NEON call is already in progress is likely to improve our current
> situation already, regardless of whether such a change is needed to
> accommodate SVE. Note that to my knowledge, the only in-tree users of
> kernel mode NEON operate in process context or softirq context, never
> in hardirq context.

Reassuring.

> Given the above, I think it is perfectly reasonable to conditionally
> disallow kernel mode NEON in hardirq context. The crypto routines that
> rely on it can easily be fixed up (I already wrote the patches for
> that). This would only be necessary on SVE systems, and the reason for
> doing so is that - given how preserving and restoring the NEON
> register file blows away the upper SVE part of the registers - whoever
> arrives at the SVE-aware preserve routine first should be allowed to
> run to completion. This does require disabling softirqs during the
> time the preserved NEON state is being manipulated but that does not
> strike me as a huge price to pay. Note that both restrictions
> (disallowing kernel mode NEON in hardirq context, and the need to
> disable softirqs while manipulating the state) could be made runtime
> dependent on whether we are actually running on an SVE system.

Given that we already bail out of kernel_neon_begin() with a WARN() if
the hardware lacks FPSIMD, I'm not sure it would be worse to do the same
if SVE is present.

However, we should probably abstract that check: currently, drivers
seemt to be using a cocktail of Kconfig dependencies,
MODULE_DEVICE_TABLE() and runtime hwcap checks in order to deduce
whether kernel_neon_begin() is safe to use.

Would you be happy with a single API for checking whether
kernel_neon_begin() works?  Maintaining this check in every driver
doesn't feel very scalable.


This would allow SVE to disable KERNEL_MODE_NEON without having to make
them conflict in Kconfig.  This wouldn't be our end goal, but it allows
the dependency to be decoupled while we figure out a better solution.

I'll try and come up with a patch.

Cheers
---Dave

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [RFC PATCH v2 00/41] Scalable Vector Extension (SVE) core support
@ 2017-04-03  9:45     ` Dave Martin
  0 siblings, 0 replies; 75+ messages in thread
From: Dave Martin @ 2017-04-03  9:45 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Mar 31, 2017 at 04:28:16PM +0100, Ard Biesheuvel wrote:
> On 22 March 2017 at 14:50, Dave Martin <Dave.Martin@arm.com> wrote:
> 
> Hi Dave,
> 
> > 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.
> >
> [...]
> > 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.
> >
> 
> Without having looked at the patches in detail yet, let me reiterate
> my position after we discussed this when this series was sent out the
> first time around.
> 
> - The primary use case for kernel mode NEON is special purpose
> instructions, i.e., AES is 20x faster when using the NEON, simply
> because that is how one accesses the logic gates that implement the
> AES algorithm. There is nothing SIMD or FP in nature about AES.
> Compare the CRC extensions, which use scalar registers and
> instructions. Of course, there are a couple of exceptions in the form
> of bit-slicing algorithms, but in general, like general SIMD, I don't
> think it is highly likely that SVE in kernel mode is something we will
> have a need for in the foreseeable future.

Certainly there is no immediate need for this, and if we decide we never
need it then that helps us avoid some complexity.

My main concern is around the extra save/restore cost, given that if
the SVE registers are live then save/restore of the full SVE vectors
is needed even if only FPSIMD is used in the meantime.

> - The current way of repeatedly stacking/unstacking NEON register
> contents in interrupt context is highly inefficient, given that we are
> usually interrupting user mode, not kernel mode, and so stacking once
> and unstacking when returning from the exception (which is how we
> usually deal with it) would be much better. So changing the current
> implementation to perform the eager stack/unstack only when a kernel
> mode NEON call is already in progress is likely to improve our current
> situation already, regardless of whether such a change is needed to
> accommodate SVE. Note that to my knowledge, the only in-tree users of
> kernel mode NEON operate in process context or softirq context, never
> in hardirq context.

Reassuring.

> Given the above, I think it is perfectly reasonable to conditionally
> disallow kernel mode NEON in hardirq context. The crypto routines that
> rely on it can easily be fixed up (I already wrote the patches for
> that). This would only be necessary on SVE systems, and the reason for
> doing so is that - given how preserving and restoring the NEON
> register file blows away the upper SVE part of the registers - whoever
> arrives at the SVE-aware preserve routine first should be allowed to
> run to completion. This does require disabling softirqs during the
> time the preserved NEON state is being manipulated but that does not
> strike me as a huge price to pay. Note that both restrictions
> (disallowing kernel mode NEON in hardirq context, and the need to
> disable softirqs while manipulating the state) could be made runtime
> dependent on whether we are actually running on an SVE system.

Given that we already bail out of kernel_neon_begin() with a WARN() if
the hardware lacks FPSIMD, I'm not sure it would be worse to do the same
if SVE is present.

However, we should probably abstract that check: currently, drivers
seemt to be using a cocktail of Kconfig dependencies,
MODULE_DEVICE_TABLE() and runtime hwcap checks in order to deduce
whether kernel_neon_begin() is safe to use.

Would you be happy with a single API for checking whether
kernel_neon_begin() works?  Maintaining this check in every driver
doesn't feel very scalable.


This would allow SVE to disable KERNEL_MODE_NEON without having to make
them conflict in Kconfig.  This wouldn't be our end goal, but it allows
the dependency to be decoupled while we figure out a better solution.

I'll try and come up with a patch.

Cheers
---Dave

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [RFC PATCH v2 00/41] Scalable Vector Extension (SVE) core support
  2017-04-03  9:45     ` Dave Martin
@ 2017-04-03 10:01       ` Ard Biesheuvel
  -1 siblings, 0 replies; 75+ messages in thread
From: Ard Biesheuvel @ 2017-04-03 10:01 UTC (permalink / raw)
  To: Dave Martin
  Cc: Florian Weimer, Christoffer Dall, gdb, Marc Zyngier,
	Catalin Marinas, Yao Qi, Will Deacon, linux-kernel,
	Szabolcs Nagy, Richard Sandiford, linux-arm-kernel, Alan Hayward,
	libc-alpha, Andrew Morton, Torvald Riegel, Joseph Myers

On 3 April 2017 at 10:45, Dave Martin <Dave.Martin@arm.com> wrote:
> On Fri, Mar 31, 2017 at 04:28:16PM +0100, Ard Biesheuvel wrote:
>> On 22 March 2017 at 14:50, Dave Martin <Dave.Martin@arm.com> wrote:
>>
>> Hi Dave,
>>
>> > 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.
>> >
>> [...]
>> > 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.
>> >
>>
>> Without having looked at the patches in detail yet, let me reiterate
>> my position after we discussed this when this series was sent out the
>> first time around.
>>
>> - The primary use case for kernel mode NEON is special purpose
>> instructions, i.e., AES is 20x faster when using the NEON, simply
>> because that is how one accesses the logic gates that implement the
>> AES algorithm. There is nothing SIMD or FP in nature about AES.
>> Compare the CRC extensions, which use scalar registers and
>> instructions. Of course, there are a couple of exceptions in the form
>> of bit-slicing algorithms, but in general, like general SIMD, I don't
>> think it is highly likely that SVE in kernel mode is something we will
>> have a need for in the foreseeable future.
>
> Certainly there is no immediate need for this, and if we decide we never
> need it then that helps us avoid some complexity.
>
> My main concern is around the extra save/restore cost, given that if
> the SVE registers are live then save/restore of the full SVE vectors
> is needed even if only FPSIMD is used in the meantime.
>
>> - The current way of repeatedly stacking/unstacking NEON register
>> contents in interrupt context is highly inefficient, given that we are
>> usually interrupting user mode, not kernel mode, and so stacking once
>> and unstacking when returning from the exception (which is how we
>> usually deal with it) would be much better. So changing the current
>> implementation to perform the eager stack/unstack only when a kernel
>> mode NEON call is already in progress is likely to improve our current
>> situation already, regardless of whether such a change is needed to
>> accommodate SVE. Note that to my knowledge, the only in-tree users of
>> kernel mode NEON operate in process context or softirq context, never
>> in hardirq context.
>
> Reassuring.
>
>> Given the above, I think it is perfectly reasonable to conditionally
>> disallow kernel mode NEON in hardirq context. The crypto routines that
>> rely on it can easily be fixed up (I already wrote the patches for
>> that). This would only be necessary on SVE systems, and the reason for
>> doing so is that - given how preserving and restoring the NEON
>> register file blows away the upper SVE part of the registers - whoever
>> arrives at the SVE-aware preserve routine first should be allowed to
>> run to completion. This does require disabling softirqs during the
>> time the preserved NEON state is being manipulated but that does not
>> strike me as a huge price to pay. Note that both restrictions
>> (disallowing kernel mode NEON in hardirq context, and the need to
>> disable softirqs while manipulating the state) could be made runtime
>> dependent on whether we are actually running on an SVE system.
>
> Given that we already bail out of kernel_neon_begin() with a WARN() if
> the hardware lacks FPSIMD, I'm not sure it would be worse to do the same
> if SVE is present.
>
> However, we should probably abstract that check: currently, drivers
> seemt to be using a cocktail of Kconfig dependencies,
> MODULE_DEVICE_TABLE() and runtime hwcap checks in order to deduce
> whether kernel_neon_begin() is safe to use.
>

Not quite. The Kconfig dependencies are about
CONFIG_KERNEL_MODE_NEON=y being set, without which it is pretty
pointless to build the modules that depend on it.

The hwcap dependencies are mostly about the actual instructions
themselves, i.e., AES, PMULL, SHA1/2 etc

> Would you be happy with a single API for checking whether
> kernel_neon_begin() works?  Maintaining this check in every driver
> doesn't feel very scalable.
>

Yes, that makes sense, but it is unrelated to hwcap. I'd like to see a
kernel_neon_allowed() that would return '!IS_ENABLED(CONFIG_SVE) ||
!(elf_hwcap & HWCAP_SVE) || !in_irq()' at some point, although I
understand you want to remove the last part for now.
To short-circuit some decisions in the driver when
kernel_neon_allowed() is always true (as it would be currently),
something like kernel_neon_need_fallback() comes to mind.

>
> This would allow SVE to disable KERNEL_MODE_NEON without having to make
> them conflict in Kconfig.  This wouldn't be our end goal, but it allows
> the dependency to be decoupled while we figure out a better solution.
>

I still don't think there is a need to disable kernel mode NEON
altogether. But we can defer that decision until later, but prepare
the existing code to deal with that in the mean time.

As I mentioned, I already looked into this a while ago, so I can
quickly respin the changes to the crypto code to take this into
account.

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [RFC PATCH v2 00/41] Scalable Vector Extension (SVE) core support
@ 2017-04-03 10:01       ` Ard Biesheuvel
  0 siblings, 0 replies; 75+ messages in thread
From: Ard Biesheuvel @ 2017-04-03 10:01 UTC (permalink / raw)
  To: linux-arm-kernel

On 3 April 2017 at 10:45, Dave Martin <Dave.Martin@arm.com> wrote:
> On Fri, Mar 31, 2017 at 04:28:16PM +0100, Ard Biesheuvel wrote:
>> On 22 March 2017 at 14:50, Dave Martin <Dave.Martin@arm.com> wrote:
>>
>> Hi Dave,
>>
>> > 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.
>> >
>> [...]
>> > 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.
>> >
>>
>> Without having looked at the patches in detail yet, let me reiterate
>> my position after we discussed this when this series was sent out the
>> first time around.
>>
>> - The primary use case for kernel mode NEON is special purpose
>> instructions, i.e., AES is 20x faster when using the NEON, simply
>> because that is how one accesses the logic gates that implement the
>> AES algorithm. There is nothing SIMD or FP in nature about AES.
>> Compare the CRC extensions, which use scalar registers and
>> instructions. Of course, there are a couple of exceptions in the form
>> of bit-slicing algorithms, but in general, like general SIMD, I don't
>> think it is highly likely that SVE in kernel mode is something we will
>> have a need for in the foreseeable future.
>
> Certainly there is no immediate need for this, and if we decide we never
> need it then that helps us avoid some complexity.
>
> My main concern is around the extra save/restore cost, given that if
> the SVE registers are live then save/restore of the full SVE vectors
> is needed even if only FPSIMD is used in the meantime.
>
>> - The current way of repeatedly stacking/unstacking NEON register
>> contents in interrupt context is highly inefficient, given that we are
>> usually interrupting user mode, not kernel mode, and so stacking once
>> and unstacking when returning from the exception (which is how we
>> usually deal with it) would be much better. So changing the current
>> implementation to perform the eager stack/unstack only when a kernel
>> mode NEON call is already in progress is likely to improve our current
>> situation already, regardless of whether such a change is needed to
>> accommodate SVE. Note that to my knowledge, the only in-tree users of
>> kernel mode NEON operate in process context or softirq context, never
>> in hardirq context.
>
> Reassuring.
>
>> Given the above, I think it is perfectly reasonable to conditionally
>> disallow kernel mode NEON in hardirq context. The crypto routines that
>> rely on it can easily be fixed up (I already wrote the patches for
>> that). This would only be necessary on SVE systems, and the reason for
>> doing so is that - given how preserving and restoring the NEON
>> register file blows away the upper SVE part of the registers - whoever
>> arrives at the SVE-aware preserve routine first should be allowed to
>> run to completion. This does require disabling softirqs during the
>> time the preserved NEON state is being manipulated but that does not
>> strike me as a huge price to pay. Note that both restrictions
>> (disallowing kernel mode NEON in hardirq context, and the need to
>> disable softirqs while manipulating the state) could be made runtime
>> dependent on whether we are actually running on an SVE system.
>
> Given that we already bail out of kernel_neon_begin() with a WARN() if
> the hardware lacks FPSIMD, I'm not sure it would be worse to do the same
> if SVE is present.
>
> However, we should probably abstract that check: currently, drivers
> seemt to be using a cocktail of Kconfig dependencies,
> MODULE_DEVICE_TABLE() and runtime hwcap checks in order to deduce
> whether kernel_neon_begin() is safe to use.
>

Not quite. The Kconfig dependencies are about
CONFIG_KERNEL_MODE_NEON=y being set, without which it is pretty
pointless to build the modules that depend on it.

The hwcap dependencies are mostly about the actual instructions
themselves, i.e., AES, PMULL, SHA1/2 etc

> Would you be happy with a single API for checking whether
> kernel_neon_begin() works?  Maintaining this check in every driver
> doesn't feel very scalable.
>

Yes, that makes sense, but it is unrelated to hwcap. I'd like to see a
kernel_neon_allowed() that would return '!IS_ENABLED(CONFIG_SVE) ||
!(elf_hwcap & HWCAP_SVE) || !in_irq()' at some point, although I
understand you want to remove the last part for now.
To short-circuit some decisions in the driver when
kernel_neon_allowed() is always true (as it would be currently),
something like kernel_neon_need_fallback() comes to mind.

>
> This would allow SVE to disable KERNEL_MODE_NEON without having to make
> them conflict in Kconfig.  This wouldn't be our end goal, but it allows
> the dependency to be decoupled while we figure out a better solution.
>

I still don't think there is a need to disable kernel mode NEON
altogether. But we can defer that decision until later, but prepare
the existing code to deal with that in the mean time.

As I mentioned, I already looked into this a while ago, so I can
quickly respin the changes to the crypto code to take this into
account.

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [RFC PATCH v2 00/41] Scalable Vector Extension (SVE) core support
  2017-04-03 10:01       ` Ard Biesheuvel
@ 2017-04-03 10:51         ` Dave Martin
  -1 siblings, 0 replies; 75+ messages in thread
From: Dave Martin @ 2017-04-03 10:51 UTC (permalink / raw)
  To: Ard Biesheuvel
  Cc: Florian Weimer, Richard Sandiford, Joseph Myers, Marc Zyngier,
	gdb, Yao Qi, Alan Hayward, Will Deacon, linux-kernel,
	Szabolcs Nagy, linux-arm-kernel, Catalin Marinas, libc-alpha,
	Andrew Morton, Torvald Riegel, Christoffer Dall

On Mon, Apr 03, 2017 at 11:01:28AM +0100, Ard Biesheuvel wrote:
> On 3 April 2017 at 10:45, Dave Martin <Dave.Martin@arm.com> wrote:
> > On Fri, Mar 31, 2017 at 04:28:16PM +0100, Ard Biesheuvel wrote:

[...]

> >> Given the above, I think it is perfectly reasonable to conditionally
> >> disallow kernel mode NEON in hardirq context. The crypto routines that
> >> rely on it can easily be fixed up (I already wrote the patches for
> >> that). This would only be necessary on SVE systems, and the reason for
> >> doing so is that - given how preserving and restoring the NEON
> >> register file blows away the upper SVE part of the registers - whoever
> >> arrives at the SVE-aware preserve routine first should be allowed to
> >> run to completion. This does require disabling softirqs during the
> >> time the preserved NEON state is being manipulated but that does not
> >> strike me as a huge price to pay. Note that both restrictions
> >> (disallowing kernel mode NEON in hardirq context, and the need to
> >> disable softirqs while manipulating the state) could be made runtime
> >> dependent on whether we are actually running on an SVE system.
> >
> > Given that we already bail out of kernel_neon_begin() with a WARN() if
> > the hardware lacks FPSIMD, I'm not sure it would be worse to do the same
> > if SVE is present.
> >
> > However, we should probably abstract that check: currently, drivers
> > seemt to be using a cocktail of Kconfig dependencies,
> > MODULE_DEVICE_TABLE() and runtime hwcap checks in order to deduce
> > whether kernel_neon_begin() is safe to use.
> >
> 
> Not quite. The Kconfig dependencies are about
> CONFIG_KERNEL_MODE_NEON=y being set, without which it is pretty
> pointless to build the modules that depend on it.
> 
> The hwcap dependencies are mostly about the actual instructions
> themselves, i.e., AES, PMULL, SHA1/2 etc

Sure, there are multiple reasons why these checks are being done:
checking that kernel_neon_begin() is available is part of the reason,
but not the whole reason for some of the checks.

Doing other checks for specific ISA extensions that the driver
wants to use remains perfectly appropriate.

> > Would you be happy with a single API for checking whether
> > kernel_neon_begin() works?  Maintaining this check in every driver
> > doesn't feel very scalable.
> >
> 
> Yes, that makes sense, but it is unrelated to hwcap. I'd like to see a
> kernel_neon_allowed() that would return '!IS_ENABLED(CONFIG_SVE) ||
> !(elf_hwcap & HWCAP_SVE) || !in_irq()' at some point, although I
> understand you want to remove the last part for now.
> To short-circuit some decisions in the driver when
> kernel_neon_allowed() is always true (as it would be currently),
> something like kernel_neon_need_fallback() comes to mind.
> 
> >
> > This would allow SVE to disable KERNEL_MODE_NEON without having to make
> > them conflict in Kconfig.  This wouldn't be our end goal, but it allows
> > the dependency to be decoupled while we figure out a better solution.
> >
> 
> I still don't think there is a need to disable kernel mode NEON
> altogether. But we can defer that decision until later, but prepare
> the existing code to deal with that in the mean time.

Agreed -- given that SVE hardware won't exist in the wild for some time,
I prefer to at least have SVE buildable in defconfig without impacting
existing systems.

This means that integrating KMN with SVE could be worked on later, and
also means that the improvements to KMN already discussed can be worked
on independently without necessarily considering SVE.

> As I mentioned, I already looked into this a while ago, so I can
> quickly respin the changes to the crypto code to take this into
> account.

It would be interesting to see what that looks like.

Cheers
---Dave

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [RFC PATCH v2 00/41] Scalable Vector Extension (SVE) core support
@ 2017-04-03 10:51         ` Dave Martin
  0 siblings, 0 replies; 75+ messages in thread
From: Dave Martin @ 2017-04-03 10:51 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Apr 03, 2017 at 11:01:28AM +0100, Ard Biesheuvel wrote:
> On 3 April 2017 at 10:45, Dave Martin <Dave.Martin@arm.com> wrote:
> > On Fri, Mar 31, 2017 at 04:28:16PM +0100, Ard Biesheuvel wrote:

[...]

> >> Given the above, I think it is perfectly reasonable to conditionally
> >> disallow kernel mode NEON in hardirq context. The crypto routines that
> >> rely on it can easily be fixed up (I already wrote the patches for
> >> that). This would only be necessary on SVE systems, and the reason for
> >> doing so is that - given how preserving and restoring the NEON
> >> register file blows away the upper SVE part of the registers - whoever
> >> arrives at the SVE-aware preserve routine first should be allowed to
> >> run to completion. This does require disabling softirqs during the
> >> time the preserved NEON state is being manipulated but that does not
> >> strike me as a huge price to pay. Note that both restrictions
> >> (disallowing kernel mode NEON in hardirq context, and the need to
> >> disable softirqs while manipulating the state) could be made runtime
> >> dependent on whether we are actually running on an SVE system.
> >
> > Given that we already bail out of kernel_neon_begin() with a WARN() if
> > the hardware lacks FPSIMD, I'm not sure it would be worse to do the same
> > if SVE is present.
> >
> > However, we should probably abstract that check: currently, drivers
> > seemt to be using a cocktail of Kconfig dependencies,
> > MODULE_DEVICE_TABLE() and runtime hwcap checks in order to deduce
> > whether kernel_neon_begin() is safe to use.
> >
> 
> Not quite. The Kconfig dependencies are about
> CONFIG_KERNEL_MODE_NEON=y being set, without which it is pretty
> pointless to build the modules that depend on it.
> 
> The hwcap dependencies are mostly about the actual instructions
> themselves, i.e., AES, PMULL, SHA1/2 etc

Sure, there are multiple reasons why these checks are being done:
checking that kernel_neon_begin() is available is part of the reason,
but not the whole reason for some of the checks.

Doing other checks for specific ISA extensions that the driver
wants to use remains perfectly appropriate.

> > Would you be happy with a single API for checking whether
> > kernel_neon_begin() works?  Maintaining this check in every driver
> > doesn't feel very scalable.
> >
> 
> Yes, that makes sense, but it is unrelated to hwcap. I'd like to see a
> kernel_neon_allowed() that would return '!IS_ENABLED(CONFIG_SVE) ||
> !(elf_hwcap & HWCAP_SVE) || !in_irq()' at some point, although I
> understand you want to remove the last part for now.
> To short-circuit some decisions in the driver when
> kernel_neon_allowed() is always true (as it would be currently),
> something like kernel_neon_need_fallback() comes to mind.
> 
> >
> > This would allow SVE to disable KERNEL_MODE_NEON without having to make
> > them conflict in Kconfig.  This wouldn't be our end goal, but it allows
> > the dependency to be decoupled while we figure out a better solution.
> >
> 
> I still don't think there is a need to disable kernel mode NEON
> altogether. But we can defer that decision until later, but prepare
> the existing code to deal with that in the mean time.

Agreed -- given that SVE hardware won't exist in the wild for some time,
I prefer to at least have SVE buildable in defconfig without impacting
existing systems.

This means that integrating KMN with SVE could be worked on later, and
also means that the improvements to KMN already discussed can be worked
on independently without necessarily considering SVE.

> As I mentioned, I already looked into this a while ago, so I can
> quickly respin the changes to the crypto code to take this into
> account.

It would be interesting to see what that looks like.

Cheers
---Dave

^ permalink raw reply	[flat|nested] 75+ messages in thread

* Re: [RFC PATCH v2 00/41] Scalable Vector Extension (SVE) core support
  2017-04-03 10:51         ` Dave Martin
@ 2017-04-03 10:55           ` Ard Biesheuvel
  -1 siblings, 0 replies; 75+ messages in thread
From: Ard Biesheuvel @ 2017-04-03 10:55 UTC (permalink / raw)
  To: Dave Martin
  Cc: Florian Weimer, Richard Sandiford, Joseph Myers, Marc Zyngier,
	gdb, Yao Qi, Alan Hayward, Will Deacon, linux-kernel,
	Szabolcs Nagy, linux-arm-kernel, Catalin Marinas, libc-alpha,
	Andrew Morton, Torvald Riegel, Christoffer Dall

(- list)

On 3 April 2017 at 11:51, Dave Martin <Dave.Martin@arm.com> wrote:
> On Mon, Apr 03, 2017 at 11:01:28AM +0100, Ard Biesheuvel wrote:
>> On 3 April 2017 at 10:45, Dave Martin <Dave.Martin@arm.com> wrote:
>> > On Fri, Mar 31, 2017 at 04:28:16PM +0100, Ard Biesheuvel wrote:
>
> [...]
>
>> >> Given the above, I think it is perfectly reasonable to conditionally
>> >> disallow kernel mode NEON in hardirq context. The crypto routines that
>> >> rely on it can easily be fixed up (I already wrote the patches for
>> >> that). This would only be necessary on SVE systems, and the reason for
>> >> doing so is that - given how preserving and restoring the NEON
>> >> register file blows away the upper SVE part of the registers - whoever
>> >> arrives at the SVE-aware preserve routine first should be allowed to
>> >> run to completion. This does require disabling softirqs during the
>> >> time the preserved NEON state is being manipulated but that does not
>> >> strike me as a huge price to pay. Note that both restrictions
>> >> (disallowing kernel mode NEON in hardirq context, and the need to
>> >> disable softirqs while manipulating the state) could be made runtime
>> >> dependent on whether we are actually running on an SVE system.
>> >
>> > Given that we already bail out of kernel_neon_begin() with a WARN() if
>> > the hardware lacks FPSIMD, I'm not sure it would be worse to do the same
>> > if SVE is present.
>> >
>> > However, we should probably abstract that check: currently, drivers
>> > seemt to be using a cocktail of Kconfig dependencies,
>> > MODULE_DEVICE_TABLE() and runtime hwcap checks in order to deduce
>> > whether kernel_neon_begin() is safe to use.
>> >
>>
>> Not quite. The Kconfig dependencies are about
>> CONFIG_KERNEL_MODE_NEON=y being set, without which it is pretty
>> pointless to build the modules that depend on it.
>>
>> The hwcap dependencies are mostly about the actual instructions
>> themselves, i.e., AES, PMULL, SHA1/2 etc
>
> Sure, there are multiple reasons why these checks are being done:
> checking that kernel_neon_begin() is available is part of the reason,
> but not the whole reason for some of the checks.
>
> Doing other checks for specific ISA extensions that the driver
> wants to use remains perfectly appropriate.
>
>> > Would you be happy with a single API for checking whether
>> > kernel_neon_begin() works?  Maintaining this check in every driver
>> > doesn't feel very scalable.
>> >
>>
>> Yes, that makes sense, but it is unrelated to hwcap. I'd like to see a
>> kernel_neon_allowed() that would return '!IS_ENABLED(CONFIG_SVE) ||
>> !(elf_hwcap & HWCAP_SVE) || !in_irq()' at some point, although I
>> understand you want to remove the last part for now.
>> To short-circuit some decisions in the driver when
>> kernel_neon_allowed() is always true (as it would be currently),
>> something like kernel_neon_need_fallback() comes to mind.
>>
>> >
>> > This would allow SVE to disable KERNEL_MODE_NEON without having to make
>> > them conflict in Kconfig.  This wouldn't be our end goal, but it allows
>> > the dependency to be decoupled while we figure out a better solution.
>> >
>>
>> I still don't think there is a need to disable kernel mode NEON
>> altogether. But we can defer that decision until later, but prepare
>> the existing code to deal with that in the mean time.
>
> Agreed -- given that SVE hardware won't exist in the wild for some time,
> I prefer to at least have SVE buildable in defconfig without impacting
> existing systems.
>
> This means that integrating KMN with SVE could be worked on later, and
> also means that the improvements to KMN already discussed can be worked
> on independently without necessarily considering SVE.
>
>> As I mentioned, I already looked into this a while ago, so I can
>> quickly respin the changes to the crypto code to take this into
>> account.
>
> It would be interesting to see what that looks like.
>

This stuff is quite stale and out of date, and overloading
may_use_simd() is inappropriate since async crypto algorithms may
still prefer to defer their work to process context even if crypto is
allowed in hardirq context. But this should give you an idea

https://git.kernel.org/pub/scm/linux/kernel/git/ardb/linux.git/log/?h=arm64-sve-crypto

^ permalink raw reply	[flat|nested] 75+ messages in thread

* [RFC PATCH v2 00/41] Scalable Vector Extension (SVE) core support
@ 2017-04-03 10:55           ` Ard Biesheuvel
  0 siblings, 0 replies; 75+ messages in thread
From: Ard Biesheuvel @ 2017-04-03 10:55 UTC (permalink / raw)
  To: linux-arm-kernel

(- list)

On 3 April 2017 at 11:51, Dave Martin <Dave.Martin@arm.com> wrote:
> On Mon, Apr 03, 2017 at 11:01:28AM +0100, Ard Biesheuvel wrote:
>> On 3 April 2017 at 10:45, Dave Martin <Dave.Martin@arm.com> wrote:
>> > On Fri, Mar 31, 2017 at 04:28:16PM +0100, Ard Biesheuvel wrote:
>
> [...]
>
>> >> Given the above, I think it is perfectly reasonable to conditionally
>> >> disallow kernel mode NEON in hardirq context. The crypto routines that
>> >> rely on it can easily be fixed up (I already wrote the patches for
>> >> that). This would only be necessary on SVE systems, and the reason for
>> >> doing so is that - given how preserving and restoring the NEON
>> >> register file blows away the upper SVE part of the registers - whoever
>> >> arrives at the SVE-aware preserve routine first should be allowed to
>> >> run to completion. This does require disabling softirqs during the
>> >> time the preserved NEON state is being manipulated but that does not
>> >> strike me as a huge price to pay. Note that both restrictions
>> >> (disallowing kernel mode NEON in hardirq context, and the need to
>> >> disable softirqs while manipulating the state) could be made runtime
>> >> dependent on whether we are actually running on an SVE system.
>> >
>> > Given that we already bail out of kernel_neon_begin() with a WARN() if
>> > the hardware lacks FPSIMD, I'm not sure it would be worse to do the same
>> > if SVE is present.
>> >
>> > However, we should probably abstract that check: currently, drivers
>> > seemt to be using a cocktail of Kconfig dependencies,
>> > MODULE_DEVICE_TABLE() and runtime hwcap checks in order to deduce
>> > whether kernel_neon_begin() is safe to use.
>> >
>>
>> Not quite. The Kconfig dependencies are about
>> CONFIG_KERNEL_MODE_NEON=y being set, without which it is pretty
>> pointless to build the modules that depend on it.
>>
>> The hwcap dependencies are mostly about the actual instructions
>> themselves, i.e., AES, PMULL, SHA1/2 etc
>
> Sure, there are multiple reasons why these checks are being done:
> checking that kernel_neon_begin() is available is part of the reason,
> but not the whole reason for some of the checks.
>
> Doing other checks for specific ISA extensions that the driver
> wants to use remains perfectly appropriate.
>
>> > Would you be happy with a single API for checking whether
>> > kernel_neon_begin() works?  Maintaining this check in every driver
>> > doesn't feel very scalable.
>> >
>>
>> Yes, that makes sense, but it is unrelated to hwcap. I'd like to see a
>> kernel_neon_allowed() that would return '!IS_ENABLED(CONFIG_SVE) ||
>> !(elf_hwcap & HWCAP_SVE) || !in_irq()' at some point, although I
>> understand you want to remove the last part for now.
>> To short-circuit some decisions in the driver when
>> kernel_neon_allowed() is always true (as it would be currently),
>> something like kernel_neon_need_fallback() comes to mind.
>>
>> >
>> > This would allow SVE to disable KERNEL_MODE_NEON without having to make
>> > them conflict in Kconfig.  This wouldn't be our end goal, but it allows
>> > the dependency to be decoupled while we figure out a better solution.
>> >
>>
>> I still don't think there is a need to disable kernel mode NEON
>> altogether. But we can defer that decision until later, but prepare
>> the existing code to deal with that in the mean time.
>
> Agreed -- given that SVE hardware won't exist in the wild for some time,
> I prefer to at least have SVE buildable in defconfig without impacting
> existing systems.
>
> This means that integrating KMN with SVE could be worked on later, and
> also means that the improvements to KMN already discussed can be worked
> on independently without necessarily considering SVE.
>
>> As I mentioned, I already looked into this a while ago, so I can
>> quickly respin the changes to the crypto code to take this into
>> account.
>
> It would be interesting to see what that looks like.
>

This stuff is quite stale and out of date, and overloading
may_use_simd() is inappropriate since async crypto algorithms may
still prefer to defer their work to process context even if crypto is
allowed in hardirq context. But this should give you an idea

https://git.kernel.org/pub/scm/linux/kernel/git/ardb/linux.git/log/?h=arm64-sve-crypto

^ permalink raw reply	[flat|nested] 75+ messages in thread

end of thread, other threads:[~2017-04-03 10:55 UTC | newest]

Thread overview: 75+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
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 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 ` [RFC PATCH v2 03/41] arm64: signal: factor out signal frame record allocation Dave Martin
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 ` [RFC PATCH v2 05/41] arm64: signal: Parse extra_context during sigreturn Dave Martin
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 ` [RFC PATCH v2 07/41] arm64/sve: Allow kernel-mode NEON to be disabled in Kconfig Dave Martin
2017-03-22 14:50 ` [RFC PATCH v2 08/41] arm64/sve: Low-level save/restore code Dave Martin
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 ` [RFC PATCH v2 10/41] arm64/sve: Boot-time feature enablement Dave Martin
2017-03-22 14:50 ` [RFC PATCH v2 11/41] arm64/sve: Expand task_struct for Scalable Vector Extension state Dave Martin
2017-03-22 16:20   ` Mark Rutland
2017-03-23 10:49     ` Dave Martin
2017-03-23 11:26       ` Mark Rutland
2017-03-22 14:50 ` [RFC PATCH v2 12/41] arm64/sve: Save/restore SVE state on context switch paths Dave Martin
2017-03-22 14:50 ` [RFC PATCH v2 13/41] arm64/sve: [BROKEN] Basic support for KERNEL_MODE_NEON Dave Martin
2017-03-22 14:50 ` [RFC PATCH v2 14/41] Revert "arm64/sve: Allow kernel-mode NEON to be disabled in Kconfig" Dave Martin
2017-03-22 14:50 ` [RFC PATCH v2 15/41] arm64/sve: Restore working FPSIMD save/restore around signals Dave Martin
2017-03-22 14:50 ` [RFC PATCH v2 16/41] arm64/sve: signal: Add SVE state record to sigcontext Dave Martin
2017-03-22 14:50 ` [RFC PATCH v2 17/41] arm64/sve: signal: Dump Scalable Vector Extension registers to user stack Dave Martin
2017-03-22 14:50 ` [RFC PATCH v2 18/41] arm64/sve: signal: Restore FPSIMD/SVE state in rt_sigreturn Dave Martin
2017-03-22 14:50 ` [RFC PATCH v2 19/41] arm64/sve: Avoid corruption when replacing the SVE state Dave Martin
2017-03-22 14:50 ` [RFC PATCH v2 20/41] arm64/sve: traps: Add descriptive string for SVE exceptions Dave Martin
2017-03-22 14:50 ` [RFC PATCH v2 21/41] arm64/sve: Enable SVE on demand for userspace Dave Martin
2017-03-22 16:48   ` Mark Rutland
2017-03-23 11:24     ` Dave Martin
2017-03-23 11:30       ` Suzuki K Poulose
2017-03-23 11:52         ` Mark Rutland
2017-03-23 12:07           ` Dave Martin
2017-03-23 13:40             ` Mark Rutland
2017-03-23 13:45               ` Dave Martin
2017-03-22 14:50 ` [RFC PATCH v2 22/41] arm64/sve: Implement FPSIMD-only context for tasks not using SVE Dave Martin
2017-03-22 14:50 ` [RFC PATCH v2 23/41] arm64/sve: Move ZEN handling to the common task_fpsimd_load() path Dave Martin
2017-03-22 16:55   ` Mark Rutland
2017-03-23 11:52     ` Dave Martin
2017-03-22 14:50 ` [RFC PATCH v2 24/41] arm64/sve: Discard SVE state on system call Dave Martin
2017-03-22 17:03   ` Mark Rutland
2017-03-23 11:59     ` Dave Martin
2017-03-22 14:50 ` [RFC PATCH v2 25/41] arm64/sve: Avoid preempt_disable() during sigreturn Dave Martin
2017-03-22 14:50 ` [RFC PATCH v2 26/41] arm64/sve: Avoid stale user register state after SVE access exception Dave Martin
2017-03-22 14:50 ` [RFC PATCH v2 27/41] arm64/sve: ptrace support Dave Martin
2017-03-22 14:50 ` [RFC PATCH v2 28/41] arm64: KVM: Treat SVE use by guests as undefined instruction execution Dave Martin
2017-03-22 17:06   ` Mark Rutland
2017-03-23 12:10     ` Dave Martin
2017-03-22 14:50 ` [RFC PATCH v2 29/41] prctl: Add skeleton for PR_SVE_{SET,GET}_VL controls Dave Martin
2017-03-22 14:50   ` [RFC PATCH v2 29/41] prctl: Add skeleton for PR_SVE_{SET, GET}_VL controls Dave Martin
2017-03-22 14:51 ` [RFC PATCH v2 30/41] arm64/sve: Track vector length for each task Dave Martin
2017-03-22 14:51 ` [RFC PATCH v2 31/41] arm64/sve: Set CPU vector length to match current task Dave Martin
2017-03-22 14:51 ` [RFC PATCH v2 32/41] arm64/sve: Factor out clearing of tasks' SVE regs Dave Martin
2017-03-22 14:51 ` [RFC PATCH v2 33/41] arm64/sve: Wire up vector length control prctl() calls Dave Martin
2017-03-22 14:51   ` Dave Martin
2017-03-22 14:51 ` [RFC PATCH v2 34/41] arm64/sve: Disallow VL setting for individual threads by default Dave Martin
2017-03-22 14:51 ` [RFC PATCH v2 35/41] arm64/sve: Add vector length inheritance control Dave Martin
2017-03-22 14:51 ` [RFC PATCH v2 36/41] arm64/sve: ptrace: Wire up vector length control and reporting Dave Martin
2017-03-22 14:51 ` [RFC PATCH v2 37/41] arm64/sve: Enable default vector length control via procfs Dave Martin
2017-03-22 14:51 ` [RFC PATCH v2 38/41] arm64/sve: Detect SVE via the cpufeature framework Dave Martin
2017-03-23 14:11   ` Suzuki K Poulose
2017-03-23 14:37     ` Dave Martin
2017-03-23 14:43       ` Dave Martin
2017-03-22 14:51 ` [RFC PATCH v2 39/41] arm64/sve: Migrate to cpucap based detection for runtime SVE code Dave Martin
2017-03-22 14:51 ` [RFC PATCH v2 40/41] arm64/sve: Allocate task SVE context storage dynamically Dave Martin
2017-03-22 14:51 ` [RFC PATCH v2 41/41] arm64/sve: Documentation: Add overview of the SVE userspace ABI Dave Martin
2017-03-22 14:51   ` Dave Martin
2017-03-31 15:28 ` [RFC PATCH v2 00/41] Scalable Vector Extension (SVE) core support Ard Biesheuvel
2017-03-31 15:28   ` Ard Biesheuvel
2017-04-03  9:45   ` Dave Martin
2017-04-03  9:45     ` Dave Martin
2017-04-03 10:01     ` Ard Biesheuvel
2017-04-03 10:01       ` Ard Biesheuvel
2017-04-03 10:51       ` Dave Martin
2017-04-03 10:51         ` Dave Martin
2017-04-03 10:55         ` Ard Biesheuvel
2017-04-03 10:55           ` Ard Biesheuvel

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.