x86 fixes
Linus,
Please pull the latest x86-urgent-for-linus git tree from:
git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git x86-urgent-for-linus
# HEAD: 5aaeb5c01c5b6c0be7b7aadbf3ace9f3a4458c3d x86/fpu, sched: Introduce CONFIG_ARCH_WANTS_DYNAMIC_TASK_STRUCT and use it on x86
Two families of fixes:
- Fix an FPU context related boot crash on newer x86 hardware with larger
context sizes than what most people test. To fix this without ugly kludges or
extensive reverts we had to touch core task allocator, to allow x86 to
determine the task size dynamically, at boot time.
I've tested it on a number of x86 platforms, and I cross-built it to a handful
of architectures:
(warns) (warns)
testing x86-64: -git: pass ( 0), -tip: pass ( 0)
testing x86-32: -git: pass ( 0), -tip: pass ( 0)
testing arm: -git: pass ( 1359), -tip: pass ( 1359)
testing cris: -git: pass ( 1031), -tip: pass ( 1031)
testing m32r: -git: pass ( 1135), -tip: pass ( 1135)
testing m68k: -git: pass ( 1471), -tip: pass ( 1471)
testing mips: -git: pass ( 1162), -tip: pass ( 1162)
testing mn10300: -git: pass ( 1058), -tip: pass ( 1058)
testing parisc: -git: pass ( 1846), -tip: pass ( 1846)
testing sparc: -git: pass ( 1185), -tip: pass ( 1185)
... so I hope the cross-arch impact 'none', as intended.
(by Dave Hansen)- Fix various NMI handling related bugs unearthed by the big asm code rewrite and generally make the NMI code more robust and more maintainable while at it. These changes are a bit late in the cycle, I hope they are still acceptable.
(by Andy Lutomirski)
out-of-topic modifications in x86-urgent-for-linus:
-----------------------------------------------------
arch/Kconfig # 5aaeb5c01c5b: x86/fpu, sched: Introduce CO fs/proc/kcore.c # 5aaeb5c01c5b: x86/fpu, sched: Introduce CO kernel/fork.c # 0c8c0f03e3a2: x86/fpu, sched: Dynamically
Thanks,
Ingo
------------------>
Andy Lutomirski (9):
x86/nmi: Enable nested do_nmi() handling for 64-bit kernels x86/nmi/64: Remove asm code that saves CR2
x86/nmi/64: Switch stacks on userspace NMI entry x86/nmi/64: Improve nested NMI comments
x86/nmi/64: Reorder nested NMI checks
x86/nmi/64: Use DF to avoid userspace RSP confusing nested NMI detection x86/nmi/64: Minor asm simplification
x86/nmi/64: Make the "NMI executing" variable more consistent x86/entry/64, x86/nmi/64: Add CONFIG_DEBUG_ENTRY NMI testing code
Dave Hansen (1):
x86/fpu, sched: Dynamically allocate 'struct fpu'
Ingo Molnar (1):
x86/fpu, sched: Introduce CONFIG_ARCH_WANTS_DYNAMIC_TASK_STRUCT and use it on x86
arch/Kconfig | 4 + arch/x86/Kconfig | 1 + arch/x86/Kconfig.debug | 12 ++ arch/x86/entry/entry_64.S | 299 ++++++++++++++++++++++++++------------- arch/x86/include/asm/fpu/types.h | 72 +++++----- arch/x86/include/asm/processor.h | 10 +- arch/x86/kernel/fpu/init.c | 40 ++++++ arch/x86/kernel/nmi.c | 123 +++++++--------- arch/x86/kernel/process.c | 2 +- fs/proc/kcore.c | 4 +- include/linux/sched.h | 16 ++- kernel/fork.c | 7 +- 12 files changed, 376 insertions(+), 214 deletions(-)
arch/Kconfig +4 -0
@@ -221,6 +221,10 @@ config ARCH_TASK_STRUCT_ALLOCATOR config ARCH_THREAD_INFO_ALLOCATOR bool +# Select if arch wants to size task_struct dynamically via arch_task_struct_size: +config ARCH_WANTS_DYNAMIC_TASK_STRUCT + bool + config HAVE_REGS_AND_STACK_ACCESS_API bool help
arch/x86/Kconfig +1 -0
@@ -41,6 +41,7 @@ config X86 select ARCH_USE_CMPXCHG_LOCKREF if X86_64 select ARCH_USE_QUEUED_RWLOCKS select ARCH_USE_QUEUED_SPINLOCKS + select ARCH_WANTS_DYNAMIC_TASK_STRUCT select ARCH_WANT_FRAME_POINTERS select ARCH_WANT_IPC_PARSE_VERSION if X86_32 select ARCH_WANT_OPTIONAL_GPIOLIB
arch/x86/Kconfig.debug +12 -0
@@ -297,6 +297,18 @@ config OPTIMIZE_INLINING If unsure, say N. +config DEBUG_ENTRY + bool "Debug low-level entry code" + depends on DEBUG_KERNEL + ---help--- + This option enables sanity checks in x86's low-level entry code. + Some of these sanity checks may slow down kernel entries and + exits or otherwise impact performance. + + This is currently used to help test NMI code. + + If unsure, say N. + config DEBUG_NMI_SELFTEST bool "NMI Selftest" depends on DEBUG_KERNEL && X86_LOCAL_APIC
arch/x86/entry/entry_64.S +199 -100
391 lines not on this page · raw message
arch/x86/include/asm/fpu/types.h +38 -34
90 lines not on this page · raw message
arch/x86/include/asm/processor.h +7 -3
@@ -390,9 +390,6 @@ struct thread_struct {#endif unsigned long gs; -/* Floating point and extended processor state */ -struct fpu fpu; -/* Save middle states of ptrace breakpoints */ struct perf_event *ptrace_bps[HBP_NUM ];/* Debug status used for traps, single steps, etc... */
@@ -418,6 +415,13 @@ struct thread_struct {unsigned long iopl;/* Max allowed port in the bitmap, in bytes: */ unsigned io_bitmap_max; + +/* Floating point and extended processor state */ +struct fpu fpu; +/* +* WARNING: 'fpu' is dynamically-sized. It *MUST* be at +* the end. +*/ };/*
arch/x86/kernel/fpu/init.c +40 -0
@@ -4,6 +4,8 @@#include <asm/fpu/internal.h> #include <asm/tlbflush.h> +#include <linux/sched.h> +/* * Initialize the TS bit in CR0 according to the style of context-switches * we are using:
@@ -136,6 +138,43 @@ static void __init fpu__init_system_generic(void)unsigned int xstate_size;EXPORT_SYMBOL_GPL (xstate_size); +/* Enforce that 'MEMBER' is the last field of 'TYPE': */ +#define CHECK_MEMBER_AT_END_OF (TYPE ,MEMBER ) \ + BUILD_BUG_ON(sizeof(TYPE) != offsetofend(TYPE, MEMBER)) + +/* +* We append the 'struct fpu' to the task_struct: +*/ +static void __init fpu__init_task_struct_size (void ) +{ +int task_size =sizeof (struct task_struct ); + +/* +* Subtract off the static size of the register state. +* It potentially has a bunch of padding. +*/ + task_size -=sizeof (((struct task_struct *)0 )->thread.fpu.state); + +/* +* Add back the dynamically-calculated register state +* size. +*/ + task_size += xstate_size; + +/* +* We dynamically size 'struct fpu', so we require that +* it be at the end of 'thread_struct' and that +* 'thread_struct' be at the end of 'task_struct'. If +* you hit a compile error here, check the structure to +* see if something got added to the end. +*/ + CHECK_MEMBER_AT_END_OF(struct fpu, state); + CHECK_MEMBER_AT_END_OF(struct thread_struct, fpu); + CHECK_MEMBER_AT_END_OF(struct task_struct, thread); + + arch_task_struct_size = task_size; +} +/* * Set up the xstate_size based on the legacy FPU context size. *
@@ -287,6 +326,7 @@ void __init fpu__init_system(struct cpuinfo_x86 *c)fpu__init_system_generic ();fpu__init_system_xstate_size_legacy ();fpu__init_system_xstate (); +fpu__init_task_struct_size ();fpu__init_system_ctx_switch (); }
arch/x86/kernel/nmi.c +52 -71
161 lines not on this page · raw message
arch/x86/kernel/process.c +1 -1
@@ -81,7 +81,7 @@ EXPORT_SYMBOL_GPL(idle_notifier_unregister);*/ int arch_dup_task_struct (struct task_struct *dst,struct task_struct *src) { - *dst = *src; +memcpy (dst, src, arch_task_struct_size);return fpu__copy (&dst->thread.fpu, &src->thread.fpu); }
fs/proc/kcore.c +2 -2
@@ -92,7 +92,7 @@ static size_t get_kcore_size(int *nphdr, size_t *elf_buflen) roundup(sizeof(CORE_STR), 4)) +roundup (sizeof (struct elf_prstatus ),4 ) +roundup (sizeof (struct elf_prpsinfo ),4 ) + -roundup (sizeof (struct task_struct ),4 ); +roundup (arch_task_struct_size,4 ); *elf_buflen =PAGE_ALIGN (*elf_buflen);return size + *elf_buflen; }
@@ -415,7 +415,7 @@ static void elf_kcore_store_hdr(char *bufp, int nphdr, int dataoff)/* set up the task structure */ notes[2 ].name =CORE_STR ; notes[2 ].type =NT_TASKSTRUCT ; - notes[2 ].datasz =sizeof (struct task_struct ); + notes[2 ].datasz = arch_task_struct_size; notes[2 ].data = current; nhdr->p_filesz +=notesize (¬es[2 ]);
include/linux/sched.h +14 -2
@@ -1522,8 +1522,6 @@ struct task_struct {/* hung task detection */ unsigned long last_switch_count;#endif -/* CPU-specific state of this task */ -struct thread_struct thread;/* filesystem information */ struct fs_struct *fs;/* open file information */
@@ -1778,8 +1776,22 @@ struct task_struct {unsigned long task_state_change;#endif int pagefault_disabled; +/* CPU-specific state of this task */ +struct thread_struct thread; +/* +* WARNING: on x86, 'thread_struct' contains a variable-sized +* structure. It *MUST* be at the end of 'task_struct'. +* +* Do not put anything below here! +*/ }; +#ifdef CONFIG_ARCH_WANTS_DYNAMIC_TASK_STRUCT +extern int arch_task_struct_size__read_mostly ; +#else +# define arch_task_struct_size (sizeof(struct task_struct)) +#endif +/* Future-safe accessor for struct task_struct's cpus_allowed. */ #define tsk_cpus_allowed (tsk) (&(tsk)->cpus_allowed)
kernel/fork.c +6 -1
@@ -287,6 +287,11 @@ static void set_max_threads(unsigned int max_threads_suggested) max_threads =clamp_t (u64, threads,MIN_THREADS ,MAX_THREADS ); } +#ifdef CONFIG_ARCH_WANTS_DYNAMIC_TASK_STRUCT +/* Initialized by the architecture: */ +int arch_task_struct_size__read_mostly ; +#endif +void __init fork_init (void ) {#ifndef CONFIG_ARCH_TASK_STRUCT_ALLOCATOR
@@ -295,7 +300,7 @@ void __init fork_init(void)#endif /* create a slab on which task_structs can be allocated */ task_struct_cachep = -kmem_cache_create ("task_struct" ,sizeof (struct task_struct ), +kmem_cache_create ("task_struct" , arch_task_struct_size,ARCH_MIN_TASKALIGN ,SLAB_PANIC |SLAB_NOTRACK ,NULL );#endif
Quoted 25 lines · Ingo Molnar
Linus,
Please pull the latest x86-urgent-for-linus git tree from:
git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.gitx86-urgent-for-linus# HEAD:
5aaeb5c01c5b6c0be7b7aadbf3ace9f3a4458c3dx86/fpu, sched: IntroduceCONFIG_ARCH_WANTS_DYNAMIC_TASK_STRUCTand use it on x86Two families of fixes:
- Fix an FPU context related boot crash on newer x86 hardware with larger
context sizes than what most people test. To fix this without ugly kludges or extensive reverts we had to touch core task allocator, to allow x86 to determine the task size dynamically, at boot time. I've tested it on a number of x86 platforms, and I cross-built it to a handful of architectures: (warns) (warns) testing x86-64: -git: pass ( 0), -tip: pass ( 0) testing x86-32: -git: pass ( 0), -tip: pass ( 0) testing arm: -git: pass ( 1359), -tip: pass ( 1359) testing cris: -git: pass ( 1031), -tip: pass ( 1031) testing m32r: -git: pass ( 1135), -tip: pass ( 1135) testing m68k: -git: pass ( 1471), -tip: pass ( 1471)
Quoted 8 lines
testing mips: -git: pass ( 1162), -tip: pass ( 1162)
testing mn10300: -git: pass ( 1058), -tip: pass ( 1058)
testing parisc: -git: pass ( 1846), -tip: pass ( 1846)
testing sparc: -git: pass ( 1185), -tip: pass ( 1185)
... so I hope the cross-arch impact 'none', as intended.
(by Dave Hansen)Unfortunately not true. It breaks the build on s390 since a couple of displacements used in asm code now get too large:
arch/s390/kernel/entry.S:181: Error: operand out of range (0x00000000000018a8 is not between 0x0000000000000000 and 0x0000000000000fff) arch/s390/kernel/entry.S:191: Error: operand out of range (0x00000000000018a8 is not between 0x0000000000000000 and 0x0000000000000fff) arch/s390/kernel/entry.S:423: Error: operand out of range (0x0000000000001924 is not between 0x0000000000000000 and 0x0000000000000fff) arch/s390/kernel/entry.S:437: Error: operand out of range (0x00000000000018e8 is not between 0x0000000000000000 and 0x0000000000000fff) arch/s390/kernel/entry.S:438: Error: operand out of range (0x00000000000018e0 is not between 0x0000000000000000 and 0x0000000000000fff) arch/s390/kernel/entry.S:439: Error: operand out of range (0x00000000000018f0 is not between 0x0000000000000000 and 0x0000000000000fff) make[1]: *** [arch/s390/kernel/entry.o] Error 1
Let's see how we can fix this.
PATCH 1/1 sched, s390: Fix the fallout of increasing the offset of 'thread_struct' within 'task_struct'
Quoted 30 lines · Heiko Carstens
Quoted 10 lines
I've tested it on a number of x86 platforms, and I cross-built it to a handful of architectures: (warns) (warns) testing x86-64: -git: pass ( 0), -tip: pass ( 0) testing x86-32: -git: pass ( 0), -tip: pass ( 0) testing arm: -git: pass ( 1359), -tip: pass ( 1359) testing cris: -git: pass ( 1031), -tip: pass ( 1031) testing m32r: -git: pass ( 1135), -tip: pass ( 1135) testing m68k: -git: pass ( 1471), -tip: pass ( 1471)Quoted 8 lines
testing mips: -git: pass ( 1162), -tip: pass ( 1162) testing mn10300: -git: pass ( 1058), -tip: pass ( 1058) testing parisc: -git: pass ( 1846), -tip: pass ( 1846) testing sparc: -git: pass ( 1185), -tip: pass ( 1185) ... so I hope the cross-arch impact 'none', as intended. (by Dave Hansen)Unfortunately not true. It breaks the build on s390 since a couple of displacements used in asm code now get too large:
arch/s390/kernel/entry.S:181: Error: operand out of range (0x00000000000018a8is not between0x0000000000000000and0x0000000000000fff)arch/s390/kernel/entry.S:191: Error: operand out of range (0x00000000000018a8is not between0x0000000000000000and0x0000000000000fff)arch/s390/kernel/entry.S:423: Error: operand out of range (0x0000000000001924is not between0x0000000000000000and0x0000000000000fff)arch/s390/kernel/entry.S:437: Error: operand out of range (0x00000000000018e8is not between0x0000000000000000and0x0000000000000fff)arch/s390/kernel/entry.S:438: Error: operand out of range (0x00000000000018e0is not between0x0000000000000000and0x0000000000000fff)arch/s390/kernel/entry.S:439: Error: operand out of range (0x00000000000018f0is not between0x0000000000000000and0x0000000000000fff) make[1]: *** [arch/s390/kernel/entry.o] Error 1
Quoted 1 line
Let's see how we can fix this.
There's also a traps.c build breakage reported below - and an RFC fix for it.
Thanks,
Ingo
=========================>
Quoted 10 lines · Guenter
Hi,
Commit
0c8c0f03e3a2("x86/fpu, sched: Dynamically allocate 'struct fpu'") causes s390 builds in mainline to fail as follows.
arch/s390/kernel/traps.c: Assembler messages:arch/s390/kernel/traps.c:262: Error: operand out of range(0x00000000000023e8 is not between 0x0000000000000000 and 0x0000000000000fff) arch/s390/kernel/traps.c:300: Error: operand out of range (0x00000000000023e8 is not between 0x0000000000000000 and 0x0000000000000fff)
Yeah, so I'm really out on a limb here as I know next to nothing about s390 assembly, but the build failure appears to be analogous to the arm64 one: the offset of thread_struct fields within task_struct increased due to commit 0c8c0f03e3a2 ("x86/fpu, sched: Dynamically allocate 'struct fpu'"), which increased assembly offsets beyond the limit this instruction can apparently encode.
Does the (untested!) patch below help?
It's an equivalent transformation on the C side, but it might cause GCC to generate different assembly code, because we now have a temporary variable with much smaller offsets.
The code is also a tiny bit cleaner this way, as the 'current->thread.fp_regs' pattern isn't repeated twice.
In case this works:
Thanks,
Ingo
================>
arch/s390/kernel/traps.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
arch/s390/kernel/traps.c +4 -2
@@ -251,6 +251,7 @@ int alloc_vector_registers(struct task_struct *tsk)void vector_exception (struct pt_regs *regs) { +s390_fp_regs *fp_regs = ¤t->thread.fp_regs;int si_code, vic;if (!MACHINE_HAS_VX ) {
@@ -259,8 +260,9 @@ void vector_exception(struct pt_regs *regs) }/* get vector interrupt code from fpc */ - asmvolatile ("stfpc %0" :"=m" (current->thread.fp_regs.fpc)); - vic = (current->thread.fp_regs.fpc &0xf00 ) >>8 ; + asmvolatile ("stfpc %0" :"=m" (fp_regs->fpc)); + vic = (fp_regs->fpc &0xf00 ) >>8 ; +switch (vic) {case 1 :/* invalid vector operation */ si_code =FPE_FLTINV ;
Re: [PATCH] sched, s390: Fix the fallout of increasing the offset of 'thread_struct' within 'task_struct'
Quoted 10 lines · On Mon, 20 Jul 2015 10:00:32 +0200 Ingo Molnar <[email protected]> wrote:
Quoted 8 lines · Heiko Carstens
arch/s390/kernel/entry.S:181: Error: operand out of range (0x00000000000018a8is not between0x0000000000000000and0x0000000000000fff)arch/s390/kernel/entry.S:191: Error: operand out of range (0x00000000000018a8is not between0x0000000000000000and0x0000000000000fff)arch/s390/kernel/entry.S:423: Error: operand out of range (0x0000000000001924is not between0x0000000000000000and0x0000000000000fff)arch/s390/kernel/entry.S:437: Error: operand out of range (0x00000000000018e8is not between0x0000000000000000and0x0000000000000fff)arch/s390/kernel/entry.S:438: Error: operand out of range (0x00000000000018e0is not between0x0000000000000000and0x0000000000000fff)arch/s390/kernel/entry.S:439: Error: operand out of range (0x00000000000018f0is not between0x0000000000000000and0x0000000000000fff) make[1]: *** [arch/s390/kernel/entry.o] Error 1
Quoted 3 lines
Quoted 1 line
Let's see how we can fix this.
There's also a
traps.cbuild breakage reported below - and an RFC fix for it.
This patch should fix it for good.
--
Quoted 1 line
From
54b3c4b85572bf5acc698cfca15d2c9cad446c44Mon Sep 17 00:00:00 2001
From: Martin Schwidefsky <[email protected]>
Date: Mon, 20 Jul 2015 10:01:46 +0200
Subject: [PATCH] s390: adapt entry.S to the move of thread_struct
git commit 0c8c0f03e3a292e031596484275c14cf39c0ab7a "x86/fpu, sched: Dynamically allocate 'struct fpu'" moved the thread_struct to the end of the task_struct.
This causes some of the offsets used in entry.S to overflow their instruction operand field. To fix this use aghi to create a dedicated pointer for the thread_struct.
--- arch/s390/kernel/asm-offsets.c | 15 +++++++-------- arch/s390/kernel/entry.S | 13 +++++++++---- arch/s390/kernel/traps.c | 4 ++-- 3 files changed, 18 insertions(+), 14 deletions(-)
arch/s390/kernel/asm-offsets.c +7 -8
@@ -23,15 +23,15 @@int main (void ) { -DEFINE (__THREAD_info, offsetof(struct task_struct , stack)); - DEFINE(__THREAD_ksp, offsetof(struct task_struct, thread.ksp)); - DEFINE(__THREAD_mm_segment, offsetof(struct task_struct, thread.mm_segment)); -BLANK (); +DEFINE (__TASK_thread_info, offsetof(struct task_struct , stack)); +DEFINE (__TASK_thread, offsetof(struct task_struct , thread));DEFINE (__TASK_pid, offsetof(struct task_struct , pid));BLANK (); - DEFINE(__THREAD_per_cause, offsetof(struct task_struct, thread.per_event.cause)); - DEFINE(__THREAD_per_address, offsetof(struct task_struct, thread.per_event.address)); - DEFINE(__THREAD_per_paid, offsetof(struct task_struct, thread.per_event.paid)); +DEFINE (__THREAD_ksp, offsetof(struct thread_struct , ksp)); + DEFINE(__THREAD_per_cause, offsetof(struct thread_struct, per_event.cause)); + DEFINE(__THREAD_per_address, offsetof(struct thread_struct, per_event.address)); + DEFINE(__THREAD_per_paid, offsetof(struct thread_struct, per_event.paid)); +DEFINE (__THREAD_trap_tdb, offsetof(struct thread_struct , trap_tdb));BLANK ();DEFINE (__TI_task, offsetof(struct thread_info , task));DEFINE (__TI_flags, offsetof(struct thread_info , flags));
@@ -176,7 +176,6 @@ int main(void)DEFINE (__LC_VDSO_PER_CPU, offsetof(struct _lowcore , vdso_per_cpu_data));DEFINE (__LC_GMAP, offsetof(struct _lowcore , gmap));DEFINE (__LC_PGM_TDB, offsetof(struct _lowcore , pgm_tdb)); - DEFINE(__THREAD_trap_tdb, offsetof(struct task_struct, thread.trap_tdb));DEFINE (__GMAP_ASCE, offsetof(struct gmap , asce));DEFINE (__SIE_PROG0C, offsetof(struct kvm_s390_sie_block , prog0c));DEFINE (__SIE_PROG20, offsetof(struct kvm_s390_sie_block , prog20));
arch/s390/kernel/entry.S +9 -4
@@ -178,17 +178,21 @@ _PIF_WORK = (_PIF_PER_TRAP) */ ENTRY(__switch_to) stmg %r6,%r15,__SF_GPRS(%r15) # store gprs of prev task - stg %r15,__THREAD_ksp(%r2) # store kernel stack of prev - lg %r4,__THREAD_info(%r2) # get thread_info of prev - lg %r5,__THREAD_info(%r3) # get thread_info of next + lgr %r1,%r2 + aghi %r1,__TASK_thread # thread_struct of prev task + lg %r4,__TASK_thread_info(%r2) # get thread_info of prev + lg %r5,__TASK_thread_info(%r3) # get thread_info of next + stg %r15,__THREAD_ksp(%r1) # store kernel stack of prev + lgr %r1,%r3 + aghi %r1,__TASK_thread # thread_struct of next task lgr %r15,%r5 aghi %r15,STACK_INIT # end of kernel stack of next stg %r3,__LC_CURRENT # store task struct of next stg %r5,__LC_THREAD_INFO # store thread info of next stg %r15,__LC_KERNEL_STACK # store end of kernel stack + lg %r15,__THREAD_ksp(%r1) # load kernel stack of next lctl %c4,%c4,__TASK_pid(%r3) # load pid to control reg. 4 mvc __LC_CURRENT_PID+4(4,%r0),__TASK_pid(%r3) # store pid of next - lg %r15,__THREAD_ksp(%r3) # load kernel stack of next lmg %r6,%r15,__SF_GPRS(%r15) # load gprs of next task br %r14
@@ -417,6 +421,7 @@ ENTRY(pgm_check_handler) LAST_BREAK %r14 lg %r15,__LC_KERNEL_STACK lg %r14,__TI_task(%r12) + aghi %r14,__TASK_thread # pointer to thread_struct lghi %r13,__LC_PGM_TDB tm __LC_PGM_ILC+2,0x02 # check for transaction abort jz 2f
arch/s390/kernel/traps.c +2 -2
@@ -259,7 +259,7 @@ void vector_exception(struct pt_regs *regs) }/* get vector interrupt code from fpc */ - asmvolatile ("stfpc %0" :"=m" (current->thread.fp_regs.fpc)); + asmvolatile ("stfpc %0" :"=Q" (current->thread.fp_regs.fpc)); vic = (current->thread.fp_regs.fpc &0xf00 ) >>8 ;switch (vic) {case 1 :/* invalid vector operation */
@@ -297,7 +297,7 @@ void data_exception(struct pt_regs *regs) location =get_trap_ip (regs); - asmvolatile ("stfpc %0" :"=m" (current->thread.fp_regs.fpc)); + asmvolatile ("stfpc %0" :"=Q" (current->thread.fp_regs.fpc));/* Check for vector register enablement */ if (MACHINE_HAS_VX && !current->thread.vxrs && (current->thread.fp_regs.fpc &FPC_DXC_MASK ) ==0xfe00 ) {
Signature · 8 lines
2.3.8 -- blue skies, Martin. "Reality continues to ruin my life." - Calvin.
Re: [PATCH] sched, s390: Fix the fallout of increasing the offset of 'thread_struct' within 'task_struct'
Quoted 19 lines · Martin Schwidefsky
arch/s390/kernel/entry.S +7
-3@@ -178,17 +178,21 @@ _PIF_WORK = (_PIF_PER_TRAP) */ ENTRY(__switch_to) stmg %r6,%r15,__SF_GPRS(%r15) # store gprs of prev task - stg %r15,__THREAD_ksp(%r2) # store kernel stack of prev - lg %r4,__THREAD_info(%r2) # get thread_info of prev - lg %r5,__THREAD_info(%r3) # get thread_info of next + lgr %r1,%r2 + aghi %r1,__TASK_thread # thread_struct of prev task + lg %r4,__TASK_thread_info(%r2) # get thread_info of prev + lg %r5,__TASK_thread_info(%r3) # get thread_info of next + stg %r15,__THREAD_ksp(%r1) # store kernel stack of prev + lgr %r1,%r3 + aghi %r1,__TASK_thread # thread_struct of next task lgr %r15,%r5
arch/s390/kernel/entry.S _PIF_WORK = (_PIF_PER_TRAP) · line 197
Quoted 10 lines
arch/s390/kernel/entry.S +1
-1aghi %r15,STACK_INIT # end of kernel stack of next stg %r3,__LC_CURRENT # store task struct of next stg %r5,__LC_THREAD_INFO # store thread info of next stg %r15,__LC_KERNEL_STACK # store end of kernel stack + lg %r15,__THREAD_ksp(%r1) # load kernel stack of next lctl %c4,%c4,__TASK_pid(%r3) # load pid to control reg. 4 mvc __LC_CURRENT_PID+4(4,%r0),__TASK_pid(%r3) # store pid of next - lg %r15,__THREAD_ksp(%r3) # load kernel stack of next lmg %r6,%r15,__SF_GPRS(%r15) # load gprs of next task br %r14
Btw., I think we'd be slightly better off with the variant I sent: that way the offset arithmetics are done in C code and are ready in the relevant registers by the time they are used in __switch_to().
arch/s390/kernel/entry.S ENTRY(pgm_check_handler) · line 427
Quoted 9 lines
arch/s390/kernel/entry.S +1
-0@@ -417,6 +421,7 @@ ENTRY(pgm_check_handler) LAST_BREAK %r14 lg %r15,__LC_KERNEL_STACK lg %r14,__TI_task(%r12) + aghi %r14,__TASK_thread # pointer to thread_struct lghi %r13,__LC_PGM_TDB tm __LC_PGM_ILC+2,0x02 # check for transaction abort jz 2f
Don't we also need the chunk I have:
@@ -448,6 +449,7 @@ ENTRY(pgm_check_handler)
nill %r10,0x007f
sll %r10,2
je .Lsysc_return
+ ahi %r14,-__TASK_thread_struct # r14 now points to 'current'
lgf %r1,0(%r10,%r1) # load address of handler routine
lgr %r2,%r11 # pass pointer to pt_regs
basr %r14,%r1 # branch to interrupt-handler
Because the 'basr' line relies on 'r14' having task_struct, I think?
But I don't really know what I'm talking about here ...
Thanks,
Ingo
Re: [PATCH] sched, s390: Fix the fallout of increasing the offset of 'thread_struct' within 'task_struct'
Quoted 28 lines · On Mon, 20 Jul 2015 10:38:47 +0200 Ingo Molnar <[email protected]> wrote:
Quoted 25 lines · Martin Schwidefsky
arch/s390/kernel/entry.S +8
-3@@ -178,17 +178,21 @@ _PIF_WORK = (_PIF_PER_TRAP) */ ENTRY(__switch_to) stmg %r6,%r15,__SF_GPRS(%r15) # store gprs of prev task - stg %r15,__THREAD_ksp(%r2) # store kernel stack of prev - lg %r4,__THREAD_info(%r2) # get thread_info of prev - lg %r5,__THREAD_info(%r3) # get thread_info of next + lgr %r1,%r2 + aghi %r1,__TASK_thread # thread_struct of prev task + lg %r4,__TASK_thread_info(%r2) # get thread_info of prev + lg %r5,__TASK_thread_info(%r3) # get thread_info of next + stg %r15,__THREAD_ksp(%r1) # store kernel stack of prev + lgr %r1,%r3 + aghi %r1,__TASK_thread # thread_struct of next task lgr %r15,%r5 aghi %r15,STACK_INIT # end of kernel stack of next stg %r3,__LC_CURRENT # store task struct of next stg %r5,__LC_THREAD_INFO # store thread info of next stg %r15,__LC_KERNEL_STACK # store end of kernel stack + lg %r15,__THREAD_ksp(%r1) # load kernel stack of next lctl %c4,%c4,__TASK_pid(%r3) # load pid to control reg. 4
Quoted 8 lines
arch/s390/kernel/entry.S _PIF_WORK = (_PIF_PER_TRAP) · line 197
Quoted 4 lines
arch/s390/kernel/entry.S +0
-1mvc __LC_CURRENT_PID+4(4,%r0),__TASK_pid(%r3) # store pid of next - lg %r15,__THREAD_ksp(%r3) # load kernel stack of next lmg %r6,%r15,__SF_GPRS(%r15) # load gprs of next task br %r14Btw., I think we'd be slightly better off with the variant I sent: that way the offset arithmetics are done in C code and are ready in the relevant registers by the time they are used in
__switch_to().
If we save any instruction then not many, we are trading additional parameter passing vs. four additional instructions in __switch_to. With this variant the fallout is kept at a minimum which I would prefer at this point.
Quoted 21 lines
arch/s390/kernel/entry.S ENTRY(pgm_check_handler) · line 427
Quoted 9 lines
arch/s390/kernel/entry.S +1
-0@@ -417,6 +421,7 @@ ENTRY(pgm_check_handler) LAST_BREAK %r14 lg %r15,__LC_KERNEL_STACK lg %r14,__TI_task(%r12) + aghi %r14,__TASK_thread # pointer to thread_struct lghi %r13,__LC_PGM_TDB tm __LC_PGM_ILC+2,0x02 # check for transaction abort jz 2fDon't we also need the chunk I have:
(quoted diff) +1
-0@@ -448,6 +449,7 @@ ENTRY(pgm_check_handler) nill %r10,0x007f sll %r10,2 je .Lsysc_return + ahi %r14,-__TASK_thread_struct # r14 now points to 'current' lgf %r1,0(%r10,%r1) # load address of handler routine lgr %r2,%r11 # pass pointer to pt_regs basr %r14,%r1 # branch to interrupt-handler
Quoted 3 lines
Because the 'basr' line relies on 'r14' having
task_struct, I think?But I don't really know what I'm talking about here ...
The basr instruction is one of the function calling instructions and %r14 is used for the return address. Between function calls the register is basically free. So far it is used for the task_struct pointer (the code following the "lg %r14,__TI_task(%r12)"). What I noticed is that the pointer is only used to access the embedded thread_struct. To get from the task_struct to a thread_struct a single aghi is needed. The rest is moving stuff around in asm-offsets.c
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
PATCH 1/1 s390, sched: Fix thread_struct move fallout to __switch_to()
In reply to Heiko CarstensQuoted 11 lines · Heiko Carstens
Unfortunately not true. It breaks the build on s390 since a couple of displacements used in asm code now get too large:
arch/s390/kernel/entry.S:181: Error: operand out of range (0x00000000000018a8is not between0x0000000000000000and0x0000000000000fff)arch/s390/kernel/entry.S:191: Error: operand out of range (0x00000000000018a8is not between0x0000000000000000and0x0000000000000fff)arch/s390/kernel/entry.S:423: Error: operand out of range (0x0000000000001924is not between0x0000000000000000and0x0000000000000fff)arch/s390/kernel/entry.S:437: Error: operand out of range (0x00000000000018e8is not between0x0000000000000000and0x0000000000000fff)arch/s390/kernel/entry.S:438: Error: operand out of range (0x00000000000018e0is not between0x0000000000000000and0x0000000000000fff)arch/s390/kernel/entry.S:439: Error: operand out of range (0x00000000000018f0is not between0x0000000000000000and0x0000000000000fff) make[1]: *** [arch/s390/kernel/entry.o] Error 1
Quoted 1 line
Let's see how we can fix this.
Sorry about this!
So I looked at the __switch_to() assembly, and the main complication appears to be that we have two uses of 'prev':
lg %r4,__THREAD_info(%r2) # get thread_info of prev
stg %r15,__THREAD_ksp(%r2) # store kernel stack of prev
the __THREAD_info offset is best expressed relative to task_struct - the __THREAD_ksp offset is best expressed relative to thread_struct.
I.e. I think the best fix would be to extend the signature of s390's __switch_to() from (prev,next) to (prev,next,prev_thread,next_thread).
Is the C parameter mapping r2,r3,r4,r5? If yes then the patch below should do the trick. (Utterly untested.)
Note:
- I renamed __THREAD_info to __TASK_thread_info, to better separate task_struct and thread_struct offsets syntactically and visually.
- I removed __THREAD_mm_segment which is unused
I also looked at fixing pgm_check_handler(), but my s390-fu gave up completely on that one: task_struct is in 'r14', but this is a hardware entry function it appears. So to fix it we'd have to pick a temporary register, put thread_struct pointer into it, and fix up these offsets:
arch/s390/kernel/asm-offsets.c: DEFINE(__THREAD_per_address, offsetof(struct task_struct, thread.per_event.address)); arch/s390/kernel/asm-offsets.c: DEFINE(__THREAD_per_paid, offsetof(struct task_struct, thread.per_event.paid)); arch/s390/kernel/asm-offsets.c: DEFINE(__THREAD_trap_tdb, offsetof(struct task_struct, thread.trap_tdb));
to be thread_struct relative.
Thanks,
Ingo
==============>
arch/s390/include/asm/switch_to.h | 7 +++++-- arch/s390/kernel/asm-offsets.c | 5 ++--- arch/s390/kernel/entry.S | 14 +++++++++----- 3 files changed, 16 insertions(+), 10 deletions(-)
arch/s390/include/asm/switch_to.h +5 -2
@@ -10,7 +10,10 @@#include <linux/thread_info.h> #include <asm/ptrace.h> -extern struct task_struct *__switch_to (void *,void *); +extern struct task_struct * +__switch_to (struct task_struct *prev,struct task_struct *next, +struct thread_struct *prev_thread,struct thread_struct *next_thrad); +extern void update_cr_regs (struct task_struct *task);static inline int test_fp_ctl (u32 fpc)
@@ -169,7 +172,7 @@ static inline void restore_access_regs(unsigned int *acrs)restore_access_regs (&next->thread.acrs[0 ]); \ restore_ri_cb(next->thread.ri_cb, prev->thread.ri_cb); \ } \ - prev =__switch_to (prev,next); \ + prev =__switch_to (prev, next, &prev->thread, &next->thread); \ }while (0 ) #endif /* __ASM_SWITCH_TO_H */
arch/s390/kernel/asm-offsets.c +2 -3
@@ -23,9 +23,8 @@int main (void ) { -DEFINE (__THREAD_info, offsetof(struct task_struct , stack)); - DEFINE(__THREAD_ksp, offsetof(struct task_struct, thread.ksp)); - DEFINE(__THREAD_mm_segment, offsetof(struct task_struct, thread.mm_segment)); +DEFINE (__TASK_thread_info, offsetof(struct task_struct , stack)); +DEFINE (__THREAD_ksp, offsetof(struct thread_struct , ksp));BLANK ();DEFINE (__TASK_pid, offsetof(struct task_struct , pid));BLANK ();
arch/s390/kernel/entry.S +9 -5
@@ -170,17 +170,21 @@ _PIF_WORK = (_PIF_PER_TRAP) .section .kprobes.text, "ax" /* - * Scheduler resume function, called by switch_to + * Low level scheduler resume function, called by switch_to(): + * * gpr2 = (task_struct *) prev * gpr3 = (task_struct *) next + * gpr4 = (thread_struct *) prev->thread + * gpr5 = (thread_struct *) next->thread + * * Returns: * gpr2 = prev */ ENTRY(__switch_to) stmg %r6,%r15,__SF_GPRS(%r15) # store gprs of prev task - stg %r15,__THREAD_ksp(%r2) # store kernel stack of prev - lg %r4,__THREAD_info(%r2) # get thread_info of prev - lg %r5,__THREAD_info(%r3) # get thread_info of next + stg %r15,__THREAD_ksp(%r4) # store kernel stack of prev + lg %r4,__TASK_thread_info(%r2) # get thread_info of prev + lg %r5,__TASK_thread_info(%r3) # get thread_info of next lgr %r15,%r5 aghi %r15,STACK_INIT # end of kernel stack of next stg %r3,__LC_CURRENT # store task struct of next
@@ -188,7 +192,7 @@ ENTRY(__switch_to) stg %r15,__LC_KERNEL_STACK # store end of kernel stack lctl %c4,%c4,__TASK_pid(%r3) # load pid to control reg. 4 mvc __LC_CURRENT_PID+4(4,%r0),__TASK_pid(%r3) # store pid of next - lg %r15,__THREAD_ksp(%r3) # load kernel stack of next + lg %r15,__THREAD_ksp(%r5) # load kernel stack of next lmg %r6,%r15,__SF_GPRS(%r15) # load gprs of next task br %r14
Re: [PATCH] s390, sched: Fix thread_struct move fallout to __switch_to()
Quoted 47 lines · On Mon, 20 Jul 2015 10:20:04 +0200 Ingo Molnar <[email protected]> wrote:
Quoted 11 lines · Heiko Carstens
Unfortunately not true. It breaks the build on s390 since a couple of displacements used in asm code now get too large:
arch/s390/kernel/entry.S:181: Error: operand out of range (0x00000000000018a8is not between0x0000000000000000and0x0000000000000fff)arch/s390/kernel/entry.S:191: Error: operand out of range (0x00000000000018a8is not between0x0000000000000000and0x0000000000000fff)arch/s390/kernel/entry.S:423: Error: operand out of range (0x0000000000001924is not between0x0000000000000000and0x0000000000000fff)arch/s390/kernel/entry.S:437: Error: operand out of range (0x00000000000018e8is not between0x0000000000000000and0x0000000000000fff)arch/s390/kernel/entry.S:438: Error: operand out of range (0x00000000000018e0is not between0x0000000000000000and0x0000000000000fff)arch/s390/kernel/entry.S:439: Error: operand out of range (0x00000000000018f0is not between0x0000000000000000and0x0000000000000fff) make[1]: *** [arch/s390/kernel/entry.o] Error 1Quoted 1 line
Let's see how we can fix this.
Sorry about this!
So I looked at the
__switch_to()assembly, and the main complication appears to be that we have two uses of 'prev':lg %r4,__THREAD_info(%r2) # get
thread_infoof prevstg %r15,__THREAD_ksp(%r2) # store kernel stack of prev
the
__THREAD_infooffset is best expressed relative totask_struct- the__THREAD_kspoffset is best expressed relative tothread_struct.I.e. I think the best fix would be to extend the signature of s390's
__switch_to()from (prev,next) to (prev,next,prev_thread,next_thread).Is the C parameter mapping r2,r3,r4,r5? If yes then the patch below should do the trick. (Utterly untested.)
Note:
- I renamed
__THREAD_infoto__TASK_thread_info, to better separatetask_structandthread_structoffsets syntactically and visually.- I removed
__THREAD_mm_segmentwhich is unusedI also looked at fixing
pgm_check_handler(), but my s390-fu gave up completely on that one:task_structis in 'r14', but this is a hardware entry function it appears. So to fix it we'd have to pick a temporary register, putthread_structpointer into it, and fix up these offsets:
Quoted 5 lines
arch/s390/kernel/asm-offsets.c:DEFINE(__THREAD_per_address, offsetof(struct task_struct, thread.per_event.address));arch/s390/kernel/asm-offsets.c:DEFINE(__THREAD_per_paid, offsetof(struct task_struct, thread.per_event.paid));arch/s390/kernel/asm-offsets.c:DEFINE(__THREAD_trap_tdb, offsetof(struct task_struct, thread.trap_tdb));to be
thread_structrelative.
Just use the patch I've sent. No worries :-)
Signature · 4 lines
blue skies, Martin. "Reality continues to ruin my life." - Calvin.
Re: [PATCH] s390, sched: Fix thread_struct move fallout to __switch_to()
In reply to Ingo MolnarQuoted 10 lines · Ingo Molnar
I also looked at fixing
pgm_check_handler(), but my s390-fu gave up completely on that one:task_structis in 'r14', but this is a hardware entry function it appears. So to fix it we'd have to pick a temporary register, putthread_structpointer into it, and fix up these offsets:
arch/s390/kernel/asm-offsets.c:DEFINE(__THREAD_per_address, offsetof(struct task_struct, thread.per_event.address));arch/s390/kernel/asm-offsets.c:DEFINE(__THREAD_per_paid, offsetof(struct task_struct, thread.per_event.paid));arch/s390/kernel/asm-offsets.c:DEFINE(__THREAD_trap_tdb, offsetof(struct task_struct, thread.trap_tdb));to be
thread_structrelative.
Here's a stab at that: we can move 'r14' from 'current' to 'current->thread' and back relatively cheaply I think. If I got the mnemonics right.
Thanks,
Ingo
===============================>
arch/s390/kernel/asm-offsets.c | 9 +++++---- arch/s390/kernel/entry.S | 2 ++ 2 files changed, 7 insertions(+), 4 deletions(-)
arch/s390/kernel/asm-offsets.c +5 -4
@@ -24,13 +24,14 @@int main (void ) {DEFINE (__TASK_thread_info, offsetof(struct task_struct , stack)); +DEFINE (__TASK_thread_struct, offsetof(struct task_struct , thread));DEFINE (__THREAD_ksp, offsetof(struct thread_struct , ksp));BLANK ();DEFINE (__TASK_pid, offsetof(struct task_struct , pid));BLANK (); - DEFINE(__THREAD_per_cause, offsetof(struct task_struct, thread.per_event.cause)); - DEFINE(__THREAD_per_address, offsetof(struct task_struct, thread.per_event.address)); - DEFINE(__THREAD_per_paid, offsetof(struct task_struct, thread.per_event.paid)); + DEFINE(__THREAD_per_cause, offsetof(struct thread_struct, per_event.cause)); + DEFINE(__THREAD_per_address, offsetof(struct thread_struct, per_event.address)); + DEFINE(__THREAD_per_paid, offsetof(struct thread_struct, per_event.paid));BLANK ();DEFINE (__TI_task, offsetof(struct thread_info , task));DEFINE (__TI_flags, offsetof(struct thread_info , flags));
@@ -175,7 +176,7 @@ int main(void)DEFINE (__LC_VDSO_PER_CPU, offsetof(struct _lowcore , vdso_per_cpu_data));DEFINE (__LC_GMAP, offsetof(struct _lowcore , gmap));DEFINE (__LC_PGM_TDB, offsetof(struct _lowcore , pgm_tdb)); - DEFINE(__THREAD_trap_tdb, offsetof(struct task_struct, thread.trap_tdb)); +DEFINE (__THREAD_trap_tdb, offsetof(struct thread_struct , trap_tdb));DEFINE (__GMAP_ASCE, offsetof(struct gmap , asce));DEFINE (__SIE_PROG0C, offsetof(struct kvm_s390_sie_block , prog0c));DEFINE (__SIE_PROG20, offsetof(struct kvm_s390_sie_block , prog20));
arch/s390/kernel/entry.S +2 -0
@@ -421,6 +421,7 @@ ENTRY(pgm_check_handler) LAST_BREAK %r14 lg %r15,__LC_KERNEL_STACK lg %r14,__TI_task(%r12) + ahi %r14,__TASK_thread_struct # r14 now points to 'current->thread' lghi %r13,__LC_PGM_TDB tm __LC_PGM_ILC+2,0x02 # check for transaction abort jz 2f
@@ -448,6 +449,7 @@ ENTRY(pgm_check_handler) nill %r10,0x007f sll %r10,2 je .Lsysc_return + ahi %r14,-__TASK_thread_struct # r14 now points to 'current' lgf %r1,0(%r10,%r1) # load address of handler routine lgr %r2,%r11 # pass pointer to pt_regs basr %r14,%r1 # branch to interrupt-handler