diff options
Diffstat (limited to 'arch/s390/include/asm')
-rw-r--r-- | arch/s390/include/asm/cpu_mf.h | 2 | ||||
-rw-r--r-- | arch/s390/include/asm/perf_event.h | 7 | ||||
-rw-r--r-- | arch/s390/include/asm/processor.h | 2 | ||||
-rw-r--r-- | arch/s390/include/asm/stacktrace.h | 36 | ||||
-rw-r--r-- | arch/s390/include/asm/unwind.h | 8 | ||||
-rw-r--r-- | arch/s390/include/asm/vdso.h | 13 |
6 files changed, 54 insertions, 14 deletions
diff --git a/arch/s390/include/asm/cpu_mf.h b/arch/s390/include/asm/cpu_mf.h index 819803a97c2b..0d90cbeb89b4 100644 --- a/arch/s390/include/asm/cpu_mf.h +++ b/arch/s390/include/asm/cpu_mf.h @@ -313,7 +313,7 @@ static inline unsigned long *trailer_entry_ptr(unsigned long v) return (unsigned long *) ret; } -/* Return if the entry in the sample data block table (sdbt) +/* Return true if the entry in the sample data block table (sdbt) * is a link to the next sdbt */ static inline int is_link_entry(unsigned long *s) { diff --git a/arch/s390/include/asm/perf_event.h b/arch/s390/include/asm/perf_event.h index 4652ffffe0b2..b9da71632827 100644 --- a/arch/s390/include/asm/perf_event.h +++ b/arch/s390/include/asm/perf_event.h @@ -12,6 +12,7 @@ #include <linux/perf_event.h> #include <linux/device.h> +#include <asm/stacktrace.h> /* Per-CPU flags for PMU states */ #define PMU_F_RESERVED 0x1000 @@ -73,4 +74,10 @@ struct perf_sf_sde_regs { #define SDB_FULL_BLOCKS(hwc) (SAMPL_FLAGS(hwc) & PERF_CPUM_SF_FULL_BLOCKS) #define SAMPLE_FREQ_MODE(hwc) (SAMPL_FLAGS(hwc) & PERF_CPUM_SF_FREQ_MODE) +#define perf_arch_fetch_caller_regs(regs, __ip) do { \ + (regs)->psw.addr = (__ip); \ + (regs)->gprs[15] = (unsigned long)__builtin_frame_address(0) - \ + offsetof(struct stack_frame, back_chain); \ +} while (0) + #endif /* _ASM_S390_PERF_EVENT_H */ diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h index 881fc37c11c6..361ef5eda468 100644 --- a/arch/s390/include/asm/processor.h +++ b/arch/s390/include/asm/processor.h @@ -310,7 +310,7 @@ void enabled_wait(void); /* * Function to drop a processor into disabled wait state */ -static inline void __noreturn disabled_wait(void) +static __always_inline void __noreturn disabled_wait(void) { psw_t psw; diff --git a/arch/s390/include/asm/stacktrace.h b/arch/s390/include/asm/stacktrace.h index fee40212af11..ee056f4a4fa3 100644 --- a/arch/s390/include/asm/stacktrace.h +++ b/arch/s390/include/asm/stacktrace.h @@ -33,12 +33,12 @@ static inline bool on_stack(struct stack_info *info, return addr >= info->begin && addr + len <= info->end; } -static inline unsigned long get_stack_pointer(struct task_struct *task, - struct pt_regs *regs) +static __always_inline unsigned long get_stack_pointer(struct task_struct *task, + struct pt_regs *regs) { if (regs) return (unsigned long) kernel_stack_pointer(regs); - if (!task || task == current) + if (task == current) return current_stack_pointer(); return (unsigned long) task->thread.ksp; } @@ -62,6 +62,17 @@ struct stack_frame { }; #endif +/* + * Unlike current_stack_pointer() which simply returns current value of %r15 + * current_frame_address() returns function stack frame address, which matches + * %r15 upon function invocation. It may differ from %r15 later if function + * allocates stack for local variables or new stack frame to call other + * functions. + */ +#define current_frame_address() \ + ((unsigned long)__builtin_frame_address(0) - \ + offsetof(struct stack_frame, back_chain)) + #define CALL_ARGS_0() \ register unsigned long r2 asm("2") #define CALL_ARGS_1(arg1) \ @@ -95,20 +106,33 @@ struct stack_frame { #define CALL_ON_STACK(fn, stack, nr, args...) \ ({ \ + unsigned long frame = current_frame_address(); \ CALL_ARGS_##nr(args); \ unsigned long prev; \ \ asm volatile( \ " la %[_prev],0(15)\n" \ - " la 15,0(%[_stack])\n" \ - " stg %[_prev],%[_bc](15)\n" \ + " lg 15,%[_stack]\n" \ + " stg %[_frame],%[_bc](15)\n" \ " brasl 14,%[_fn]\n" \ " la 15,0(%[_prev])\n" \ : [_prev] "=&a" (prev), CALL_FMT_##nr \ - [_stack] "a" (stack), \ + [_stack] "R" (stack), \ [_bc] "i" (offsetof(struct stack_frame, back_chain)), \ + [_frame] "d" (frame), \ [_fn] "X" (fn) : CALL_CLOBBER_##nr); \ r2; \ }) +#define CALL_ON_STACK_NORETURN(fn, stack) \ +({ \ + asm volatile( \ + " la 15,0(%[_stack])\n" \ + " xc %[_bc](8,15),%[_bc](15)\n" \ + " brasl 14,%[_fn]\n" \ + ::[_bc] "i" (offsetof(struct stack_frame, back_chain)), \ + [_stack] "a" (stack), [_fn] "X" (fn)); \ + BUG(); \ +}) + #endif /* _ASM_S390_STACKTRACE_H */ diff --git a/arch/s390/include/asm/unwind.h b/arch/s390/include/asm/unwind.h index eaaefeceef6f..de9006b0cfeb 100644 --- a/arch/s390/include/asm/unwind.h +++ b/arch/s390/include/asm/unwind.h @@ -35,7 +35,6 @@ struct unwind_state { struct task_struct *task; struct pt_regs *regs; unsigned long sp, ip; - bool reuse_sp; int graph_idx; bool reliable; bool error; @@ -59,10 +58,11 @@ static inline bool unwind_error(struct unwind_state *state) static inline void unwind_start(struct unwind_state *state, struct task_struct *task, struct pt_regs *regs, - unsigned long sp) + unsigned long first_frame) { - sp = sp ? : get_stack_pointer(task, regs); - __unwind_start(state, task, regs, sp); + task = task ?: current; + first_frame = first_frame ?: get_stack_pointer(task, regs); + __unwind_start(state, task, regs, first_frame); } static inline struct pt_regs *unwind_get_entry_regs(struct unwind_state *state) diff --git a/arch/s390/include/asm/vdso.h b/arch/s390/include/asm/vdso.h index 169d7604eb80..3bcfdeb01395 100644 --- a/arch/s390/include/asm/vdso.h +++ b/arch/s390/include/asm/vdso.h @@ -41,8 +41,17 @@ struct vdso_data { struct vdso_per_cpu_data { __u64 ectg_timer_base; __u64 ectg_user_time; - __u32 cpu_nr; - __u32 node_id; + /* + * Note: node_id and cpu_nr must be at adjacent memory locations. + * VDSO userspace must read both values with a single instruction. + */ + union { + __u64 getcpu_val; + struct { + __u32 node_id; + __u32 cpu_nr; + }; + }; }; extern struct vdso_data *vdso_data; |