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].
The first 5 patches "arm64: signal: ..." factor out the allocation and
placement of state information in the signal frame. The first three
are prerequisites for the SVE support patches.
Patches 04-05 implement expansion of the signal frame, and may remain
controversial due to ABI break issues:
* Discussion is needed on how userspace should detect/negotiate signal
frame size in order for this expansion mechanism to be workable.
The remaining patches implement initial SVE support for Linux, with the
following limitations:
* No KVM/virtualisation support for guests.
* No independent SVE vector length configuration per thread. This is
planned, but will follow as a separate add-on series.
* As a temporary workaround for the signal frame size issue, vector
length is software-limited to 512 bits (see patch 29), with a
build-time kernel configuration option to relax this.
Discussion is needed on how to smooth address the signal ABI issues
so that this workaround can be removed.
* A fair number of development BUG_ON()s are still present, which
will be demoted or removed for merge.
* There is a context-switch race condition lurking somewhere which
fires in certain situations with my development KVM hacks (not part
of this posting) -- the underlying bug might or might not be in this
series.
Review and comments welcome.
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/2016-November/thread.html
Alan Hayward (1):
arm64/sve: ptrace support
Dave Martin (28):
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: 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
arm64/sve: Limit vector length to 512 bits by default
arch/arm64/Kconfig | 48 +++
arch/arm64/include/asm/esr.h | 3 +-
arch/arm64/include/asm/fpsimd.h | 37 +++
arch/arm64/include/asm/fpsimdmacros.h | 145 +++++++++
arch/arm64/include/asm/kvm_arm.h | 1 +
arch/arm64/include/asm/sysreg.h | 11 +
arch/arm64/include/asm/thread_info.h | 2 +
arch/arm64/include/uapi/asm/hwcap.h | 1 +
arch/arm64/include/uapi/asm/ptrace.h | 125 ++++++++
arch/arm64/include/uapi/asm/sigcontext.h | 117 ++++++++
arch/arm64/kernel/cpufeature.c | 3 +
arch/arm64/kernel/cpuinfo.c | 1 +
arch/arm64/kernel/entry-fpsimd.S | 17 ++
arch/arm64/kernel/entry.S | 18 +-
arch/arm64/kernel/fpsimd.c | 301 ++++++++++++++++++-
arch/arm64/kernel/head.S | 16 +-
arch/arm64/kernel/process.c | 2 +-
arch/arm64/kernel/ptrace.c | 254 +++++++++++++++-
arch/arm64/kernel/setup.c | 3 +
arch/arm64/kernel/signal.c | 497 +++++++++++++++++++++++++++++--
arch/arm64/kernel/signal32.c | 2 +-
arch/arm64/kernel/traps.c | 1 +
arch/arm64/kvm/handle_exit.c | 9 +
arch/arm64/mm/proc.S | 27 +-
include/uapi/linux/elf.h | 1 +
25 files changed, 1583 insertions(+), 59 deletions(-)
--
2.1.4
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(-)
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 sizeof 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(-)
@@ -49,8 +50,39 @@ struct rt_sigframe {structrt_sigframe_user_layout{structrt_sigframe__user*sigframe;++unsignedlongsize;/* size of allocated sigframe data */+unsignedlonglimit;/* largest allowed size */++unsignedlongfpsimd_offset;+unsignedlongesr_offset;+unsignedlongend_offset;};+staticvoidinit_user_layout(structrt_sigframe_user_layout*user)+{+memset(user,0,sizeof(*user));+user->size=offsetof(structrt_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 */+}++staticsize_tsigframe_size(structrt_sigframe_user_layoutconst*user)+{+returnround_up(max(user->size,sizeof(structrt_sigframe)),16);+}++staticvoid__user*apply_user_offset(+structrt_sigframe_user_layoutconst*user,unsignedlongoffset)+{+char__user*base=(char__user*)user->sigframe;++returnbase+offset;+}+staticintpreserve_fpsimd_context(structfpsimd_context__user*ctx){structfpsimd_state*fpsimd=¤t->thread.fpsimd_state;
@@ -106,26 +138,35 @@ static int parse_user_sigframe(struct user_ctxs *user,structrt_sigframe__user*sf){structsigcontext__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_toffset=0;+size_tlimit=sizeof(sc->__reserved);user->fpsimd=NULL;+if(!IS_ALIGNED((unsignedlong)base,16))+gotoinvalid;+while(1){-interr;+interr=0;u32magic,size;-head=(struct_aarch64_ctx__user*)&sc->__reserved[offset];-if(!IS_ALIGNED((unsignedlong)head,16))+if(limit-offset<sizeof(*head))gotoinvalid;-err=0;+if(!IS_ALIGNED(offset,16))+gotoinvalid;++head=(struct_aarch64_ctx__user*)(base+offset);__get_user_error(magic,&head->magic,err);__get_user_error(size,&head->size,err);if(err)returnerr;+if(limit-offset<size)+gotoinvalid;+switch(magic){case0:if(size)
@@ -137,9 +178,7 @@ static int parse_user_sigframe(struct user_ctxs *user,if(user->fpsimd)gotoinvalid;-if(offset>sizeof(sc->__reserved)--sizeof(*user->fpsimd)||-size<sizeof(*user->fpsimd))+if(size<sizeof(*user->fpsimd))gotoinvalid;user->fpsimd=(structfpsimd_context__user*)head;
@@ -156,7 +195,7 @@ static int parse_user_sigframe(struct user_ctxs *user,if(size<sizeof(*head))gotoinvalid;-if(size>sizeof(sc->__reserved)-(sizeof(*head)+offset))+if(limit-offset<size)gotoinvalid;offset+=size;
@@ -241,13 +280,30 @@ asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)return0;}+/* Determine the layout of optional records in the signal frame */+staticintsetup_sigframe_layout(structrt_sigframe_user_layout*user)+{+user->fpsimd_offset=user->size;+user->size+=round_up(sizeof(structfpsimd_context),16);++/* fault information, if valid */+if(current->thread.fault_code){+user->esr_offset=user->size;+user->size+=round_up(sizeof(structesr_context),16);+}++/* set the "end" magic */+user->end_offset=user->size;++return0;+}++staticintsetup_sigframe(structrt_sigframe_user_layout*user,structpt_regs*regs,sigset_t*set){inti,err=0;structrt_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){-structfpsimd_context*fpsimd_ctx=-container_of(aux,structfpsimd_context,head);+structfpsimd_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){-structesr_context*esr_ctx=-container_of(aux,structesr_context,head);+if(err==0&&user->esr_offset){+structesr_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);+}returnerr;}
@@ -293,10 +352,15 @@ static int get_sigframe(struct rt_sigframe_user_layout *user,structksignal*ksig,structpt_regs*regs){unsignedlongsp,sp_top;+interr;-sp=sp_top=sigsp(regs->sp,ksig);+init_user_layout(user);+err=setup_sigframe_layout(user);+if(err)+returnerr;-sp=(sp-sizeof(structrt_sigframe))&~15;+sp=sp_top=sigsp(regs->sp,ksig);+sp=(sp&~15)-sigframe_size(user);user->sigframe=(structrt_sigframe__user*)sp;/*
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(-)
@@ -283,19 +299,32 @@ asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)/* Determine the layout of optional records in the signal frame */staticintsetup_sigframe_layout(structrt_sigframe_user_layout*user){-user->fpsimd_offset=user->size;-user->size+=round_up(sizeof(structfpsimd_context),16);+interr;++err=sigframe_alloc(user,&user->fpsimd_offset,+sizeof(structfpsimd_context));+if(err)+returnerr;/* fault information, if valid */if(current->thread.fault_code){-user->esr_offset=user->size;-user->size+=round_up(sizeof(structesr_context),16);+err=sigframe_alloc(user,&user->esr_offset,+sizeof(structesr_context));+if(err)+returnerr;}-/* set the "end" magic */-user->end_offset=user->size;+/*+*Allocatespacefortheterminatorrecord.+*HACK:hereweundothereservationofspacefortheendrecord.+*Thisbodgeshouldbereplacedwithacleanerapproachlateron.+*/+user->limit=offsetof(structrt_sigframe,uc.uc_mcontext.__reserved)++sizeof(user->sigframe->uc.uc_mcontext.__reserved);-return0;+err=sigframe_alloc(user,&user->end_offset,+sizeof(struct_aarch64_ctx));+returnerr;}
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(-)
@@ -61,4 +61,31 @@ struct esr_context {__u64esr;};+/*+*Pointertoextraspaceforadditionalstructuresthatdon'tfitin+*sigcontext.__reserved[].Note:+*+*1)fpsimd_context,esr_contextandextra_contextmustbeplacedin+*sigcontext.__reserved[]ifpresent.Theycannotbeplacedinthe+*extraspace.Anyotherrecordcanbeplacedeitherintheextra+*spaceorinsigcontext.__reserved[].+*+*2)Theremustnotbemorethanoneextra_context.+*+*3)Ifextra_contextispresent,itmustbefollowedimmediatelyin+*sigcontext.__reserved[]bytheterminatingnull_aarch64_ctx(i.e.,+*extra_contextmustbethelastrecordinsigcontext.__reserved[]+*exceptfortheterminator).+*+*4)Theextraspacemustitselfbeterminatedwithanull+*_aarch64_ctx.+*/+#define EXTRA_MAGIC 0x45585401++structextra_context{+struct_aarch64_ctxhead;+void*data;/* 16-byte aligned pointer to the extra space */+__u32size;/* size in bytes of the extra space */+};+#endif /* _UAPI__ASM_SIGCONTEXT_H */
@@ -56,18 +57,22 @@ struct rt_sigframe_user_layout {unsignedlongfpsimd_offset;unsignedlongesr_offset;+unsignedlongextra_offset;unsignedlongend_offset;};staticvoidinit_user_layout(structrt_sigframe_user_layout*user){+constsize_t__reserved_size=+sizeof(user->sigframe->uc.uc_mcontext.__reserved);+constsize_tterminator_size=+round_up(sizeof(struct_aarch64_ctx),16);+memset(user,0,sizeof(*user));user->size=offsetof(structrt_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(structextra_context));+/* Reserve space for extension and terminator ^ */}staticsize_tsigframe_size(structrt_sigframe_user_layoutconst*user)
@@ -75,6 +80,49 @@ static size_t sigframe_size(struct rt_sigframe_user_layout const *user)returnround_up(max(user->size,sizeof(structrt_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++staticint__sigframe_alloc(structrt_sigframe_user_layout*user,+unsignedlong*offset,size_tsize,boolextend)+{+size_tpadded_size=round_up(size,16);++if(padded_size>user->limit-user->size&&+!user->extra_offset&&+extend){+intret;++ret=__sigframe_alloc(user,&user->extra_offset,+sizeof(structextra_context),false);+if(ret)+returnret;++/*+*Furtherallocationsmustgoafterthefixed-size+*partofthesignalframe:+*/+user->size=round_up(sizeof(structrt_sigframe),16);++/*+*AllowexpansionuptoSIGFRAME_MAXSZ,ensuringspacefor+*theterminator:+*/+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;++return0;+}+/**Allocatespaceforanoptionalrecordof<size>bytesintheuser*signalframe.Theoffsetfromthesignalframebaseaddresstothe
@@ -83,11 +131,26 @@ static size_t sigframe_size(struct rt_sigframe_user_layout const *user)staticintsigframe_alloc(structrt_sigframe_user_layout*user,unsignedlong*offset,size_tsize){-size_tpadded_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 */+staticintsigframe_alloc_end(structrt_sigframe_user_layout*user)+{+intret;+constsize_tterminator_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)+returnret;+/* Prevent further allocation: */+user->limit=user->size;return0;}
@@ -314,17 +377,7 @@ static int setup_sigframe_layout(struct rt_sigframe_user_layout *user)returnerr;}-/*-*Allocatespacefortheterminatorrecord.-*HACK:hereweundothereservationofspacefortheendrecord.-*Thisbodgeshouldbereplacedwithacleanerapproachlateron.-*/-user->limit=offsetof(structrt_sigframe,uc.uc_mcontext.__reserved)+-sizeof(user->sigframe->uc.uc_mcontext.__reserved);--err=sigframe_alloc(user,&user->end_offset,-sizeof(struct_aarch64_ctx));-returnerr;+returnsigframe_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){+structextra_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(structrt_sigframe),16));+u32extra_size=round_up(user->size,16)-+round_up(sizeof(structrt_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=
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(+)
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(+)
On 25 November 2016 at 19:38, Dave Martin [off-list ref] wrote:
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>
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(-)
@@ -268,6 +265,10 @@ endmenumenu"Kernel Features"+configKERNEL_MODE_NEON+bool"Support NEON/FPSIMD code in the kernel"+defaulty+menu"ARM errata workarounds via the alternatives framework"configARM64_ERRATUM_826319
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(+)
@@ -876,6 +876,18 @@ config ARM64_UAOendmenu+configARM64_SVE+bool"ARM Scalable Vector Extension support"+defaulty+depends on!KERNEL_MODE_NEON# until it works with SVE+help+TheScalableVectorExtension(SVE)isanextensiontotheAArch64+executionstatewhichcomplementsandextendstheSIMDfunctionality+ofthebasearchitecturetosupportmuchlargervectorsandtoenable+additionalvectorisationopportunities.++ToenableuseofthisextensiononCPUsthatimplementit,sayY.+configARM64_MODULE_CMODEL_LARGEbool
@@ -131,3 +131,148 @@ldpq0,q1,[\state,#-16*0-16]0:.endm++.macro_check_regnr+.if(\nr)<0||(\nr)>31+.error"Bad register number \nr."+.endif+.endm++.macro_check_zregznr+.if(\znr)<0||(\znr)>31+.error"Bad Scalable Vector Extension vector register number \znr."+.endif+.endm++.macro_check_pregpnr+.if(\pnr)<0||(\pnr)>15+.error"Bad Scalable Vector Extension predicate register number \pnr."+.endif+.endm++.macro_check_numn,min,max+.if(\n)<(\min)||(\n)>(\max)+.error"Number \n out of range [\min,\max]"+.endif+.endm++.macro_zstrvznt,nspb,ioff=0+_check_zreg\znt+_check_reg\nspb+_check_num(\ioff),-0x100,0xff+.inst0xe5804000\+|(\znt)\+|((\nspb)<<5)\+|(((\ioff)&7)<<10)\+|(((\ioff)&0x1f8)<<13)+.endm++.macro_zldrvznt,nspb,ioff=0+_check_zreg\znt+_check_reg\nspb+_check_num(\ioff),-0x100,0xff+.inst0x85804000\+|(\znt)\+|((\nspb)<<5)\+|(((\ioff)&7)<<10)\+|(((\ioff)&0x1f8)<<13)+.endm++.macro_zstrppnt,nspb,ioff=0+_check_preg\pnt+_check_reg\nspb+_check_num(\ioff),-0x100,0xff+.inst0xe5800000\+|(\pnt)\+|((\nspb)<<5)\+|(((\ioff)&7)<<10)\+|(((\ioff)&0x1f8)<<13)+.endm++.macro_zldrppnt,nspb,ioff=0+_check_preg\pnt+_check_reg\nspb+_check_num(\ioff),-0x100,0xff+.inst0x85800000\+|(\pnt)\+|((\nspb)<<5)\+|(((\ioff)&7)<<10)\+|(((\ioff)&0x1f8)<<13)+.endm++.macro_zrdvlnspd,is1+_check_reg\nspd+_check_num(\is1),-0x20,0x1f+.inst0x04bf5000\+|(\nspd)\+|(((\is1)&0x3f)<<5)+.endm++.macro_zrdffrpnd+_check_preg\pnd+.inst0x2519f000\+|(\pnd)+.endm++.macro_zwrffrpnd+_check_preg\pnd+.inst0x25289000\+|((\pnd)<<5)+.endm++.macroforfrom,to,insn+.if(\from)>=(\to)+\insn(\from)+.exitm+.endif++for\from,((\from)+(\to))/2,\insn+for((\from)+(\to))/2+1,\to,\insn+.endm++.macrosve_savenb,xpfpsr,ntmp+.macrosavezn+_zstrv\n,\nb,(\n)-34+.endm++.macrosavepn+_zstrp\n,\nb,(\n)-16+.endm++for0,31,savez+for0,15,savep+_zrdffr0+_zstrp0,\nb+_zldrp0,\nb,-16++mrsx\ntmp,fpsr+strw\ntmp,[\xpfpsr]+mrsx\ntmp,fpcr+strw\ntmp,[\xpfpsr,#4]++.purgemsavez+.purgemsavep+.endm++.macrosve_loadnb,xpfpsr,ntmp+.macroloadzn+_zldrv\n,\nb,(\n)-34+.endm++.macroloadpn+_zldrp\n,\nb,(\n)-16+.endm++for0,31,loadz+_zldrp0,\nb+_zwrffr0+for0,15,loadp++ldrw\ntmp,[\xpfpsr]+msrfpsr,x\ntmp+ldrw\ntmp,[\xpfpsr,#4]+msrfpcr,x\ntmp++.purgemloadz+.purgemloadp+.endm
@@ -572,9 +572,23 @@ CPU_LE( movk x0, #0x30d0, lsl #16 ) // Clear EE and E0E on LE systems/*Coprocessortraps.*/movx0,#0x33ff++/*SVEregisteraccess*/+mrsx1,id_aa64pfr0_el1+ubfxx1,x1,#ID_AA64PFR0_SVE_SHIFT, #4+cbzx1,4f++bicx0,x0,#CPTR_EL2_TZ // Disable SVE traps to EL2msrcptr_el2,x0//Disablecopro.trapstoEL2-1:+isb++mrs_sx1,ZIDR_EL1//ScalableVectorExtension:+andx1,x1,#ZCR_EL1_LEN_MASK // Enable full vector length+msr_sZCR_EL2,x1//forEL1.+b1f+4:msrcptr_el2,x0//Disablecopro.trapstoEL2+1:#ifdef CONFIG_COMPATmsrhstr_el2,xzr//DisableCP15trapstoEL2#endif
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 | 12 +++++++
arch/arm64/kernel/fpsimd.c | 71 ++++++++++++++++++++++++++++++++++++++++-
arch/arm64/kernel/process.c | 2 +-
arch/arm64/kernel/setup.c | 3 ++
5 files changed, 87 insertions(+), 2 deletions(-)
@@ -51,6 +51,15 @@ struct fpsimd_partial_state {__uint128_tvregs[32];};+/*+*ScalableVectorExtensionstatestructuretemplate.+*Thelayoutisvectorlengthdependent,withvectorlength=vl*16bytes.+*/+#define fpsimd_sve_state(vl) { \+__uint128_tzregs[32][vl];\+u16pregs[16][vl];\+u16ffr[vl];\+}#if defined(__KERNEL__) && defined(CONFIG_COMPAT)/* Masks for extracting the FPSR and FPCR from the FPSCR */
@@ -125,6 +126,47 @@ void do_fpsimd_exc(unsigned int esr, struct pt_regs *regs)send_sig_info(SIGFPE,&info,current);}+#ifdef CONFIG_ARM64_SVE++staticvoid*__task_sve_state(structtask_struct*task)+{+return(char*)task+ALIGN(sizeof(*task),16);+}++staticvoid*__task_pffr(structtask_struct*task)+{+unsignedintvl=sve_get_vl();++BUG_ON(vl%16);+return(char*)__task_sve_state(task)+34*vl;+}++#else /* !CONFIG_ARM64_SVE */++/* Turn any non-optimised out attempts to use these into a link error: */+externvoid*__task_sve_state(structtask_struct*task);+externvoid*__task_pffr(structtask_struct*task);++#endif /* !CONFIG_ARM64_SVE */++staticvoidtask_fpsimd_load(structtask_struct*task)+{+if(IS_ENABLED(CONFIG_ARM64_SVE)&&(elf_hwcap&HWCAP_SVE))+sve_load_state(__task_pffr(task),+&task->thread.fpsimd_state.fpsr);+else+fpsimd_load_state(&task->thread.fpsimd_state);+}++staticvoidtask_fpsimd_save(structtask_struct*task)+{+if(IS_ENABLED(CONFIG_ARM64_SVE)&&(elf_hwcap&HWCAP_SVE))+sve_save_state(__task_pffr(task),+&task->thread.fpsimd_state.fpsr);+else+fpsimd_save_state(&task->thread.fpsimd_state);+}+voidfpsimd_thread_switch(structtask_struct*next){/*
@@ -315,6 +369,21 @@ static inline void fpsimd_hotplug_init(void)staticinlinevoidfpsimd_hotplug_init(void){}#endif+void__initfpsimd_init_task_struct_size(void)+{+arch_task_struct_size=sizeof(structtask_struct);++if(IS_ENABLED(CONFIG_ARM64_SVE)&&+((read_cpuid(ID_AA64PFR0_EL1)>>ID_AA64PFR0_SVE_SHIFT)+&0xf)==1){+arch_task_struct_size=sizeof(structtask_struct)++35*sve_get_vl();++pr_info("SVE: enabled with maximum %u bits per vector\n",+sve_get_vl()*8);+}+}+/**FP/SIMDsupportcodeinitialisation.*/
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(-)
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.
Signed-off-by: Dave Martin <Dave.Martin@arm.com>
---
arch/arm64/Kconfig | 1 -
arch/arm64/kernel/fpsimd.c | 22 ++++++++++++++++++----
2 files changed, 18 insertions(+), 5 deletions(-)
@@ -880,7 +880,6 @@ endmenuconfigARM64_SVEbool"ARM Scalable Vector Extension support"defaulty-depends on!KERNEL_MODE_NEON# until it works with SVEhelpTheScalableVectorExtension(SVE)isanextensiontotheAArch64executionstatewhichcomplementsandextendstheSIMDfunctionality
On 25 November 2016 at 19:39, Dave Martin [off-list ref] wrote:
quoted hunk
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.
Signed-off-by: Dave Martin <Dave.Martin@arm.com>
---
arch/arm64/Kconfig | 1 -
arch/arm64/kernel/fpsimd.c | 22 ++++++++++++++++++----
2 files changed, 18 insertions(+), 5 deletions(-)
@@ -880,7 +880,6 @@ endmenuconfigARM64_SVEbool"ARM Scalable Vector Extension support"defaulty-depends on!KERNEL_MODE_NEON# until it works with SVEhelpTheScalableVectorExtension(SVE)isanextensiontotheAArch64executionstatewhichcomplementsandextendstheSIMDfunctionality
I am having trouble understanding why we need all of this if we don't
support SVE in the kernel. Could you elaborate?
quoted hunk
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 {
/*
@@ -295,7 +310,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(¤t->thread.fpsimd_state);
On Fri, Nov 25, 2016 at 08:45:02PM +0000, Ard Biesheuvel wrote:
On 25 November 2016 at 19:39, Dave Martin [off-list ref] wrote:
quoted
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.
Signed-off-by: Dave Martin <Dave.Martin@arm.com>
---
arch/arm64/Kconfig | 1 -
arch/arm64/kernel/fpsimd.c | 22 ++++++++++++++++++----
2 files changed, 18 insertions(+), 5 deletions(-)
@@ -880,7 +880,6 @@ endmenuconfigARM64_SVEbool"ARM Scalable Vector Extension support"defaulty-depends on!KERNEL_MODE_NEON# until it works with SVEhelpTheScalableVectorExtension(SVE)isanextensiontotheAArch64executionstatewhichcomplementsandextendstheSIMDfunctionality
I am having trouble understanding why we need all of this if we don't
support SVE in the kernel. Could you elaborate?
Dave knows all the details but a reason is that touching a Neon register
zeros the upper SVE state in the same vector register. So we can't
safely save/restore just the Neon part without corrupting the SVE state.
--
Catalin
On Sat, Nov 26, 2016 at 11:30:42AM +0000, Catalin Marinas wrote:
On Fri, Nov 25, 2016 at 08:45:02PM +0000, Ard Biesheuvel wrote:
quoted
On 25 November 2016 at 19:39, Dave Martin [off-list ref] wrote:
quoted
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.
Signed-off-by: Dave Martin <Dave.Martin@arm.com>
---
arch/arm64/Kconfig | 1 -
arch/arm64/kernel/fpsimd.c | 22 ++++++++++++++++++----
2 files changed, 18 insertions(+), 5 deletions(-)
@@ -880,7 +880,6 @@ endmenuconfigARM64_SVEbool"ARM Scalable Vector Extension support"defaulty-depends on!KERNEL_MODE_NEON# until it works with SVEhelpTheScalableVectorExtension(SVE)isanextensiontotheAArch64executionstatewhichcomplementsandextendstheSIMDfunctionality
I am having trouble understanding why we need all of this if we don't
support SVE in the kernel. Could you elaborate?
Dave knows all the details but a reason is that touching a Neon register
zeros the upper SVE state in the same vector register. So we can't
safely save/restore just the Neon part without corrupting the SVE state.
This is right -- this also means that EFI services can trash the upper
bits of an SVE vector register (as a side-effect of FPSIMD/NEON usage).
It's overkill to save/restore absolutely everything -- I ignore num_regs
for example -- but I wanted to keep things as simple as possible
initially.
Cheers
---Dave
I am having trouble understanding why we need all of this if we don't
support SVE in the kernel. Could you elaborate?
Dave knows all the details but a reason is that touching a Neon register
zeros the upper SVE state in the same vector register. So we can't
safely save/restore just the Neon part without corrupting the SVE state.
This is right -- this also means that EFI services can trash the upper
bits of an SVE vector register (as a side-effect of FPSIMD/NEON usage).
It's overkill to save/restore absolutely everything -- I ignore num_regs
for example -- but I wanted to keep things as simple as possible
initially.
Without looking at your patches in detail, could we mandate in the ABI
that the SVE state is lost on the user/kernel syscall boundary? I guess
even for the PCS, the SVE state is caller-saved, so there shouldn't be
an additional cost to user. On interrupts, however, we'd have to
preserve the SVE state but if we do this on entry/exit points, the
kernel_neon_*() functions would not have to deal with any SVE state (and
even ignore it completely if in interrupt).
BTW, we will need an SVE ABI document in Documentation/arm64/ to specify
the requirements for syscall and sigcontext modifications.
--
Catalin
I am having trouble understanding why we need all of this if we don't
support SVE in the kernel. Could you elaborate?
Dave knows all the details but a reason is that touching a Neon register
zeros the upper SVE state in the same vector register. So we can't
safely save/restore just the Neon part without corrupting the SVE state.
This is right -- this also means that EFI services can trash the upper
bits of an SVE vector register (as a side-effect of FPSIMD/NEON usage).
It's overkill to save/restore absolutely everything -- I ignore num_regs
for example -- but I wanted to keep things as simple as possible
initially.
Without looking at your patches in detail, could we mandate in the ABI
that the SVE state is lost on the user/kernel syscall boundary? I guess
even for the PCS, the SVE state is caller-saved, so there shouldn't be
an additional cost to user. On interrupts, however, we'd have to
preserve the SVE state but if we do this on entry/exit points, the
kernel_neon_*() functions would not have to deal with any SVE state (and
even ignore it completely if in interrupt).
See [RFC PATCH 24/29] arm64/sve: Discard SVE state on system call.
Currently, kernel_neon_begin_partial() doesn't take advandage of this --
discarding the state is deferred until sched-out, and anyway I don't
check for TIF_SVE in kernel_neon_begin_partial(). There's definitely
some room for improvement.
the requirements for syscall and sigcontext modifications.
Agreed -- I wanted to get this series posted so skipped that for now,
but I plan to include a Documentation patch alongside the final series.
Cheers
---Dave
I am having trouble understanding why we need all of this if we don't
support SVE in the kernel. Could you elaborate?
Dave knows all the details but a reason is that touching a Neon register
zeros the upper SVE state in the same vector register. So we can't
safely save/restore just the Neon part without corrupting the SVE state.
This is right -- this also means that EFI services can trash the upper
bits of an SVE vector register (as a side-effect of FPSIMD/NEON usage).
It's overkill to save/restore absolutely everything -- I ignore num_regs
for example -- but I wanted to keep things as simple as possible
initially.
Actually, I think we could simplify this even further by always
preserving the userland state, instead of having two copies of the
statements above. The reason is that stacking and unstacking, as we do
for softirq/hardirq context, is only required if we happen to be
interrupting a thread while it is executing in the kernel *and* using
the NEON, in all other cases we can simply preserve the userland
context, and let the exit code take care of restoring the state upon
exit to userland (unless we're interrupting kernel mode NEON executing
in softirq context from an interrupt handler).
i will send out a separate RFC with a proposal to optimize this, which
I think will remove the need for this patch entirely.
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(-)
@@ -266,10 +269,6 @@ endmenumenu"Kernel Features"-configKERNEL_MODE_NEON-bool"Support NEON/FPSIMD code in the kernel"-defaulty-menu"ARM errata workarounds via the alternatives framework"configARM64_ERRATUM_826319
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 | 92 ++++++++++++++++++++++++++++++++++++++++-
arch/arm64/kernel/signal.c | 2 +-
arch/arm64/kernel/signal32.c | 2 +-
4 files changed, 94 insertions(+), 3 deletions(-)
@@ -228,6 +228,52 @@ void fpsimd_preserve_current_state(void)preempt_enable();}+#ifdef CONFIG_ARM64_SVE++/* Helpers to sync task FPSIMD and SVE register views */++staticvoid__task_sve_to_fpsimd(structtask_struct*task,unsignedintvq)+{+structsve_structfpsimd_sve_state(vq)*sst=+__task_sve_state(task);+structfpsimd_state*fst=&task->thread.fpsimd_state;+unsignedinti;++for(i=0;i<32;++i)+fst->vregs[i]=sst->zregs[i][0];+}++staticvoidtask_sve_to_fpsimd(structtask_struct*task)+{+unsignedintvl=sve_get_vl();+unsignedintvq;++if(!(elf_hwcap&HWCAP_SVE))+return;++BUG_ON(vl%16);+vq=vl/16;+BUG_ON(vq<1||vq>16);++__task_sve_to_fpsimd(task,vq);+}++#else /* ! CONFIG_ARM64_SVE */++staticvoidtask_sve_to_fpsimd(structtask_struct*task__always_unused){}++#endif /* ! CONFIG_ARM64_SVE */+++voidfpsimd_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();+task_sve_to_fpsimd(current);+}+/**LoadtheuserlandFPSIMDstateof'current'frommemory,butonlyifthe*FPSIMDstatealreadyheldintheregistersis/not/themostrecentFPSIMD
@@ -246,6 +292,43 @@ void fpsimd_restore_current_state(void)preempt_enable();}++#ifdef CONFIG_ARM64_SVE++staticvoid__task_fpsimd_to_sve(structtask_struct*task,unsignedintvq)+{+structsve_structfpsimd_sve_state(vq)*sst=+__task_sve_state(task);+structfpsimd_state*fst=&task->thread.fpsimd_state;+unsignedinti;++memset(sst,0,sizeof(*sst));+for(i=0;i<32;++i)+sst->zregs[i][0]=fst->vregs[i];+}++staticvoidtask_fpsimd_to_sve(structtask_struct*task)+{+unsignedintvl=sve_get_vl();+unsignedintvq;++if(!(elf_hwcap&HWCAP_SVE))+return;++BUG_ON(vl%16);+vq=vl/16;+BUG_ON(vq<1||vq>16);++__task_fpsimd_to_sve(task,vq);+}++#else /* ! CONFIG_ARM64_SVE */++/* Turn any non-optimised out attempts to use this into a link error: */+externvoidtask_fpsimd_to_sve(structtask_struct*task);++#endif /* ! CONFIG_ARM64_SVE */+/**LoadanupdateduserlandFPSIMDstatefor'current'frommemoryandsetthe*flagthatindicatesthattheFPSIMDregistercontentsarethemostrecent
@@ -168,7 +168,7 @@ static int preserve_fpsimd_context(struct fpsimd_context __user *ctx)interr;/* 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));
@@ -244,7 +244,7 @@ static int compat_preserve_vfp_context(struct compat_vfp_sigframe __user *frame)*NotethatthisalsosavesV16-31,whicharen'tvisible*inAArch32.*/-fpsimd_preserve_current_state();+fpsimd_signal_preserve_current_state();/* Place structure header on the stack */__put_user_error(magic,&frame->magic,err);
This patch adds a record to sigcontext that will contain the SVE
state.
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/signal.c | 62 +++++++++++++++++++++++
2 files changed, 148 insertions(+)
@@ -209,8 +210,39 @@ static int restore_fpsimd_context(struct fpsimd_context __user *ctx)returnerr?-EFAULT:0;}++#ifdef CONFIG_ARM64_SVE++staticintpreserve_sve_context(structsve_context__user*ctx)+{+interr=0;+u16reserved[ARRAY_SIZE(ctx->__reserved)];+unsignedintvl=sve_get_vl();+unsignedintvq=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));++returnerr?-EFAULT:0;+}++#else /* ! CONFIG_ARM64_SVE */++/* Turn any non-optimised out attempt to use this into a link error: */+externintpreserve_sve_context(void__user*ctx);++#endif /* ! CONFIG_ARM64_SVE */++structuser_ctxs{structfpsimd_context__user*fpsimd;+structsve_context__user*sve;};staticintparse_user_sigframe(structuser_ctxs*user,
@@ -224,6 +256,7 @@ static int parse_user_sigframe(struct user_ctxs *user,boolhave_extra_context=false;user->fpsimd=NULL;+user->sve=NULL;if(!IS_ALIGNED((unsignedlong)base,16))gotoinvalid;
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 | 5 ++---
arch/arm64/kernel/signal.c | 8 ++++++++
3 files changed, 11 insertions(+), 3 deletions(-)
@@ -143,8 +143,7 @@ static void *__task_pffr(struct task_struct *task)#else /* !CONFIG_ARM64_SVE */-/* Turn any non-optimised out attempts to use these into a link error: */-externvoid*__task_sve_state(structtask_struct*task);+/* Turn any non-optimised out attempts to use this into a link error: */externvoid*__task_pffr(structtask_struct*task);#endif /* !CONFIG_ARM64_SVE */
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(-)
@@ -240,19 +245,68 @@ static int preserve_sve_context(struct sve_context __user *ctx)returnerr?-EFAULT:0;}+staticint__restore_sve_fpsimd_context(structuser_ctxs*user,+unsignedintvl,unsignedintvq)+{+interr;+structfpsimd_sve_state(vq)*task_sve_regs=+__task_sve_state(current);+structfpsimd_statefpsimd;++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__userconst*)user->sve++SVE_SIG_REGS_OFFSET,+SVE_SIG_REGS_SIZE(vq));+if(err)+returnerr;++/* 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);++returnerr;+}++staticintrestore_sve_fpsimd_context(structuser_ctxs*user)+{+interr;+u16vl,vq;++err=__get_user(vl,&user->sve->vl);+if(err)+returnerr;++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: */externintpreserve_sve_context(void__user*ctx);+externintrestore_sve_fpsimd_context(structuser_ctxs*user);#endif /* ! CONFIG_ARM64_SVE */-structuser_ctxs{-structfpsimd_context__user*fpsimd;-structsve_context__user*sve;-};-staticintparse_user_sigframe(structuser_ctxs*user,structrt_sigframe__user*sf){
@@ -316,6 +370,9 @@ static int parse_user_sigframe(struct user_ctxs *user,if(!IS_ENABLED(CONFIG_ARM64_SVE))gotoinvalid;+if(!(elf_hwcap&HWCAP_SVE))+gotoinvalid;+if(user->sve)gotoinvalid;
@@ -375,9 +432,6 @@ static int parse_user_sigframe(struct user_ctxs *user,}done:-if(!user->fpsimd)-gotoinvalid;-return0;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);+}returnerr;}
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(-)
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(-)
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 | 30 ++++++++++++++++++++++++++++++
3 files changed, 48 insertions(+), 1 deletion(-)
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 | 34 +++++++++++++++++++++++-----------
arch/arm64/kernel/signal.c | 5 ++++-
2 files changed, 27 insertions(+), 12 deletions(-)
@@ -532,6 +541,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");+return0;}late_initcall(fpsimd_init);
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 | 48 +++++++++++++++++++-----------------
2 files changed, 27 insertions(+), 22 deletions(-)
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(+)
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.
Signed-off-by: Dave Martin <Dave.Martin@arm.com>
---
arch/arm64/kernel/signal.c | 12 +++++-------
1 file changed, 5 insertions(+), 7 deletions(-)
@@ -256,10 +256,8 @@ 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);-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 +268,7 @@ static int __restore_sve_fpsimd_context(struct user_ctxs *user,SVE_SIG_REGS_OFFSET,SVE_SIG_REGS_SIZE(vq));if(err)-gotoout_preempt;+returnerr;/* copy the FP and status/control registers *//* restore_sigframe() already checked that user->fpsimd != NULL. */
@@ -279,13 +277,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();-returnerr;}
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(-)
@@ -103,22 +103,18 @@ void do_fpsimd_acc(unsigned int esr, struct pt_regs *regs)staticvoidtask_fpsimd_to_sve(structtask_struct*task);staticvoidtask_fpsimd_load(structtask_struct*task);+staticvoidtask_fpsimd_save(structtask_struct*task);voiddo_sve_acc(unsignedintesr,structpt_regs*regs){-if(test_and_set_thread_flag(TIF_SVE)){-unsignedlongtmp;--asm("mrs %0, cpacr_el1":"=r"(tmp));--printk(KERN_INFO"%s: Strange, ZEN=%u\n",-__func__,(unsignedint)((tmp>>16)&3));-BUG();-}-BUG_ON(is_compat_task());+task_fpsimd_save(current);+task_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);}
From: Alan Hayward <redacted>
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 <redacted>
Signed-off-by: Dave Martin <Dave.Martin@arm.com>
---
arch/arm64/include/asm/fpsimd.h | 20 +++
arch/arm64/include/uapi/asm/ptrace.h | 125 +++++++++++++++
arch/arm64/include/uapi/asm/sigcontext.h | 4 +
arch/arm64/kernel/fpsimd.c | 42 +++++
arch/arm64/kernel/ptrace.c | 254 ++++++++++++++++++++++++++++++-
include/uapi/linux/elf.h | 1 +
6 files changed, 440 insertions(+), 6 deletions(-)
@@ -35,6 +35,10 @@ struct fpsimd_state {__uint128_tvregs[32];u32fpsr;u32fpcr;+/*+*Forptracecompatibility,padtonext128-bit+*boundaryhereifextendingthisstruct.+*/};};/* the id of the last cpu to have restored this state */
@@ -77,6 +78,7 @@ struct user_fpsimd_state {__uint128_tvregs[32];__u32fpsr;__u32fpcr;+/* Pad to next 128-bit boundary here if extending this struct */};structuser_hwdebug_state{
@@ -89,6 +91,129 @@ struct user_hwdebug_state {}dbg_regs[16];};+/* SVE/FP/SIMD state (NT_ARM_SVE) */++structuser_sve_header{+__u32size;/* total meaningful regset content in bytes */+__u32max_size;/* maxmium possible size for this thread */+__u16vl;/* current vector length */+__u16max_vl;/* maximum possible vector length */+__u16flags;+__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+++/*+*TheremainderoftheSVEstatefollowsstructuser_sve_header.The+*totalsizeoftheSVEstate(includingheader)dependsonthe+*metadataintheheader:SVE_PT_SIZE(vq,flags)givesthetotalsize+*ofthestateinbytes,includingtheheader.+*+*Referto<asm/sigcontext.h>fordetailsofhowtopassthecorrect+*"vq"argumenttothesemacros.+*/++/* 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)++/*+*Theregisterdatacontentandlayoutdependsonthevalueofthe+*flagsfield.+*/++/*+*(flags&SVE_PT_REGS_MASK)==SVE_PT_REGS_FPSIMDcase:+*+*ThepayloadstartsatoffsetSVE_PT_FPSIMD_OFFSET,andisoftype+*structuser_fpsimd_state.Additionaldatamightbeappendedinthe+*future:useSVE_PT_FPSIMD_SIZE(vq,flags)tocomputethetotalsize.+*SVE_PT_FPSIMD_SIZE(vq,flags)willneverbelessthan+*sizeof(structuser_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_SVEcase:+*+*ThepayloadstartsatoffsetSVE_PT_SVE_OFFSET,andisofsize+*SVE_PT_SVE_SIZE(vq,flags).+*+*Additionalmacrosdescribethecontentsandlayoutofthepayload.+*Foreach,SVE_PT_SVE_x_OFFSET(args)isthestartoffsetrelativeto+*thestartofstructuser_sve_header,andSVE_PT_SVE_x_SIZE(args)is+*thesizeinbytes:+*+*xtypedescription+*----------------+*ZREGS\+*ZREG|+*PREGS|referto<asm/sigcontext.h>+*PREG|+*FFR/+*+*FPSRuint32_tFPSR+*FPCRuint32_tFPCR+*+*Additionaldatamightbeappendedinthefuture.+*/++#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)++/*+*AnyfutureextensionappendedafterFPCRmustbealignedtothenext+*128-bitboundary.+*/++#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 */
@@ -685,6 +720,204 @@ static int system_call_set(struct task_struct *target,returnret;}+#ifdef CONFIG_ARM64_SVE++staticintsve_get(structtask_struct*target,+conststructuser_regset*regset,+unsignedintpos,unsignedintcount,+void*kbuf,void__user*ubuf)+{+intret;+structuser_sve_headerheader;+unsignedintvq;+unsignedlongstart,end;++/* 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)+returnret;++/* 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*)__task_sve_state(target)<(char*)target);+BUG_ON(end<start);+BUG_ON(arch_task_struct_size<end-start);+BUG_ON((char*)__task_sve_state(target)-(char*)target>+arch_task_struct_size-(end-start));+ret=user_regset_copyout(&pos,&count,&kbuf,&ubuf,+__task_sve_state(target),+start,end);+if(ret)+returnret;++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)+returnret;++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)+returnret;++start=end;+end=(SVE_PT_SIZE(SVE_VQ_MAX,SVE_PT_REGS_SVE)+15)/16*16;+BUG_ON(end<start);++returnuser_regset_copyout_zero(&pos,&count,&kbuf,&ubuf,+start,end);+}++staticintsve_set(structtask_struct*target,+conststructuser_regset*regset,+unsignedintpos,unsignedintcount,+constvoid*kbuf,constvoid__user*ubuf)+{+intret;+structuser_sve_headerheader;+unsignedintvq;+unsignedlongstart,end;++/* Header */+ret=user_regset_copyin(&pos,&count,&kbuf,&ubuf,&header,+0,sizeof(header));+if(ret)+gotoout;++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){+ret=__fpr_set(target,regset,pos,count,kbuf,ubuf,+SVE_PT_FPSIMD_OFFSET);+clear_tsk_thread_flag(target,TIF_SVE);+gotoout;+}++/* 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*)__task_sve_state(target)<(char*)target);+BUG_ON(end<start);+BUG_ON(arch_task_struct_size<end-start);+BUG_ON((char*)__task_sve_state(target)-(char*)target>+arch_task_struct_size-(end-start));+ret=user_regset_copyin(&pos,&count,&kbuf,&ubuf,+__task_sve_state(target),+start,end);+if(ret)+gotoout;++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)+gotoout;++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);+returnret;+}++#else /* !CONFIG_ARM64_SVE */++staticintsve_get(structtask_struct*target,+conststructuser_regset*regset,+unsignedintpos,unsignedintcount,+void*kbuf,void__user*ubuf)+{+return-EINVAL;+}++staticintsve_set(structtask_struct*target,+conststructuser_regset*regset,+unsignedintpos,unsignedintcount,+constvoid*kbuf,constvoid__user*ubuf)+{+return-EINVAL;+}++#endif /* !CONFIG_ARM64_SVE */+enumaarch64_regset{REGSET_GPR,REGSET_FPR,
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 | 9 +++++++++
1 file changed, 9 insertions(+)
@@ -125,6 +125,14 @@ static int kvm_handle_guest_debug(struct kvm_vcpu *vcpu, struct kvm_run *run)returnret;}+staticinthandle_sve(structkvm_vcpu*vcpu,structkvm_run*run)+{+/* Until SVE is supported for guests: */+kvm_inject_undefined(vcpu);++return1;+}+staticexit_handle_fnarm_exit_handlers[]={[ESR_ELx_EC_WFx]=kvm_handle_wfx,[ESR_ELx_EC_CP15_32]=kvm_handle_cp15_32,
As a transitional workaround for userspace incompatibilities caused
by enlargement of the signal frame, this patch adds a new config
option CONFIG_ARM64_SVE_FULL_VECTOR_LENGTH, which default to n.
Unless this option is set to y, the vector length for SVE will be
limited to 512 bits. This leaves a bit of free space for other
architecture extensions just in case we need it.
This option will be removed and replaced with a user/kernel control
interface in the future.
Signed-off-by: Dave Martin <Dave.Martin@arm.com>
---
arch/arm64/Kconfig | 35 +++++++++++++++++++++++++++++++++++
arch/arm64/mm/proc.S | 5 +++++
2 files changed, 40 insertions(+)
Hi, Dave,
On Fri, Nov 25, 2016 at 7:38 PM, Dave Martin [off-list ref] wrote:
* No independent SVE vector length configuration per thread. This is
planned, but will follow as a separate add-on series.
If I read "independent SVE vector length configuration per thread"
correctly, SVE vector length can be different in each thread, so the
size of vector registers is different too. In GDB, we describe registers
by "target description" which is per process, not per thread.
--
Yao (??)
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].
The first 5 patches "arm64: signal: ..." factor out the allocation and
placement of state information in the signal frame. The first three
are prerequisites for the SVE support patches.
Patches 04-05 implement expansion of the signal frame, and may remain
controversial due to ABI break issues:
* Discussion is needed on how userspace should detect/negotiate signal
frame size in order for this expansion mechanism to be workable.
I'm leaning towards a simple increase in the glibc headers (despite the
ABI risk), plus a personality flag to disable really wide vector
registers in case this causes problems with old binaries.
A more elaborate mechanism will likely introduce more bugs than it makes
existing applications working, due to its complexity.
The remaining patches implement initial SVE support for Linux, with the
following limitations:
* No KVM/virtualisation support for guests.
* No independent SVE vector length configuration per thread. This is
planned, but will follow as a separate add-on series.
Per-thread register widths will likely make coroutine switching
(setcontext) and C++ resumable functions/executors quite challenging.
Can you detail your plans in this area?
Thanks,
Florian
From: Szabolcs Nagy <hidden> Date: 2016-11-30 11:05:41
On 30/11/16 10:08, Florian Weimer wrote:
On 11/25/2016 08:38 PM, Dave Martin wrote:
quoted
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].
The first 5 patches "arm64: signal: ..." factor out the allocation and
placement of state information in the signal frame. The first three
are prerequisites for the SVE support patches.
Patches 04-05 implement expansion of the signal frame, and may remain
controversial due to ABI break issues:
* Discussion is needed on how userspace should detect/negotiate signal
frame size in order for this expansion mechanism to be workable.
I'm leaning towards a simple increase in the glibc headers (despite the ABI risk), plus a personality flag to
disable really wide vector registers in case this causes problems with old binaries.
if the kernel does not increase the size and libc
does not add size checks then old binaries would
work with new libc just fine..
but that's non-conforming, posix requires the check.
if the kernel increases the size then it has to be
changed in bionic and musl as well and old binaries
may break.
A more elaborate mechanism will likely introduce more bugs than it makes existing applications working, due to
its complexity.
quoted
The remaining patches implement initial SVE support for Linux, with the
following limitations:
* No KVM/virtualisation support for guests.
* No independent SVE vector length configuration per thread. This is
planned, but will follow as a separate add-on series.
Per-thread register widths will likely make coroutine switching (setcontext) and C++ resumable
functions/executors quite challenging.
i'd assume it's undefined to context switch to a different
thread or to resume a function on a different thread
(because the implementation can cache thread local state
on the stack: e.g. errno pointer).. of course this does
not stop ppl from doing it, but the practice is questionable.
Can you detail your plans in this area?
Thanks,
Florian
On Wed, Nov 30, 2016 at 11:05:41AM +0000, Szabolcs Nagy wrote:
On 30/11/16 10:08, Florian Weimer wrote:
quoted
On 11/25/2016 08:38 PM, Dave Martin wrote:
[...]
quoted
quoted
* Discussion is needed on how userspace should detect/negotiate signal
frame size in order for this expansion mechanism to be workable.
I'm leaning towards a simple increase in the glibc headers (despite the ABI risk), plus a personality flag to
disable really wide vector registers in case this causes problems with old binaries.
if the kernel does not increase the size and libc
does not add size checks then old binaries would
work with new libc just fine..
but that's non-conforming, posix requires the check.
if the kernel increases the size then it has to be
changed in bionic and musl as well and old binaries
may break.
Or we need a personality flag or similar to distinguish the two cases.
[...]
quoted
A more elaborate mechanism will likely introduce more bugs than it makes existing applications working, due to
its complexity.
quoted
The remaining patches implement initial SVE support for Linux, with the
following limitations:
* No KVM/virtualisation support for guests.
* No independent SVE vector length configuration per thread. This is
planned, but will follow as a separate add-on series.
Per-thread register widths will likely make coroutine switching (setcontext) and C++ resumable
functions/executors quite challenging.
i'd assume it's undefined to context switch to a different
thread or to resume a function on a different thread
(because the implementation can cache thread local state
on the stack: e.g. errno pointer).. of course this does
not stop ppl from doing it, but the practice is questionable.