diff options
-rw-r--r-- | arch/s390/include/asm/ptrace.h | 5 | ||||
-rw-r--r-- | arch/s390/include/asm/syscall.h | 5 | ||||
-rw-r--r-- | arch/s390/include/asm/thread_info.h | 1 | ||||
-rw-r--r-- | arch/s390/kernel/asm-offsets.c | 3 | ||||
-rw-r--r-- | arch/s390/kernel/compat_signal.c | 2 | ||||
-rw-r--r-- | arch/s390/kernel/entry.S | 28 | ||||
-rw-r--r-- | arch/s390/kernel/entry64.S | 30 | ||||
-rw-r--r-- | arch/s390/kernel/ptrace.c | 51 | ||||
-rw-r--r-- | arch/s390/kernel/signal.c | 107 | ||||
-rw-r--r-- | include/linux/elf.h | 1 |
10 files changed, 142 insertions, 91 deletions
diff --git a/arch/s390/include/asm/ptrace.h b/arch/s390/include/asm/ptrace.h index 62fd80c9e98c..93c907b4776f 100644 --- a/arch/s390/include/asm/ptrace.h +++ b/arch/s390/include/asm/ptrace.h | |||
@@ -328,8 +328,7 @@ struct pt_regs | |||
328 | psw_t psw; | 328 | psw_t psw; |
329 | unsigned long gprs[NUM_GPRS]; | 329 | unsigned long gprs[NUM_GPRS]; |
330 | unsigned long orig_gpr2; | 330 | unsigned long orig_gpr2; |
331 | unsigned short ilc; | 331 | unsigned int svc_code; |
332 | unsigned short svcnr; | ||
333 | }; | 332 | }; |
334 | 333 | ||
335 | /* | 334 | /* |
@@ -487,6 +486,8 @@ typedef struct | |||
487 | #define PTRACE_POKETEXT_AREA 0x5004 | 486 | #define PTRACE_POKETEXT_AREA 0x5004 |
488 | #define PTRACE_POKEDATA_AREA 0x5005 | 487 | #define PTRACE_POKEDATA_AREA 0x5005 |
489 | #define PTRACE_GET_LAST_BREAK 0x5006 | 488 | #define PTRACE_GET_LAST_BREAK 0x5006 |
489 | #define PTRACE_PEEK_SYSTEM_CALL 0x5007 | ||
490 | #define PTRACE_POKE_SYSTEM_CALL 0x5008 | ||
490 | 491 | ||
491 | /* | 492 | /* |
492 | * PT_PROT definition is loosely based on hppa bsd definition in | 493 | * PT_PROT definition is loosely based on hppa bsd definition in |
diff --git a/arch/s390/include/asm/syscall.h b/arch/s390/include/asm/syscall.h index 5c0246b955d8..614267f60713 100644 --- a/arch/s390/include/asm/syscall.h +++ b/arch/s390/include/asm/syscall.h | |||
@@ -13,6 +13,7 @@ | |||
13 | #define _ASM_SYSCALL_H 1 | 13 | #define _ASM_SYSCALL_H 1 |
14 | 14 | ||
15 | #include <linux/sched.h> | 15 | #include <linux/sched.h> |
16 | #include <linux/err.h> | ||
16 | #include <asm/ptrace.h> | 17 | #include <asm/ptrace.h> |
17 | 18 | ||
18 | /* | 19 | /* |
@@ -25,7 +26,7 @@ extern const unsigned int sys_call_table[]; | |||
25 | static inline long syscall_get_nr(struct task_struct *task, | 26 | static inline long syscall_get_nr(struct task_struct *task, |
26 | struct pt_regs *regs) | 27 | struct pt_regs *regs) |
27 | { | 28 | { |
28 | return regs->svcnr ? regs->svcnr : -1; | 29 | return regs->svc_code ? (regs->svc_code & 0xffff) : -1; |
29 | } | 30 | } |
30 | 31 | ||
31 | static inline void syscall_rollback(struct task_struct *task, | 32 | static inline void syscall_rollback(struct task_struct *task, |
@@ -37,7 +38,7 @@ static inline void syscall_rollback(struct task_struct *task, | |||
37 | static inline long syscall_get_error(struct task_struct *task, | 38 | static inline long syscall_get_error(struct task_struct *task, |
38 | struct pt_regs *regs) | 39 | struct pt_regs *regs) |
39 | { | 40 | { |
40 | return (regs->gprs[2] >= -4096UL) ? -regs->gprs[2] : 0; | 41 | return IS_ERR_VALUE(regs->gprs[2]) ? regs->gprs[2] : 0; |
41 | } | 42 | } |
42 | 43 | ||
43 | static inline long syscall_get_return_value(struct task_struct *task, | 44 | static inline long syscall_get_return_value(struct task_struct *task, |
diff --git a/arch/s390/include/asm/thread_info.h b/arch/s390/include/asm/thread_info.h index f9a9a10979c9..0c4788eb5a65 100644 --- a/arch/s390/include/asm/thread_info.h +++ b/arch/s390/include/asm/thread_info.h | |||
@@ -48,6 +48,7 @@ struct thread_info { | |||
48 | unsigned int cpu; /* current CPU */ | 48 | unsigned int cpu; /* current CPU */ |
49 | int preempt_count; /* 0 => preemptable, <0 => BUG */ | 49 | int preempt_count; /* 0 => preemptable, <0 => BUG */ |
50 | struct restart_block restart_block; | 50 | struct restart_block restart_block; |
51 | unsigned int system_call; | ||
51 | __u64 user_timer; | 52 | __u64 user_timer; |
52 | __u64 system_timer; | 53 | __u64 system_timer; |
53 | unsigned long last_break; /* last breaking-event-address. */ | 54 | unsigned long last_break; /* last breaking-event-address. */ |
diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c index 1140035b1cd8..751318765e2e 100644 --- a/arch/s390/kernel/asm-offsets.c +++ b/arch/s390/kernel/asm-offsets.c | |||
@@ -45,8 +45,7 @@ int main(void) | |||
45 | DEFINE(__PT_PSW, offsetof(struct pt_regs, psw)); | 45 | DEFINE(__PT_PSW, offsetof(struct pt_regs, psw)); |
46 | DEFINE(__PT_GPRS, offsetof(struct pt_regs, gprs)); | 46 | DEFINE(__PT_GPRS, offsetof(struct pt_regs, gprs)); |
47 | DEFINE(__PT_ORIG_GPR2, offsetof(struct pt_regs, orig_gpr2)); | 47 | DEFINE(__PT_ORIG_GPR2, offsetof(struct pt_regs, orig_gpr2)); |
48 | DEFINE(__PT_ILC, offsetof(struct pt_regs, ilc)); | 48 | DEFINE(__PT_SVC_CODE, offsetof(struct pt_regs, svc_code)); |
49 | DEFINE(__PT_SVCNR, offsetof(struct pt_regs, svcnr)); | ||
50 | DEFINE(__PT_SIZE, sizeof(struct pt_regs)); | 49 | DEFINE(__PT_SIZE, sizeof(struct pt_regs)); |
51 | BLANK(); | 50 | BLANK(); |
52 | DEFINE(__SF_BACKCHAIN, offsetof(struct stack_frame, back_chain)); | 51 | DEFINE(__SF_BACKCHAIN, offsetof(struct stack_frame, back_chain)); |
diff --git a/arch/s390/kernel/compat_signal.c b/arch/s390/kernel/compat_signal.c index a9a285b8c4ad..d7c8e54c32e7 100644 --- a/arch/s390/kernel/compat_signal.c +++ b/arch/s390/kernel/compat_signal.c | |||
@@ -342,7 +342,7 @@ static int restore_sigregs32(struct pt_regs *regs,_sigregs32 __user *sregs) | |||
342 | return err; | 342 | return err; |
343 | 343 | ||
344 | restore_fp_regs(¤t->thread.fp_regs); | 344 | restore_fp_regs(¤t->thread.fp_regs); |
345 | regs->svcnr = 0; /* disable syscall checks */ | 345 | regs->svc_code = 0; /* disable syscall checks */ |
346 | return 0; | 346 | return 0; |
347 | } | 347 | } |
348 | 348 | ||
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index 195387ab7c98..afe3685d30e7 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S | |||
@@ -43,8 +43,7 @@ SP_R13 = STACK_FRAME_OVERHEAD + __PT_GPRS + 52 | |||
43 | SP_R14 = STACK_FRAME_OVERHEAD + __PT_GPRS + 56 | 43 | SP_R14 = STACK_FRAME_OVERHEAD + __PT_GPRS + 56 |
44 | SP_R15 = STACK_FRAME_OVERHEAD + __PT_GPRS + 60 | 44 | SP_R15 = STACK_FRAME_OVERHEAD + __PT_GPRS + 60 |
45 | SP_ORIG_R2 = STACK_FRAME_OVERHEAD + __PT_ORIG_GPR2 | 45 | SP_ORIG_R2 = STACK_FRAME_OVERHEAD + __PT_ORIG_GPR2 |
46 | SP_ILC = STACK_FRAME_OVERHEAD + __PT_ILC | 46 | SP_SVC_CODE = STACK_FRAME_OVERHEAD + __PT_SVC_CODE |
47 | SP_SVCNR = STACK_FRAME_OVERHEAD + __PT_SVCNR | ||
48 | SP_SIZE = STACK_FRAME_OVERHEAD + __PT_SIZE | 47 | SP_SIZE = STACK_FRAME_OVERHEAD + __PT_SIZE |
49 | 48 | ||
50 | _TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \ | 49 | _TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \ |
@@ -229,7 +228,7 @@ sysc_saveall: | |||
229 | SAVE_ALL_SVC __LC_SVC_OLD_PSW,__LC_SAVE_AREA | 228 | SAVE_ALL_SVC __LC_SVC_OLD_PSW,__LC_SAVE_AREA |
230 | CREATE_STACK_FRAME __LC_SAVE_AREA | 229 | CREATE_STACK_FRAME __LC_SAVE_AREA |
231 | mvc SP_PSW(8,%r15),__LC_SVC_OLD_PSW | 230 | mvc SP_PSW(8,%r15),__LC_SVC_OLD_PSW |
232 | mvc SP_ILC(4,%r15),__LC_SVC_ILC | 231 | mvc SP_SVC_CODE(4,%r15),__LC_SVC_ILC |
233 | l %r12,__LC_THREAD_INFO # load pointer to thread_info struct | 232 | l %r12,__LC_THREAD_INFO # load pointer to thread_info struct |
234 | sysc_vtime: | 233 | sysc_vtime: |
235 | UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER | 234 | UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER |
@@ -239,12 +238,12 @@ sysc_update: | |||
239 | mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER | 238 | mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER |
240 | sysc_do_svc: | 239 | sysc_do_svc: |
241 | xr %r7,%r7 | 240 | xr %r7,%r7 |
242 | icm %r7,3,SP_SVCNR(%r15) # load svc number and test for svc 0 | 241 | icm %r7,3,SP_SVC_CODE+2(%r15)# load svc number and test for svc 0 |
243 | bnz BASED(sysc_nr_ok) # svc number > 0 | 242 | bnz BASED(sysc_nr_ok) # svc number > 0 |
244 | # svc 0: system call number in %r1 | 243 | # svc 0: system call number in %r1 |
245 | cl %r1,BASED(.Lnr_syscalls) | 244 | cl %r1,BASED(.Lnr_syscalls) |
246 | bnl BASED(sysc_nr_ok) | 245 | bnl BASED(sysc_nr_ok) |
247 | sth %r1,SP_SVCNR(%r15) | 246 | sth %r1,SP_SVC_CODE+2(%r15) |
248 | lr %r7,%r1 # copy svc number to %r7 | 247 | lr %r7,%r1 # copy svc number to %r7 |
249 | sysc_nr_ok: | 248 | sysc_nr_ok: |
250 | sll %r7,2 # svc number *4 | 249 | sll %r7,2 # svc number *4 |
@@ -335,10 +334,11 @@ sysc_notify_resume: | |||
335 | # | 334 | # |
336 | sysc_restart: | 335 | sysc_restart: |
337 | ni __TI_flags+3(%r12),255-_TIF_RESTART_SVC # clear TIF_RESTART_SVC | 336 | ni __TI_flags+3(%r12),255-_TIF_RESTART_SVC # clear TIF_RESTART_SVC |
338 | l %r7,SP_R2(%r15) # load new svc number | ||
339 | mvc SP_R2(4,%r15),SP_ORIG_R2(%r15) # restore first argument | ||
340 | lm %r2,%r6,SP_R2(%r15) # load svc arguments | 337 | lm %r2,%r6,SP_R2(%r15) # load svc arguments |
341 | sth %r7,SP_SVCNR(%r15) | 338 | xr %r7,%r7 # svc 0 returns -ENOSYS |
339 | clc SP_SVC_CODE+2(%r15),BASED(.Lnr_syscalls+2) | ||
340 | bnl BASED(sysc_nr_ok) # invalid svc number -> do svc 0 | ||
341 | icm %r7,3,SP_SVC_CODE+2(%r15)# load new svc number | ||
342 | b BASED(sysc_nr_ok) # restart svc | 342 | b BASED(sysc_nr_ok) # restart svc |
343 | 343 | ||
344 | # | 344 | # |
@@ -346,7 +346,7 @@ sysc_restart: | |||
346 | # | 346 | # |
347 | sysc_singlestep: | 347 | sysc_singlestep: |
348 | ni __TI_flags+3(%r12),255-_TIF_PER_TRAP # clear TIF_PER_TRAP | 348 | ni __TI_flags+3(%r12),255-_TIF_PER_TRAP # clear TIF_PER_TRAP |
349 | xc SP_SVCNR(2,%r15),SP_SVCNR(%r15) # clear svc number | 349 | xc SP_SVC_CODE(4,%r15),SP_SVC_CODE(%r15) # clear svc code |
350 | la %r2,SP_PTREGS(%r15) # address of register-save area | 350 | la %r2,SP_PTREGS(%r15) # address of register-save area |
351 | l %r1,BASED(.Lhandle_per) # load adr. of per handler | 351 | l %r1,BASED(.Lhandle_per) # load adr. of per handler |
352 | la %r14,BASED(sysc_return) # load adr. of system return | 352 | la %r14,BASED(sysc_return) # load adr. of system return |
@@ -361,7 +361,7 @@ sysc_tracesys: | |||
361 | la %r2,SP_PTREGS(%r15) # load pt_regs | 361 | la %r2,SP_PTREGS(%r15) # load pt_regs |
362 | la %r3,0 | 362 | la %r3,0 |
363 | xr %r0,%r0 | 363 | xr %r0,%r0 |
364 | icm %r0,3,SP_SVCNR(%r15) | 364 | icm %r0,3,SP_SVC_CODE(%r15) |
365 | st %r0,SP_R2(%r15) | 365 | st %r0,SP_R2(%r15) |
366 | basr %r14,%r1 | 366 | basr %r14,%r1 |
367 | cl %r2,BASED(.Lnr_syscalls) | 367 | cl %r2,BASED(.Lnr_syscalls) |
@@ -454,7 +454,7 @@ ENTRY(pgm_check_handler) | |||
454 | bnz BASED(pgm_per) # got per exception -> special case | 454 | bnz BASED(pgm_per) # got per exception -> special case |
455 | SAVE_ALL_PGM __LC_PGM_OLD_PSW,__LC_SAVE_AREA | 455 | SAVE_ALL_PGM __LC_PGM_OLD_PSW,__LC_SAVE_AREA |
456 | CREATE_STACK_FRAME __LC_SAVE_AREA | 456 | CREATE_STACK_FRAME __LC_SAVE_AREA |
457 | xc SP_ILC(4,%r15),SP_ILC(%r15) | 457 | xc SP_SVC_CODE(4,%r15),SP_SVC_CODE(%r15) |
458 | mvc SP_PSW(8,%r15),__LC_PGM_OLD_PSW | 458 | mvc SP_PSW(8,%r15),__LC_PGM_OLD_PSW |
459 | l %r12,__LC_THREAD_INFO # load pointer to thread_info struct | 459 | l %r12,__LC_THREAD_INFO # load pointer to thread_info struct |
460 | tm SP_PSW+1(%r15),0x01 # interrupting from user ? | 460 | tm SP_PSW+1(%r15),0x01 # interrupting from user ? |
@@ -531,7 +531,7 @@ pgm_svcper: | |||
531 | SAVE_ALL_PGM __LC_SVC_OLD_PSW,__LC_SAVE_AREA | 531 | SAVE_ALL_PGM __LC_SVC_OLD_PSW,__LC_SAVE_AREA |
532 | CREATE_STACK_FRAME __LC_SAVE_AREA | 532 | CREATE_STACK_FRAME __LC_SAVE_AREA |
533 | mvc SP_PSW(8,%r15),__LC_SVC_OLD_PSW | 533 | mvc SP_PSW(8,%r15),__LC_SVC_OLD_PSW |
534 | mvc SP_ILC(4,%r15),__LC_SVC_ILC | 534 | mvc SP_SVC_CODE(4,%r15),__LC_SVC_ILC |
535 | l %r12,__LC_THREAD_INFO # load pointer to thread_info struct | 535 | l %r12,__LC_THREAD_INFO # load pointer to thread_info struct |
536 | UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER | 536 | UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER |
537 | UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER | 537 | UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER |
@@ -550,7 +550,7 @@ pgm_svcper: | |||
550 | # | 550 | # |
551 | kernel_per: | 551 | kernel_per: |
552 | REENABLE_IRQS | 552 | REENABLE_IRQS |
553 | xc SP_SVCNR(2,%r15),SP_SVCNR(%r15) | 553 | xc SP_SVC_CODE(4,%r15),SP_SVC_CODE(%r15) |
554 | la %r2,SP_PTREGS(%r15) # address of register-save area | 554 | la %r2,SP_PTREGS(%r15) # address of register-save area |
555 | l %r1,BASED(.Lhandle_per) # load adr. of per handler | 555 | l %r1,BASED(.Lhandle_per) # load adr. of per handler |
556 | basr %r14,%r1 # branch to do_single_step | 556 | basr %r14,%r1 # branch to do_single_step |
@@ -966,7 +966,7 @@ cleanup_system_call: | |||
966 | st %r15,12(%r12) | 966 | st %r15,12(%r12) |
967 | CREATE_STACK_FRAME __LC_SAVE_AREA | 967 | CREATE_STACK_FRAME __LC_SAVE_AREA |
968 | mvc SP_PSW(8,%r15),__LC_SVC_OLD_PSW | 968 | mvc SP_PSW(8,%r15),__LC_SVC_OLD_PSW |
969 | mvc SP_ILC(4,%r15),__LC_SVC_ILC | 969 | mvc SP_SVC_CODE(4,%r15),__LC_SVC_ILC |
970 | mvc 0(4,%r12),__LC_THREAD_INFO | 970 | mvc 0(4,%r12),__LC_THREAD_INFO |
971 | cleanup_vtime: | 971 | cleanup_vtime: |
972 | clc __LC_RETURN_PSW+4(4),BASED(cleanup_system_call_insn+12) | 972 | clc __LC_RETURN_PSW+4(4),BASED(cleanup_system_call_insn+12) |
diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S index 3257f7f55551..7ff07d3a29c1 100644 --- a/arch/s390/kernel/entry64.S +++ b/arch/s390/kernel/entry64.S | |||
@@ -43,8 +43,7 @@ SP_R13 = STACK_FRAME_OVERHEAD + __PT_GPRS + 104 | |||
43 | SP_R14 = STACK_FRAME_OVERHEAD + __PT_GPRS + 112 | 43 | SP_R14 = STACK_FRAME_OVERHEAD + __PT_GPRS + 112 |
44 | SP_R15 = STACK_FRAME_OVERHEAD + __PT_GPRS + 120 | 44 | SP_R15 = STACK_FRAME_OVERHEAD + __PT_GPRS + 120 |
45 | SP_ORIG_R2 = STACK_FRAME_OVERHEAD + __PT_ORIG_GPR2 | 45 | SP_ORIG_R2 = STACK_FRAME_OVERHEAD + __PT_ORIG_GPR2 |
46 | SP_ILC = STACK_FRAME_OVERHEAD + __PT_ILC | 46 | SP_SVC_CODE = STACK_FRAME_OVERHEAD + __PT_SVC_CODE |
47 | SP_SVCNR = STACK_FRAME_OVERHEAD + __PT_SVCNR | ||
48 | SP_SIZE = STACK_FRAME_OVERHEAD + __PT_SIZE | 47 | SP_SIZE = STACK_FRAME_OVERHEAD + __PT_SIZE |
49 | 48 | ||
50 | STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER | 49 | STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER |
@@ -250,7 +249,7 @@ sysc_saveall: | |||
250 | SAVE_ALL_SVC __LC_SVC_OLD_PSW,__LC_SAVE_AREA | 249 | SAVE_ALL_SVC __LC_SVC_OLD_PSW,__LC_SAVE_AREA |
251 | CREATE_STACK_FRAME __LC_SAVE_AREA | 250 | CREATE_STACK_FRAME __LC_SAVE_AREA |
252 | mvc SP_PSW(16,%r15),__LC_SVC_OLD_PSW | 251 | mvc SP_PSW(16,%r15),__LC_SVC_OLD_PSW |
253 | mvc SP_ILC(4,%r15),__LC_SVC_ILC | 252 | mvc SP_SVC_CODE(4,%r15),__LC_SVC_ILC |
254 | lg %r12,__LC_THREAD_INFO # load pointer to thread_info struct | 253 | lg %r12,__LC_THREAD_INFO # load pointer to thread_info struct |
255 | sysc_vtime: | 254 | sysc_vtime: |
256 | UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER | 255 | UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER |
@@ -260,14 +259,14 @@ sysc_update: | |||
260 | mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER | 259 | mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER |
261 | LAST_BREAK | 260 | LAST_BREAK |
262 | sysc_do_svc: | 261 | sysc_do_svc: |
263 | llgh %r7,SP_SVCNR(%r15) | 262 | llgh %r7,SP_SVC_CODE+2(%r15) |
264 | slag %r7,%r7,2 # shift and test for svc 0 | 263 | slag %r7,%r7,2 # shift and test for svc 0 |
265 | jnz sysc_nr_ok | 264 | jnz sysc_nr_ok |
266 | # svc 0: system call number in %r1 | 265 | # svc 0: system call number in %r1 |
267 | llgfr %r1,%r1 # clear high word in r1 | 266 | llgfr %r1,%r1 # clear high word in r1 |
268 | cghi %r1,NR_syscalls | 267 | cghi %r1,NR_syscalls |
269 | jnl sysc_nr_ok | 268 | jnl sysc_nr_ok |
270 | sth %r1,SP_SVCNR(%r15) | 269 | sth %r1,SP_SVC_CODE+2(%r15) |
271 | slag %r7,%r1,2 # shift and test for svc 0 | 270 | slag %r7,%r1,2 # shift and test for svc 0 |
272 | sysc_nr_ok: | 271 | sysc_nr_ok: |
273 | larl %r10,sys_call_table | 272 | larl %r10,sys_call_table |
@@ -358,11 +357,12 @@ sysc_notify_resume: | |||
358 | # | 357 | # |
359 | sysc_restart: | 358 | sysc_restart: |
360 | ni __TI_flags+7(%r12),255-_TIF_RESTART_SVC # clear TIF_RESTART_SVC | 359 | ni __TI_flags+7(%r12),255-_TIF_RESTART_SVC # clear TIF_RESTART_SVC |
361 | lg %r7,SP_R2(%r15) # load new svc number | ||
362 | mvc SP_R2(8,%r15),SP_ORIG_R2(%r15) # restore first argument | ||
363 | lmg %r2,%r6,SP_R2(%r15) # load svc arguments | 360 | lmg %r2,%r6,SP_R2(%r15) # load svc arguments |
364 | sth %r7,SP_SVCNR(%r15) | 361 | lghi %r7,0 # svc 0 returns -ENOSYS |
365 | slag %r7,%r7,2 | 362 | lh %r1,SP_SVC_CODE+2(%r15) # load new svc number |
363 | cghi %r1,NR_syscalls | ||
364 | jnl sysc_nr_ok # invalid svc number -> do svc 0 | ||
365 | slag %r7,%r1,2 | ||
366 | j sysc_nr_ok # restart svc | 366 | j sysc_nr_ok # restart svc |
367 | 367 | ||
368 | # | 368 | # |
@@ -370,7 +370,7 @@ sysc_restart: | |||
370 | # | 370 | # |
371 | sysc_singlestep: | 371 | sysc_singlestep: |
372 | ni __TI_flags+7(%r12),255-_TIF_PER_TRAP # clear TIF_PER_TRAP | 372 | ni __TI_flags+7(%r12),255-_TIF_PER_TRAP # clear TIF_PER_TRAP |
373 | xc SP_SVCNR(2,%r15),SP_SVCNR(%r15) # clear svc number | 373 | xc SP_SVC_CODE(4,%r15),SP_SVC_CODE(%r15) # clear svc code |
374 | la %r2,SP_PTREGS(%r15) # address of register-save area | 374 | la %r2,SP_PTREGS(%r15) # address of register-save area |
375 | larl %r14,sysc_return # load adr. of system return | 375 | larl %r14,sysc_return # load adr. of system return |
376 | jg do_per_trap | 376 | jg do_per_trap |
@@ -382,7 +382,7 @@ sysc_singlestep: | |||
382 | sysc_tracesys: | 382 | sysc_tracesys: |
383 | la %r2,SP_PTREGS(%r15) # load pt_regs | 383 | la %r2,SP_PTREGS(%r15) # load pt_regs |
384 | la %r3,0 | 384 | la %r3,0 |
385 | llgh %r0,SP_SVCNR(%r15) | 385 | llgh %r0,SP_SVC_CODE+2(%r15) |
386 | stg %r0,SP_R2(%r15) | 386 | stg %r0,SP_R2(%r15) |
387 | brasl %r14,do_syscall_trace_enter | 387 | brasl %r14,do_syscall_trace_enter |
388 | lghi %r0,NR_syscalls | 388 | lghi %r0,NR_syscalls |
@@ -470,7 +470,7 @@ ENTRY(pgm_check_handler) | |||
470 | jnz pgm_per # got per exception -> special case | 470 | jnz pgm_per # got per exception -> special case |
471 | SAVE_ALL_PGM __LC_PGM_OLD_PSW,__LC_SAVE_AREA | 471 | SAVE_ALL_PGM __LC_PGM_OLD_PSW,__LC_SAVE_AREA |
472 | CREATE_STACK_FRAME __LC_SAVE_AREA | 472 | CREATE_STACK_FRAME __LC_SAVE_AREA |
473 | xc SP_ILC(4,%r15),SP_ILC(%r15) | 473 | xc SP_SVC_CODE(4,%r15),SP_SVC_CODE(%r15) |
474 | mvc SP_PSW(16,%r15),__LC_PGM_OLD_PSW | 474 | mvc SP_PSW(16,%r15),__LC_PGM_OLD_PSW |
475 | lg %r12,__LC_THREAD_INFO # load pointer to thread_info struct | 475 | lg %r12,__LC_THREAD_INFO # load pointer to thread_info struct |
476 | HANDLE_SIE_INTERCEPT | 476 | HANDLE_SIE_INTERCEPT |
@@ -551,7 +551,7 @@ pgm_svcper: | |||
551 | SAVE_ALL_PGM __LC_SVC_OLD_PSW,__LC_SAVE_AREA | 551 | SAVE_ALL_PGM __LC_SVC_OLD_PSW,__LC_SAVE_AREA |
552 | CREATE_STACK_FRAME __LC_SAVE_AREA | 552 | CREATE_STACK_FRAME __LC_SAVE_AREA |
553 | mvc SP_PSW(16,%r15),__LC_SVC_OLD_PSW | 553 | mvc SP_PSW(16,%r15),__LC_SVC_OLD_PSW |
554 | mvc SP_ILC(4,%r15),__LC_SVC_ILC | 554 | mvc SP_SVC_CODE(4,%r15),__LC_SVC_ILC |
555 | lg %r12,__LC_THREAD_INFO # load pointer to thread_info struct | 555 | lg %r12,__LC_THREAD_INFO # load pointer to thread_info struct |
556 | UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER | 556 | UPDATE_VTIME __LC_EXIT_TIMER,__LC_SYNC_ENTER_TIMER,__LC_USER_TIMER |
557 | UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER | 557 | UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER |
@@ -571,7 +571,7 @@ pgm_svcper: | |||
571 | # | 571 | # |
572 | kernel_per: | 572 | kernel_per: |
573 | REENABLE_IRQS | 573 | REENABLE_IRQS |
574 | xc SP_SVCNR(2,%r15),SP_SVCNR(%r15) # clear svc number | 574 | xc SP_SVC_CODE(4,%r15),SP_SVC_CODE(%r15) # clear svc number |
575 | la %r2,SP_PTREGS(%r15) # address of register-save area | 575 | la %r2,SP_PTREGS(%r15) # address of register-save area |
576 | brasl %r14,do_per_trap | 576 | brasl %r14,do_per_trap |
577 | j pgm_exit | 577 | j pgm_exit |
@@ -973,7 +973,7 @@ cleanup_system_call: | |||
973 | stg %r11,0(%r12) | 973 | stg %r11,0(%r12) |
974 | CREATE_STACK_FRAME __LC_SAVE_AREA | 974 | CREATE_STACK_FRAME __LC_SAVE_AREA |
975 | mvc SP_PSW(16,%r15),__LC_SVC_OLD_PSW | 975 | mvc SP_PSW(16,%r15),__LC_SVC_OLD_PSW |
976 | mvc SP_ILC(4,%r15),__LC_SVC_ILC | 976 | mvc SP_SVC_CODE(4,%r15),__LC_SVC_ILC |
977 | mvc 8(8,%r12),__LC_THREAD_INFO | 977 | mvc 8(8,%r12),__LC_THREAD_INFO |
978 | cleanup_vtime: | 978 | cleanup_vtime: |
979 | clc __LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn+24) | 979 | clc __LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn+24) |
diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c index ae0e14b8880c..bae1cc49fe96 100644 --- a/arch/s390/kernel/ptrace.c +++ b/arch/s390/kernel/ptrace.c | |||
@@ -42,6 +42,7 @@ enum s390_regset { | |||
42 | REGSET_GENERAL, | 42 | REGSET_GENERAL, |
43 | REGSET_FP, | 43 | REGSET_FP, |
44 | REGSET_LAST_BREAK, | 44 | REGSET_LAST_BREAK, |
45 | REGSET_SYSTEM_CALL, | ||
45 | REGSET_GENERAL_EXTENDED, | 46 | REGSET_GENERAL_EXTENDED, |
46 | }; | 47 | }; |
47 | 48 | ||
@@ -303,6 +304,13 @@ static int __poke_user(struct task_struct *child, addr_t addr, addr_t data) | |||
303 | high order bit but older gdb's rely on it */ | 304 | high order bit but older gdb's rely on it */ |
304 | data |= PSW_ADDR_AMODE; | 305 | data |= PSW_ADDR_AMODE; |
305 | #endif | 306 | #endif |
307 | if (addr == (addr_t) &dummy->regs.psw.addr) | ||
308 | /* | ||
309 | * The debugger changed the instruction address, | ||
310 | * reset system call restart, see signal.c:do_signal | ||
311 | */ | ||
312 | task_thread_info(child)->system_call = 0; | ||
313 | |||
306 | *(addr_t *)((addr_t) &task_pt_regs(child)->psw + addr) = data; | 314 | *(addr_t *)((addr_t) &task_pt_regs(child)->psw + addr) = data; |
307 | 315 | ||
308 | } else if (addr < (addr_t) (&dummy->regs.orig_gpr2)) { | 316 | } else if (addr < (addr_t) (&dummy->regs.orig_gpr2)) { |
@@ -610,6 +618,11 @@ static int __poke_user_compat(struct task_struct *child, | |||
610 | /* Build a 64 bit psw address from 31 bit address. */ | 618 | /* Build a 64 bit psw address from 31 bit address. */ |
611 | task_pt_regs(child)->psw.addr = | 619 | task_pt_regs(child)->psw.addr = |
612 | (__u64) tmp & PSW32_ADDR_INSN; | 620 | (__u64) tmp & PSW32_ADDR_INSN; |
621 | /* | ||
622 | * The debugger changed the instruction address, | ||
623 | * reset system call restart, see signal.c:do_signal | ||
624 | */ | ||
625 | task_thread_info(child)->system_call = 0; | ||
613 | } else { | 626 | } else { |
614 | /* gpr 0-15 */ | 627 | /* gpr 0-15 */ |
615 | *(__u32*)((addr_t) &task_pt_regs(child)->psw | 628 | *(__u32*)((addr_t) &task_pt_regs(child)->psw |
@@ -737,7 +750,7 @@ asmlinkage long do_syscall_trace_enter(struct pt_regs *regs) | |||
737 | * debugger stored an invalid system call number. Skip | 750 | * debugger stored an invalid system call number. Skip |
738 | * the system call and the system call restart handling. | 751 | * the system call and the system call restart handling. |
739 | */ | 752 | */ |
740 | regs->svcnr = 0; | 753 | regs->svc_code = 0; |
741 | ret = -1; | 754 | ret = -1; |
742 | } | 755 | } |
743 | 756 | ||
@@ -899,6 +912,26 @@ static int s390_last_break_get(struct task_struct *target, | |||
899 | 912 | ||
900 | #endif | 913 | #endif |
901 | 914 | ||
915 | static int s390_system_call_get(struct task_struct *target, | ||
916 | const struct user_regset *regset, | ||
917 | unsigned int pos, unsigned int count, | ||
918 | void *kbuf, void __user *ubuf) | ||
919 | { | ||
920 | unsigned int *data = &task_thread_info(target)->system_call; | ||
921 | return user_regset_copyout(&pos, &count, &kbuf, &ubuf, | ||
922 | data, 0, sizeof(unsigned int)); | ||
923 | } | ||
924 | |||
925 | static int s390_system_call_set(struct task_struct *target, | ||
926 | const struct user_regset *regset, | ||
927 | unsigned int pos, unsigned int count, | ||
928 | const void *kbuf, const void __user *ubuf) | ||
929 | { | ||
930 | unsigned int *data = &task_thread_info(target)->system_call; | ||
931 | return user_regset_copyin(&pos, &count, &kbuf, &ubuf, | ||
932 | data, 0, sizeof(unsigned int)); | ||
933 | } | ||
934 | |||
902 | static const struct user_regset s390_regsets[] = { | 935 | static const struct user_regset s390_regsets[] = { |
903 | [REGSET_GENERAL] = { | 936 | [REGSET_GENERAL] = { |
904 | .core_note_type = NT_PRSTATUS, | 937 | .core_note_type = NT_PRSTATUS, |
@@ -925,6 +958,14 @@ static const struct user_regset s390_regsets[] = { | |||
925 | .get = s390_last_break_get, | 958 | .get = s390_last_break_get, |
926 | }, | 959 | }, |
927 | #endif | 960 | #endif |
961 | [REGSET_SYSTEM_CALL] = { | ||
962 | .core_note_type = NT_S390_SYSTEM_CALL, | ||
963 | .n = 1, | ||
964 | .size = sizeof(unsigned int), | ||
965 | .align = sizeof(unsigned int), | ||
966 | .get = s390_system_call_get, | ||
967 | .set = s390_system_call_set, | ||
968 | }, | ||
928 | }; | 969 | }; |
929 | 970 | ||
930 | static const struct user_regset_view user_s390_view = { | 971 | static const struct user_regset_view user_s390_view = { |
@@ -1104,6 +1145,14 @@ static const struct user_regset s390_compat_regsets[] = { | |||
1104 | .align = sizeof(long), | 1145 | .align = sizeof(long), |
1105 | .get = s390_compat_last_break_get, | 1146 | .get = s390_compat_last_break_get, |
1106 | }, | 1147 | }, |
1148 | [REGSET_SYSTEM_CALL] = { | ||
1149 | .core_note_type = NT_S390_SYSTEM_CALL, | ||
1150 | .n = 1, | ||
1151 | .size = sizeof(compat_uint_t), | ||
1152 | .align = sizeof(compat_uint_t), | ||
1153 | .get = s390_system_call_get, | ||
1154 | .set = s390_system_call_set, | ||
1155 | }, | ||
1107 | [REGSET_GENERAL_EXTENDED] = { | 1156 | [REGSET_GENERAL_EXTENDED] = { |
1108 | .core_note_type = NT_S390_HIGH_GPRS, | 1157 | .core_note_type = NT_S390_HIGH_GPRS, |
1109 | .n = sizeof(s390_compat_regs_high) / sizeof(compat_long_t), | 1158 | .n = sizeof(s390_compat_regs_high) / sizeof(compat_long_t), |
diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c index 9a40e1cc5ec3..e751cab80e04 100644 --- a/arch/s390/kernel/signal.c +++ b/arch/s390/kernel/signal.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <asm/ucontext.h> | 30 | #include <asm/ucontext.h> |
31 | #include <asm/uaccess.h> | 31 | #include <asm/uaccess.h> |
32 | #include <asm/lowcore.h> | 32 | #include <asm/lowcore.h> |
33 | #include <asm/compat.h> | ||
33 | #include "entry.h" | 34 | #include "entry.h" |
34 | 35 | ||
35 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) | 36 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) |
@@ -156,7 +157,7 @@ static int restore_sigregs(struct pt_regs *regs, _sigregs __user *sregs) | |||
156 | current->thread.fp_regs.fpc &= FPC_VALID_MASK; | 157 | current->thread.fp_regs.fpc &= FPC_VALID_MASK; |
157 | 158 | ||
158 | restore_fp_regs(¤t->thread.fp_regs); | 159 | restore_fp_regs(¤t->thread.fp_regs); |
159 | regs->svcnr = 0; /* disable syscall checks */ | 160 | regs->svc_code = 0; /* disable syscall checks */ |
160 | return 0; | 161 | return 0; |
161 | } | 162 | } |
162 | 163 | ||
@@ -401,7 +402,6 @@ static int handle_signal(unsigned long sig, struct k_sigaction *ka, | |||
401 | */ | 402 | */ |
402 | void do_signal(struct pt_regs *regs) | 403 | void do_signal(struct pt_regs *regs) |
403 | { | 404 | { |
404 | unsigned long retval = 0, continue_addr = 0, restart_addr = 0; | ||
405 | siginfo_t info; | 405 | siginfo_t info; |
406 | int signr; | 406 | int signr; |
407 | struct k_sigaction ka; | 407 | struct k_sigaction ka; |
@@ -421,54 +421,43 @@ void do_signal(struct pt_regs *regs) | |||
421 | else | 421 | else |
422 | oldset = ¤t->blocked; | 422 | oldset = ¤t->blocked; |
423 | 423 | ||
424 | /* Are we from a system call? */ | 424 | /* |
425 | if (regs->svcnr) { | 425 | * Get signal to deliver. When running under ptrace, at this point |
426 | continue_addr = regs->psw.addr; | 426 | * the debugger may change all our registers, including the system |
427 | restart_addr = continue_addr - regs->ilc; | 427 | * call information. |
428 | retval = regs->gprs[2]; | 428 | */ |
429 | 429 | current_thread_info()->system_call = regs->svc_code; | |
430 | /* Prepare for system call restart. We do this here so that a | ||
431 | debugger will see the already changed PSW. */ | ||
432 | switch (retval) { | ||
433 | case -ERESTARTNOHAND: | ||
434 | case -ERESTARTSYS: | ||
435 | case -ERESTARTNOINTR: | ||
436 | regs->gprs[2] = regs->orig_gpr2; | ||
437 | regs->psw.addr = restart_addr; | ||
438 | break; | ||
439 | case -ERESTART_RESTARTBLOCK: | ||
440 | regs->gprs[2] = -EINTR; | ||
441 | } | ||
442 | regs->svcnr = 0; /* Don't deal with this again. */ | ||
443 | } | ||
444 | |||
445 | /* Get signal to deliver. When running under ptrace, at this point | ||
446 | the debugger may change all our registers ... */ | ||
447 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); | 430 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); |
448 | 431 | regs->svc_code = current_thread_info()->system_call; | |
449 | /* Depending on the signal settings we may need to revert the | ||
450 | decision to restart the system call. */ | ||
451 | if (signr > 0 && regs->psw.addr == restart_addr) { | ||
452 | if (retval == -ERESTARTNOHAND | ||
453 | || (retval == -ERESTARTSYS | ||
454 | && !(current->sighand->action[signr-1].sa.sa_flags | ||
455 | & SA_RESTART))) { | ||
456 | regs->gprs[2] = -EINTR; | ||
457 | regs->psw.addr = continue_addr; | ||
458 | } | ||
459 | } | ||
460 | 432 | ||
461 | if (signr > 0) { | 433 | if (signr > 0) { |
462 | /* Whee! Actually deliver the signal. */ | 434 | /* Whee! Actually deliver the signal. */ |
463 | int ret; | 435 | if (regs->svc_code > 0) { |
464 | #ifdef CONFIG_COMPAT | 436 | /* Check for system call restarting. */ |
465 | if (is_compat_task()) { | 437 | switch (regs->gprs[2]) { |
466 | ret = handle_signal32(signr, &ka, &info, oldset, regs); | 438 | case -ERESTART_RESTARTBLOCK: |
467 | } | 439 | case -ERESTARTNOHAND: |
468 | else | 440 | regs->gprs[2] = -EINTR; |
469 | #endif | 441 | break; |
470 | ret = handle_signal(signr, &ka, &info, oldset, regs); | 442 | case -ERESTARTSYS: |
471 | if (!ret) { | 443 | if (!(ka.sa.sa_flags & SA_RESTART)) { |
444 | regs->gprs[2] = -EINTR; | ||
445 | break; | ||
446 | } | ||
447 | /* fallthrough */ | ||
448 | case -ERESTARTNOINTR: | ||
449 | regs->gprs[2] = regs->orig_gpr2; | ||
450 | regs->psw.addr = regs->psw.addr - | ||
451 | (regs->svc_code >> 16); | ||
452 | break; | ||
453 | } | ||
454 | /* No longer in a system call */ | ||
455 | regs->svc_code = 0; | ||
456 | } | ||
457 | |||
458 | if ((is_compat_task() ? | ||
459 | handle_signal32(signr, &ka, &info, oldset, regs) : | ||
460 | handle_signal(signr, &ka, &info, oldset, regs)) == 0) { | ||
472 | /* | 461 | /* |
473 | * A signal was successfully delivered; the saved | 462 | * A signal was successfully delivered; the saved |
474 | * sigmask will have been stored in the signal frame, | 463 | * sigmask will have been stored in the signal frame, |
@@ -482,11 +471,28 @@ void do_signal(struct pt_regs *regs) | |||
482 | * Let tracing know that we've done the handler setup. | 471 | * Let tracing know that we've done the handler setup. |
483 | */ | 472 | */ |
484 | tracehook_signal_handler(signr, &info, &ka, regs, | 473 | tracehook_signal_handler(signr, &info, &ka, regs, |
485 | test_thread_flag(TIF_SINGLE_STEP)); | 474 | test_thread_flag(TIF_SINGLE_STEP)); |
486 | } | 475 | } |
487 | return; | 476 | return; |
488 | } | 477 | } |
489 | 478 | ||
479 | /* No handlers present - check for system call restart */ | ||
480 | if (regs->svc_code > 0) { | ||
481 | switch (regs->gprs[2]) { | ||
482 | case -ERESTART_RESTARTBLOCK: | ||
483 | /* Restart with sys_restart_syscall */ | ||
484 | regs->svc_code = __NR_restart_syscall; | ||
485 | /* fallthrough */ | ||
486 | case -ERESTARTNOHAND: | ||
487 | case -ERESTARTSYS: | ||
488 | case -ERESTARTNOINTR: | ||
489 | /* Restart system call with magic TIF bit. */ | ||
490 | regs->gprs[2] = regs->orig_gpr2; | ||
491 | set_thread_flag(TIF_RESTART_SVC); | ||
492 | break; | ||
493 | } | ||
494 | } | ||
495 | |||
490 | /* | 496 | /* |
491 | * If there's no signal to deliver, we just put the saved sigmask back. | 497 | * If there's no signal to deliver, we just put the saved sigmask back. |
492 | */ | 498 | */ |
@@ -494,13 +500,6 @@ void do_signal(struct pt_regs *regs) | |||
494 | clear_thread_flag(TIF_RESTORE_SIGMASK); | 500 | clear_thread_flag(TIF_RESTORE_SIGMASK); |
495 | sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); | 501 | sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); |
496 | } | 502 | } |
497 | |||
498 | /* Restart a different system call. */ | ||
499 | if (retval == -ERESTART_RESTARTBLOCK | ||
500 | && regs->psw.addr == continue_addr) { | ||
501 | regs->gprs[2] = __NR_restart_syscall; | ||
502 | set_thread_flag(TIF_RESTART_SVC); | ||
503 | } | ||
504 | } | 503 | } |
505 | 504 | ||
506 | void do_notify_resume(struct pt_regs *regs) | 505 | void do_notify_resume(struct pt_regs *regs) |
diff --git a/include/linux/elf.h b/include/linux/elf.h index 110821cb6ea5..31f0508d7da7 100644 --- a/include/linux/elf.h +++ b/include/linux/elf.h | |||
@@ -395,6 +395,7 @@ typedef struct elf64_shdr { | |||
395 | #define NT_S390_CTRS 0x304 /* s390 control registers */ | 395 | #define NT_S390_CTRS 0x304 /* s390 control registers */ |
396 | #define NT_S390_PREFIX 0x305 /* s390 prefix register */ | 396 | #define NT_S390_PREFIX 0x305 /* s390 prefix register */ |
397 | #define NT_S390_LAST_BREAK 0x306 /* s390 breaking event address */ | 397 | #define NT_S390_LAST_BREAK 0x306 /* s390 breaking event address */ |
398 | #define NT_S390_SYSTEM_CALL 0x307 /* s390 system call restart data */ | ||
398 | #define NT_ARM_VFP 0x400 /* ARM VFP/NEON registers */ | 399 | #define NT_ARM_VFP 0x400 /* ARM VFP/NEON registers */ |
399 | 400 | ||
400 | 401 | ||