diff options
Diffstat (limited to 'arch/s390')
-rw-r--r-- | arch/s390/Kconfig | 1 | ||||
-rw-r--r-- | arch/s390/include/asm/dasd.h | 13 | ||||
-rw-r--r-- | arch/s390/include/asm/delay.h | 1 | ||||
-rw-r--r-- | arch/s390/include/asm/pgtable.h | 45 | ||||
-rw-r--r-- | arch/s390/include/asm/ptrace.h | 1 | ||||
-rw-r--r-- | arch/s390/include/asm/qdio.h | 8 | ||||
-rw-r--r-- | arch/s390/include/asm/syscall.h | 80 | ||||
-rw-r--r-- | arch/s390/include/asm/thread_info.h | 2 | ||||
-rw-r--r-- | arch/s390/kernel/compat_linux.c | 8 | ||||
-rw-r--r-- | arch/s390/kernel/compat_linux.h | 1 | ||||
-rw-r--r-- | arch/s390/kernel/compat_ptrace.h | 1 | ||||
-rw-r--r-- | arch/s390/kernel/compat_wrapper.S | 2 | ||||
-rw-r--r-- | arch/s390/kernel/entry.S | 50 | ||||
-rw-r--r-- | arch/s390/kernel/entry64.S | 42 | ||||
-rw-r--r-- | arch/s390/kernel/ptrace.c | 89 | ||||
-rw-r--r-- | arch/s390/kernel/signal.c | 13 | ||||
-rw-r--r-- | arch/s390/kernel/smp.c | 2 | ||||
-rw-r--r-- | arch/s390/kernel/syscalls.S | 2 | ||||
-rw-r--r-- | arch/s390/kernel/time.c | 4 | ||||
-rw-r--r-- | arch/s390/lib/delay.c | 101 | ||||
-rw-r--r-- | arch/s390/mm/extmem.c | 251 |
21 files changed, 580 insertions, 137 deletions
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 8d41908e2513..4c03049e7db9 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig | |||
@@ -74,6 +74,7 @@ config S390 | |||
74 | select HAVE_KPROBES | 74 | select HAVE_KPROBES |
75 | select HAVE_KRETPROBES | 75 | select HAVE_KRETPROBES |
76 | select HAVE_KVM if 64BIT | 76 | select HAVE_KVM if 64BIT |
77 | select HAVE_ARCH_TRACEHOOK | ||
77 | 78 | ||
78 | source "init/Kconfig" | 79 | source "init/Kconfig" |
79 | 80 | ||
diff --git a/arch/s390/include/asm/dasd.h b/arch/s390/include/asm/dasd.h index 3f002e13d024..55b2b80cdf6e 100644 --- a/arch/s390/include/asm/dasd.h +++ b/arch/s390/include/asm/dasd.h | |||
@@ -3,6 +3,8 @@ | |||
3 | * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com> | 3 | * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com> |
4 | * Bugreports.to..: <Linux390@de.ibm.com> | 4 | * Bugreports.to..: <Linux390@de.ibm.com> |
5 | * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 | 5 | * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 |
6 | * EMC Symmetrix ioctl Copyright EMC Corporation, 2008 | ||
7 | * Author.........: Nigel Hislop <hislop_nigel@emc.com> | ||
6 | * | 8 | * |
7 | * This file is the interface of the DASD device driver, which is exported to user space | 9 | * This file is the interface of the DASD device driver, which is exported to user space |
8 | * any future changes wrt the API will result in a change of the APIVERSION reported | 10 | * any future changes wrt the API will result in a change of the APIVERSION reported |
@@ -202,6 +204,16 @@ typedef struct attrib_data_t { | |||
202 | #define DASD_SEQ_PRESTAGE 0x4 | 204 | #define DASD_SEQ_PRESTAGE 0x4 |
203 | #define DASD_REC_ACCESS 0x5 | 205 | #define DASD_REC_ACCESS 0x5 |
204 | 206 | ||
207 | /* | ||
208 | * Perform EMC Symmetrix I/O | ||
209 | */ | ||
210 | typedef struct dasd_symmio_parms { | ||
211 | unsigned char reserved[8]; /* compat with older releases */ | ||
212 | unsigned long long psf_data; /* char * cast to u64 */ | ||
213 | unsigned long long rssd_result; /* char * cast to u64 */ | ||
214 | int psf_data_len; | ||
215 | int rssd_result_len; | ||
216 | } __attribute__ ((packed)) dasd_symmio_parms_t; | ||
205 | 217 | ||
206 | /******************************************************************************** | 218 | /******************************************************************************** |
207 | * SECTION: Definition of IOCTLs | 219 | * SECTION: Definition of IOCTLs |
@@ -247,6 +259,7 @@ typedef struct attrib_data_t { | |||
247 | /* Set Attributes (cache operations) */ | 259 | /* Set Attributes (cache operations) */ |
248 | #define BIODASDSATTR _IOW(DASD_IOCTL_LETTER,2,attrib_data_t) | 260 | #define BIODASDSATTR _IOW(DASD_IOCTL_LETTER,2,attrib_data_t) |
249 | 261 | ||
262 | #define BIODASDSYMMIO _IOWR(DASD_IOCTL_LETTER, 240, dasd_symmio_parms_t) | ||
250 | 263 | ||
251 | #endif /* DASD_H */ | 264 | #endif /* DASD_H */ |
252 | 265 | ||
diff --git a/arch/s390/include/asm/delay.h b/arch/s390/include/asm/delay.h index 78357314c450..a356c958e260 100644 --- a/arch/s390/include/asm/delay.h +++ b/arch/s390/include/asm/delay.h | |||
@@ -15,6 +15,7 @@ | |||
15 | #define _S390_DELAY_H | 15 | #define _S390_DELAY_H |
16 | 16 | ||
17 | extern void __udelay(unsigned long usecs); | 17 | extern void __udelay(unsigned long usecs); |
18 | extern void udelay_simple(unsigned long usecs); | ||
18 | extern void __delay(unsigned long loops); | 19 | extern void __delay(unsigned long loops); |
19 | 20 | ||
20 | #define udelay(n) __udelay(n) | 21 | #define udelay(n) __udelay(n) |
diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h index 0bdb704ae051..1a928f84afd6 100644 --- a/arch/s390/include/asm/pgtable.h +++ b/arch/s390/include/asm/pgtable.h | |||
@@ -281,6 +281,9 @@ extern char empty_zero_page[PAGE_SIZE]; | |||
281 | #define RCP_GR_BIT 50 | 281 | #define RCP_GR_BIT 50 |
282 | #define RCP_GC_BIT 49 | 282 | #define RCP_GC_BIT 49 |
283 | 283 | ||
284 | /* User dirty bit for KVM's migration feature */ | ||
285 | #define KVM_UD_BIT 47 | ||
286 | |||
284 | #ifndef __s390x__ | 287 | #ifndef __s390x__ |
285 | 288 | ||
286 | /* Bits in the segment table address-space-control-element */ | 289 | /* Bits in the segment table address-space-control-element */ |
@@ -575,12 +578,16 @@ static inline void ptep_rcp_copy(pte_t *ptep) | |||
575 | unsigned long *pgste = (unsigned long *) (ptep + PTRS_PER_PTE); | 578 | unsigned long *pgste = (unsigned long *) (ptep + PTRS_PER_PTE); |
576 | 579 | ||
577 | skey = page_get_storage_key(page_to_phys(page)); | 580 | skey = page_get_storage_key(page_to_phys(page)); |
578 | if (skey & _PAGE_CHANGED) | 581 | if (skey & _PAGE_CHANGED) { |
579 | set_bit_simple(RCP_GC_BIT, pgste); | 582 | set_bit_simple(RCP_GC_BIT, pgste); |
583 | set_bit_simple(KVM_UD_BIT, pgste); | ||
584 | } | ||
580 | if (skey & _PAGE_REFERENCED) | 585 | if (skey & _PAGE_REFERENCED) |
581 | set_bit_simple(RCP_GR_BIT, pgste); | 586 | set_bit_simple(RCP_GR_BIT, pgste); |
582 | if (test_and_clear_bit_simple(RCP_HC_BIT, pgste)) | 587 | if (test_and_clear_bit_simple(RCP_HC_BIT, pgste)) { |
583 | SetPageDirty(page); | 588 | SetPageDirty(page); |
589 | set_bit_simple(KVM_UD_BIT, pgste); | ||
590 | } | ||
584 | if (test_and_clear_bit_simple(RCP_HR_BIT, pgste)) | 591 | if (test_and_clear_bit_simple(RCP_HR_BIT, pgste)) |
585 | SetPageReferenced(page); | 592 | SetPageReferenced(page); |
586 | #endif | 593 | #endif |
@@ -744,6 +751,40 @@ static inline pte_t pte_mkspecial(pte_t pte) | |||
744 | return pte; | 751 | return pte; |
745 | } | 752 | } |
746 | 753 | ||
754 | #ifdef CONFIG_PGSTE | ||
755 | /* | ||
756 | * Get (and clear) the user dirty bit for a PTE. | ||
757 | */ | ||
758 | static inline int kvm_s390_test_and_clear_page_dirty(struct mm_struct *mm, | ||
759 | pte_t *ptep) | ||
760 | { | ||
761 | int dirty; | ||
762 | unsigned long *pgste; | ||
763 | struct page *page; | ||
764 | unsigned int skey; | ||
765 | |||
766 | if (!mm->context.pgstes) | ||
767 | return -EINVAL; | ||
768 | rcp_lock(ptep); | ||
769 | pgste = (unsigned long *) (ptep + PTRS_PER_PTE); | ||
770 | page = virt_to_page(pte_val(*ptep)); | ||
771 | skey = page_get_storage_key(page_to_phys(page)); | ||
772 | if (skey & _PAGE_CHANGED) { | ||
773 | set_bit_simple(RCP_GC_BIT, pgste); | ||
774 | set_bit_simple(KVM_UD_BIT, pgste); | ||
775 | } | ||
776 | if (test_and_clear_bit_simple(RCP_HC_BIT, pgste)) { | ||
777 | SetPageDirty(page); | ||
778 | set_bit_simple(KVM_UD_BIT, pgste); | ||
779 | } | ||
780 | dirty = test_and_clear_bit_simple(KVM_UD_BIT, pgste); | ||
781 | if (skey & _PAGE_CHANGED) | ||
782 | page_clear_dirty(page); | ||
783 | rcp_unlock(ptep); | ||
784 | return dirty; | ||
785 | } | ||
786 | #endif | ||
787 | |||
747 | #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG | 788 | #define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG |
748 | static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, | 789 | static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, |
749 | unsigned long addr, pte_t *ptep) | 790 | unsigned long addr, pte_t *ptep) |
diff --git a/arch/s390/include/asm/ptrace.h b/arch/s390/include/asm/ptrace.h index af2c9ac28a07..a7226f8143fb 100644 --- a/arch/s390/include/asm/ptrace.h +++ b/arch/s390/include/asm/ptrace.h | |||
@@ -490,6 +490,7 @@ extern void user_disable_single_step(struct task_struct *); | |||
490 | 490 | ||
491 | #define user_mode(regs) (((regs)->psw.mask & PSW_MASK_PSTATE) != 0) | 491 | #define user_mode(regs) (((regs)->psw.mask & PSW_MASK_PSTATE) != 0) |
492 | #define instruction_pointer(regs) ((regs)->psw.addr & PSW_ADDR_INSN) | 492 | #define instruction_pointer(regs) ((regs)->psw.addr & PSW_ADDR_INSN) |
493 | #define user_stack_pointer(regs)((regs)->gprs[15]) | ||
493 | #define regs_return_value(regs)((regs)->gprs[2]) | 494 | #define regs_return_value(regs)((regs)->gprs[2]) |
494 | #define profile_pc(regs) instruction_pointer(regs) | 495 | #define profile_pc(regs) instruction_pointer(regs) |
495 | extern void show_regs(struct pt_regs * regs); | 496 | extern void show_regs(struct pt_regs * regs); |
diff --git a/arch/s390/include/asm/qdio.h b/arch/s390/include/asm/qdio.h index 6813772171f2..4734c3f05354 100644 --- a/arch/s390/include/asm/qdio.h +++ b/arch/s390/include/asm/qdio.h | |||
@@ -299,7 +299,13 @@ struct qdio_ssqd_desc { | |||
299 | u8 mbccnt; | 299 | u8 mbccnt; |
300 | u16 qdioac2; | 300 | u16 qdioac2; |
301 | u64 sch_token; | 301 | u64 sch_token; |
302 | u64:64; | 302 | u8 mro; |
303 | u8 mri; | ||
304 | u8:8; | ||
305 | u8 sbalic; | ||
306 | u16:16; | ||
307 | u8:8; | ||
308 | u8 mmwc; | ||
303 | } __attribute__ ((packed)); | 309 | } __attribute__ ((packed)); |
304 | 310 | ||
305 | /* params are: ccw_device, qdio_error, queue_number, | 311 | /* params are: ccw_device, qdio_error, queue_number, |
diff --git a/arch/s390/include/asm/syscall.h b/arch/s390/include/asm/syscall.h new file mode 100644 index 000000000000..6e623971fbb9 --- /dev/null +++ b/arch/s390/include/asm/syscall.h | |||
@@ -0,0 +1,80 @@ | |||
1 | /* | ||
2 | * Access to user system call parameters and results | ||
3 | * | ||
4 | * Copyright IBM Corp. 2008 | ||
5 | * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com) | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License (version 2 only) | ||
9 | * as published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #ifndef _ASM_SYSCALL_H | ||
13 | #define _ASM_SYSCALL_H 1 | ||
14 | |||
15 | #include <asm/ptrace.h> | ||
16 | |||
17 | static inline long syscall_get_nr(struct task_struct *task, | ||
18 | struct pt_regs *regs) | ||
19 | { | ||
20 | if (regs->trap != __LC_SVC_OLD_PSW) | ||
21 | return -1; | ||
22 | return regs->gprs[2]; | ||
23 | } | ||
24 | |||
25 | static inline void syscall_rollback(struct task_struct *task, | ||
26 | struct pt_regs *regs) | ||
27 | { | ||
28 | regs->gprs[2] = regs->orig_gpr2; | ||
29 | } | ||
30 | |||
31 | static inline long syscall_get_error(struct task_struct *task, | ||
32 | struct pt_regs *regs) | ||
33 | { | ||
34 | return (regs->gprs[2] >= -4096UL) ? -regs->gprs[2] : 0; | ||
35 | } | ||
36 | |||
37 | static inline long syscall_get_return_value(struct task_struct *task, | ||
38 | struct pt_regs *regs) | ||
39 | { | ||
40 | return regs->gprs[2]; | ||
41 | } | ||
42 | |||
43 | static inline void syscall_set_return_value(struct task_struct *task, | ||
44 | struct pt_regs *regs, | ||
45 | int error, long val) | ||
46 | { | ||
47 | regs->gprs[2] = error ? -error : val; | ||
48 | } | ||
49 | |||
50 | static inline void syscall_get_arguments(struct task_struct *task, | ||
51 | struct pt_regs *regs, | ||
52 | unsigned int i, unsigned int n, | ||
53 | unsigned long *args) | ||
54 | { | ||
55 | BUG_ON(i + n > 6); | ||
56 | #ifdef CONFIG_COMPAT | ||
57 | if (test_tsk_thread_flag(task, TIF_31BIT)) { | ||
58 | if (i + n == 6) | ||
59 | args[--n] = (u32) regs->args[0]; | ||
60 | while (n-- > 0) | ||
61 | args[n] = (u32) regs->gprs[2 + i + n]; | ||
62 | } | ||
63 | #endif | ||
64 | if (i + n == 6) | ||
65 | args[--n] = regs->args[0]; | ||
66 | memcpy(args, ®s->gprs[2 + i], n * sizeof(args[0])); | ||
67 | } | ||
68 | |||
69 | static inline void syscall_set_arguments(struct task_struct *task, | ||
70 | struct pt_regs *regs, | ||
71 | unsigned int i, unsigned int n, | ||
72 | const unsigned long *args) | ||
73 | { | ||
74 | BUG_ON(i + n > 6); | ||
75 | if (i + n == 6) | ||
76 | regs->args[0] = args[--n]; | ||
77 | memcpy(®s->gprs[2 + i], args, n * sizeof(args[0])); | ||
78 | } | ||
79 | |||
80 | #endif /* _ASM_SYSCALL_H */ | ||
diff --git a/arch/s390/include/asm/thread_info.h b/arch/s390/include/asm/thread_info.h index 91a8f93ad355..ea40a9d690fc 100644 --- a/arch/s390/include/asm/thread_info.h +++ b/arch/s390/include/asm/thread_info.h | |||
@@ -86,6 +86,7 @@ static inline struct thread_info *current_thread_info(void) | |||
86 | * thread information flags bit numbers | 86 | * thread information flags bit numbers |
87 | */ | 87 | */ |
88 | #define TIF_SYSCALL_TRACE 0 /* syscall trace active */ | 88 | #define TIF_SYSCALL_TRACE 0 /* syscall trace active */ |
89 | #define TIF_NOTIFY_RESUME 1 /* callback before returning to user */ | ||
89 | #define TIF_SIGPENDING 2 /* signal pending */ | 90 | #define TIF_SIGPENDING 2 /* signal pending */ |
90 | #define TIF_NEED_RESCHED 3 /* rescheduling necessary */ | 91 | #define TIF_NEED_RESCHED 3 /* rescheduling necessary */ |
91 | #define TIF_RESTART_SVC 4 /* restart svc with new svc number */ | 92 | #define TIF_RESTART_SVC 4 /* restart svc with new svc number */ |
@@ -100,6 +101,7 @@ static inline struct thread_info *current_thread_info(void) | |||
100 | #define TIF_RESTORE_SIGMASK 20 /* restore signal mask in do_signal() */ | 101 | #define TIF_RESTORE_SIGMASK 20 /* restore signal mask in do_signal() */ |
101 | 102 | ||
102 | #define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE) | 103 | #define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE) |
104 | #define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME) | ||
103 | #define _TIF_RESTORE_SIGMASK (1<<TIF_RESTORE_SIGMASK) | 105 | #define _TIF_RESTORE_SIGMASK (1<<TIF_RESTORE_SIGMASK) |
104 | #define _TIF_SIGPENDING (1<<TIF_SIGPENDING) | 106 | #define _TIF_SIGPENDING (1<<TIF_SIGPENDING) |
105 | #define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED) | 107 | #define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED) |
diff --git a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c index d7f22226fc4e..98e246dc0233 100644 --- a/arch/s390/kernel/compat_linux.c +++ b/arch/s390/kernel/compat_linux.c | |||
@@ -608,14 +608,6 @@ asmlinkage long sys32_settimeofday(struct compat_timeval __user *tv, struct time | |||
608 | return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL); | 608 | return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL); |
609 | } | 609 | } |
610 | 610 | ||
611 | /* These are here just in case some old sparc32 binary calls it. */ | ||
612 | asmlinkage long sys32_pause(void) | ||
613 | { | ||
614 | current->state = TASK_INTERRUPTIBLE; | ||
615 | schedule(); | ||
616 | return -ERESTARTNOHAND; | ||
617 | } | ||
618 | |||
619 | asmlinkage long sys32_pread64(unsigned int fd, char __user *ubuf, | 611 | asmlinkage long sys32_pread64(unsigned int fd, char __user *ubuf, |
620 | size_t count, u32 poshi, u32 poslo) | 612 | size_t count, u32 poshi, u32 poslo) |
621 | { | 613 | { |
diff --git a/arch/s390/kernel/compat_linux.h b/arch/s390/kernel/compat_linux.h index 20723a062017..05f8516366ab 100644 --- a/arch/s390/kernel/compat_linux.h +++ b/arch/s390/kernel/compat_linux.h | |||
@@ -206,7 +206,6 @@ long sys32_gettimeofday(struct compat_timeval __user *tv, | |||
206 | struct timezone __user *tz); | 206 | struct timezone __user *tz); |
207 | long sys32_settimeofday(struct compat_timeval __user *tv, | 207 | long sys32_settimeofday(struct compat_timeval __user *tv, |
208 | struct timezone __user *tz); | 208 | struct timezone __user *tz); |
209 | long sys32_pause(void); | ||
210 | long sys32_pread64(unsigned int fd, char __user *ubuf, size_t count, | 209 | long sys32_pread64(unsigned int fd, char __user *ubuf, size_t count, |
211 | u32 poshi, u32 poslo); | 210 | u32 poshi, u32 poslo); |
212 | long sys32_pwrite64(unsigned int fd, const char __user *ubuf, | 211 | long sys32_pwrite64(unsigned int fd, const char __user *ubuf, |
diff --git a/arch/s390/kernel/compat_ptrace.h b/arch/s390/kernel/compat_ptrace.h index cde81fa64f89..a2be3a978d5c 100644 --- a/arch/s390/kernel/compat_ptrace.h +++ b/arch/s390/kernel/compat_ptrace.h | |||
@@ -42,6 +42,7 @@ struct user_regs_struct32 | |||
42 | u32 gprs[NUM_GPRS]; | 42 | u32 gprs[NUM_GPRS]; |
43 | u32 acrs[NUM_ACRS]; | 43 | u32 acrs[NUM_ACRS]; |
44 | u32 orig_gpr2; | 44 | u32 orig_gpr2; |
45 | /* nb: there's a 4-byte hole here */ | ||
45 | s390_fp_regs fp_regs; | 46 | s390_fp_regs fp_regs; |
46 | /* | 47 | /* |
47 | * These per registers are in here so that gdb can modify them | 48 | * These per registers are in here so that gdb can modify them |
diff --git a/arch/s390/kernel/compat_wrapper.S b/arch/s390/kernel/compat_wrapper.S index 328a20e880b5..ee51ca9e23b5 100644 --- a/arch/s390/kernel/compat_wrapper.S +++ b/arch/s390/kernel/compat_wrapper.S | |||
@@ -128,8 +128,6 @@ sys32_alarm_wrapper: | |||
128 | llgfr %r2,%r2 # unsigned int | 128 | llgfr %r2,%r2 # unsigned int |
129 | jg sys_alarm # branch to system call | 129 | jg sys_alarm # branch to system call |
130 | 130 | ||
131 | #sys32_pause_wrapper # void | ||
132 | |||
133 | .globl compat_sys_utime_wrapper | 131 | .globl compat_sys_utime_wrapper |
134 | compat_sys_utime_wrapper: | 132 | compat_sys_utime_wrapper: |
135 | llgtr %r2,%r2 # char * | 133 | llgtr %r2,%r2 # char * |
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index 708cf9cf9a35..ed500ef799b7 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S | |||
@@ -49,9 +49,9 @@ SP_ILC = STACK_FRAME_OVERHEAD + __PT_ILC | |||
49 | SP_TRAP = STACK_FRAME_OVERHEAD + __PT_TRAP | 49 | SP_TRAP = STACK_FRAME_OVERHEAD + __PT_TRAP |
50 | SP_SIZE = STACK_FRAME_OVERHEAD + __PT_SIZE | 50 | SP_SIZE = STACK_FRAME_OVERHEAD + __PT_SIZE |
51 | 51 | ||
52 | _TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | \ | 52 | _TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \ |
53 | _TIF_MCCK_PENDING | _TIF_RESTART_SVC | _TIF_SINGLE_STEP ) | 53 | _TIF_MCCK_PENDING | _TIF_RESTART_SVC | _TIF_SINGLE_STEP ) |
54 | _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | \ | 54 | _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \ |
55 | _TIF_MCCK_PENDING) | 55 | _TIF_MCCK_PENDING) |
56 | 56 | ||
57 | STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER | 57 | STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER |
@@ -318,6 +318,8 @@ sysc_work: | |||
318 | bo BASED(sysc_reschedule) | 318 | bo BASED(sysc_reschedule) |
319 | tm __TI_flags+3(%r9),_TIF_SIGPENDING | 319 | tm __TI_flags+3(%r9),_TIF_SIGPENDING |
320 | bnz BASED(sysc_sigpending) | 320 | bnz BASED(sysc_sigpending) |
321 | tm __TI_flags+3(%r9),_TIF_NOTIFY_RESUME | ||
322 | bnz BASED(sysc_notify_resume) | ||
321 | tm __TI_flags+3(%r9),_TIF_RESTART_SVC | 323 | tm __TI_flags+3(%r9),_TIF_RESTART_SVC |
322 | bo BASED(sysc_restart) | 324 | bo BASED(sysc_restart) |
323 | tm __TI_flags+3(%r9),_TIF_SINGLE_STEP | 325 | tm __TI_flags+3(%r9),_TIF_SINGLE_STEP |
@@ -356,6 +358,16 @@ sysc_sigpending: | |||
356 | b BASED(sysc_work_loop) | 358 | b BASED(sysc_work_loop) |
357 | 359 | ||
358 | # | 360 | # |
361 | # _TIF_NOTIFY_RESUME is set, call do_notify_resume | ||
362 | # | ||
363 | sysc_notify_resume: | ||
364 | la %r2,SP_PTREGS(%r15) # load pt_regs | ||
365 | l %r1,BASED(.Ldo_notify_resume) | ||
366 | la %r14,BASED(sysc_work_loop) | ||
367 | br %r1 # call do_notify_resume | ||
368 | |||
369 | |||
370 | # | ||
359 | # _TIF_RESTART_SVC is set, set up registers and restart svc | 371 | # _TIF_RESTART_SVC is set, set up registers and restart svc |
360 | # | 372 | # |
361 | sysc_restart: | 373 | sysc_restart: |
@@ -378,20 +390,21 @@ sysc_singlestep: | |||
378 | br %r1 # branch to do_single_step | 390 | br %r1 # branch to do_single_step |
379 | 391 | ||
380 | # | 392 | # |
381 | # call trace before and after sys_call | 393 | # call tracehook_report_syscall_entry/tracehook_report_syscall_exit before |
394 | # and after the system call | ||
382 | # | 395 | # |
383 | sysc_tracesys: | 396 | sysc_tracesys: |
384 | l %r1,BASED(.Ltrace) | 397 | l %r1,BASED(.Ltrace_entry) |
385 | la %r2,SP_PTREGS(%r15) # load pt_regs | 398 | la %r2,SP_PTREGS(%r15) # load pt_regs |
386 | la %r3,0 | 399 | la %r3,0 |
387 | srl %r7,2 | 400 | srl %r7,2 |
388 | st %r7,SP_R2(%r15) | 401 | st %r7,SP_R2(%r15) |
389 | basr %r14,%r1 | 402 | basr %r14,%r1 |
390 | clc SP_R2(4,%r15),BASED(.Lnr_syscalls) | 403 | cl %r2,BASED(.Lnr_syscalls) |
391 | bnl BASED(sysc_tracenogo) | 404 | bnl BASED(sysc_tracenogo) |
392 | l %r8,BASED(.Lsysc_table) | 405 | l %r8,BASED(.Lsysc_table) |
393 | l %r7,SP_R2(%r15) # strace might have changed the | 406 | lr %r7,%r2 |
394 | sll %r7,2 # system call | 407 | sll %r7,2 # *4 |
395 | l %r8,0(%r7,%r8) | 408 | l %r8,0(%r7,%r8) |
396 | sysc_tracego: | 409 | sysc_tracego: |
397 | lm %r3,%r6,SP_R3(%r15) | 410 | lm %r3,%r6,SP_R3(%r15) |
@@ -401,9 +414,8 @@ sysc_tracego: | |||
401 | sysc_tracenogo: | 414 | sysc_tracenogo: |
402 | tm __TI_flags+3(%r9),(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT) | 415 | tm __TI_flags+3(%r9),(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT) |
403 | bz BASED(sysc_return) | 416 | bz BASED(sysc_return) |
404 | l %r1,BASED(.Ltrace) | 417 | l %r1,BASED(.Ltrace_exit) |
405 | la %r2,SP_PTREGS(%r15) # load pt_regs | 418 | la %r2,SP_PTREGS(%r15) # load pt_regs |
406 | la %r3,1 | ||
407 | la %r14,BASED(sysc_return) | 419 | la %r14,BASED(sysc_return) |
408 | br %r1 | 420 | br %r1 |
409 | 421 | ||
@@ -666,6 +678,8 @@ io_work_loop: | |||
666 | bo BASED(io_reschedule) | 678 | bo BASED(io_reschedule) |
667 | tm __TI_flags+3(%r9),_TIF_SIGPENDING | 679 | tm __TI_flags+3(%r9),_TIF_SIGPENDING |
668 | bnz BASED(io_sigpending) | 680 | bnz BASED(io_sigpending) |
681 | tm __TI_flags+3(%r9),_TIF_NOTIFY_RESUME | ||
682 | bnz BASED(io_notify_resume) | ||
669 | b BASED(io_restore) | 683 | b BASED(io_restore) |
670 | io_work_done: | 684 | io_work_done: |
671 | 685 | ||
@@ -704,6 +718,19 @@ io_sigpending: | |||
704 | TRACE_IRQS_OFF | 718 | TRACE_IRQS_OFF |
705 | b BASED(io_work_loop) | 719 | b BASED(io_work_loop) |
706 | 720 | ||
721 | # | ||
722 | # _TIF_SIGPENDING is set, call do_signal | ||
723 | # | ||
724 | io_notify_resume: | ||
725 | TRACE_IRQS_ON | ||
726 | stosm __SF_EMPTY(%r15),0x03 # reenable interrupts | ||
727 | la %r2,SP_PTREGS(%r15) # load pt_regs | ||
728 | l %r1,BASED(.Ldo_notify_resume) | ||
729 | basr %r14,%r1 # call do_signal | ||
730 | stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts | ||
731 | TRACE_IRQS_OFF | ||
732 | b BASED(io_work_loop) | ||
733 | |||
707 | /* | 734 | /* |
708 | * External interrupt handler routine | 735 | * External interrupt handler routine |
709 | */ | 736 | */ |
@@ -1070,6 +1097,8 @@ cleanup_io_leave_insn: | |||
1070 | .Ldo_IRQ: .long do_IRQ | 1097 | .Ldo_IRQ: .long do_IRQ |
1071 | .Ldo_extint: .long do_extint | 1098 | .Ldo_extint: .long do_extint |
1072 | .Ldo_signal: .long do_signal | 1099 | .Ldo_signal: .long do_signal |
1100 | .Ldo_notify_resume: | ||
1101 | .long do_notify_resume | ||
1073 | .Lhandle_per: .long do_single_step | 1102 | .Lhandle_per: .long do_single_step |
1074 | .Ldo_execve: .long do_execve | 1103 | .Ldo_execve: .long do_execve |
1075 | .Lexecve_tail: .long execve_tail | 1104 | .Lexecve_tail: .long execve_tail |
@@ -1079,7 +1108,8 @@ cleanup_io_leave_insn: | |||
1079 | .Lpreempt_schedule_irq: | 1108 | .Lpreempt_schedule_irq: |
1080 | .long preempt_schedule_irq | 1109 | .long preempt_schedule_irq |
1081 | #endif | 1110 | #endif |
1082 | .Ltrace: .long syscall_trace | 1111 | .Ltrace_entry: .long do_syscall_trace_enter |
1112 | .Ltrace_exit: .long do_syscall_trace_exit | ||
1083 | .Lschedtail: .long schedule_tail | 1113 | .Lschedtail: .long schedule_tail |
1084 | .Lsysc_table: .long sys_call_table | 1114 | .Lsysc_table: .long sys_call_table |
1085 | #ifdef CONFIG_TRACE_IRQFLAGS | 1115 | #ifdef CONFIG_TRACE_IRQFLAGS |
diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S index fee10177dbfc..d7ce150453f2 100644 --- a/arch/s390/kernel/entry64.S +++ b/arch/s390/kernel/entry64.S | |||
@@ -52,9 +52,9 @@ SP_SIZE = STACK_FRAME_OVERHEAD + __PT_SIZE | |||
52 | STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER | 52 | STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER |
53 | STACK_SIZE = 1 << STACK_SHIFT | 53 | STACK_SIZE = 1 << STACK_SHIFT |
54 | 54 | ||
55 | _TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | \ | 55 | _TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \ |
56 | _TIF_MCCK_PENDING | _TIF_RESTART_SVC | _TIF_SINGLE_STEP ) | 56 | _TIF_MCCK_PENDING | _TIF_RESTART_SVC | _TIF_SINGLE_STEP ) |
57 | _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | \ | 57 | _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \ |
58 | _TIF_MCCK_PENDING) | 58 | _TIF_MCCK_PENDING) |
59 | 59 | ||
60 | #define BASED(name) name-system_call(%r13) | 60 | #define BASED(name) name-system_call(%r13) |
@@ -310,6 +310,8 @@ sysc_work: | |||
310 | jo sysc_reschedule | 310 | jo sysc_reschedule |
311 | tm __TI_flags+7(%r9),_TIF_SIGPENDING | 311 | tm __TI_flags+7(%r9),_TIF_SIGPENDING |
312 | jnz sysc_sigpending | 312 | jnz sysc_sigpending |
313 | tm __TI_flags+7(%r9),_TIF_NOTIFY_RESUME | ||
314 | jnz sysc_notify_resume | ||
313 | tm __TI_flags+7(%r9),_TIF_RESTART_SVC | 315 | tm __TI_flags+7(%r9),_TIF_RESTART_SVC |
314 | jo sysc_restart | 316 | jo sysc_restart |
315 | tm __TI_flags+7(%r9),_TIF_SINGLE_STEP | 317 | tm __TI_flags+7(%r9),_TIF_SINGLE_STEP |
@@ -345,6 +347,14 @@ sysc_sigpending: | |||
345 | j sysc_work_loop | 347 | j sysc_work_loop |
346 | 348 | ||
347 | # | 349 | # |
350 | # _TIF_NOTIFY_RESUME is set, call do_notify_resume | ||
351 | # | ||
352 | sysc_notify_resume: | ||
353 | la %r2,SP_PTREGS(%r15) # load pt_regs | ||
354 | larl %r14,sysc_work_loop | ||
355 | jg do_notify_resume # call do_notify_resume | ||
356 | |||
357 | # | ||
348 | # _TIF_RESTART_SVC is set, set up registers and restart svc | 358 | # _TIF_RESTART_SVC is set, set up registers and restart svc |
349 | # | 359 | # |
350 | sysc_restart: | 360 | sysc_restart: |
@@ -367,20 +377,19 @@ sysc_singlestep: | |||
367 | jg do_single_step # branch to do_sigtrap | 377 | jg do_single_step # branch to do_sigtrap |
368 | 378 | ||
369 | # | 379 | # |
370 | # call syscall_trace before and after system call | 380 | # call tracehook_report_syscall_entry/tracehook_report_syscall_exit before |
371 | # special linkage: %r12 contains the return address for trace_svc | 381 | # and after the system call |
372 | # | 382 | # |
373 | sysc_tracesys: | 383 | sysc_tracesys: |
374 | la %r2,SP_PTREGS(%r15) # load pt_regs | 384 | la %r2,SP_PTREGS(%r15) # load pt_regs |
375 | la %r3,0 | 385 | la %r3,0 |
376 | srl %r7,2 | 386 | srl %r7,2 |
377 | stg %r7,SP_R2(%r15) | 387 | stg %r7,SP_R2(%r15) |
378 | brasl %r14,syscall_trace | 388 | brasl %r14,do_syscall_trace_enter |
379 | lghi %r0,NR_syscalls | 389 | lghi %r0,NR_syscalls |
380 | clg %r0,SP_R2(%r15) | 390 | clgr %r0,%r2 |
381 | jnh sysc_tracenogo | 391 | jnh sysc_tracenogo |
382 | lg %r7,SP_R2(%r15) # strace might have changed the | 392 | slag %r7,%r2,2 # *4 |
383 | sll %r7,2 # system call | ||
384 | lgf %r8,0(%r7,%r10) | 393 | lgf %r8,0(%r7,%r10) |
385 | sysc_tracego: | 394 | sysc_tracego: |
386 | lmg %r3,%r6,SP_R3(%r15) | 395 | lmg %r3,%r6,SP_R3(%r15) |
@@ -391,9 +400,8 @@ sysc_tracenogo: | |||
391 | tm __TI_flags+7(%r9),(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT) | 400 | tm __TI_flags+7(%r9),(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT) |
392 | jz sysc_return | 401 | jz sysc_return |
393 | la %r2,SP_PTREGS(%r15) # load pt_regs | 402 | la %r2,SP_PTREGS(%r15) # load pt_regs |
394 | la %r3,1 | ||
395 | larl %r14,sysc_return # return point is sysc_return | 403 | larl %r14,sysc_return # return point is sysc_return |
396 | jg syscall_trace | 404 | jg do_syscall_trace_exit |
397 | 405 | ||
398 | # | 406 | # |
399 | # a new process exits the kernel with ret_from_fork | 407 | # a new process exits the kernel with ret_from_fork |
@@ -672,6 +680,8 @@ io_work_loop: | |||
672 | jo io_reschedule | 680 | jo io_reschedule |
673 | tm __TI_flags+7(%r9),_TIF_SIGPENDING | 681 | tm __TI_flags+7(%r9),_TIF_SIGPENDING |
674 | jnz io_sigpending | 682 | jnz io_sigpending |
683 | tm __TI_flags+7(%r9),_TIF_NOTIFY_RESUME | ||
684 | jnz io_notify_resume | ||
675 | j io_restore | 685 | j io_restore |
676 | io_work_done: | 686 | io_work_done: |
677 | 687 | ||
@@ -712,6 +722,18 @@ io_sigpending: | |||
712 | TRACE_IRQS_OFF | 722 | TRACE_IRQS_OFF |
713 | j io_work_loop | 723 | j io_work_loop |
714 | 724 | ||
725 | # | ||
726 | # _TIF_NOTIFY_RESUME or is set, call do_notify_resume | ||
727 | # | ||
728 | io_notify_resume: | ||
729 | TRACE_IRQS_ON | ||
730 | stosm __SF_EMPTY(%r15),0x03 # reenable interrupts | ||
731 | la %r2,SP_PTREGS(%r15) # load pt_regs | ||
732 | brasl %r14,do_notify_resume # call do_notify_resume | ||
733 | stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts | ||
734 | TRACE_IRQS_OFF | ||
735 | j io_work_loop | ||
736 | |||
715 | /* | 737 | /* |
716 | * External interrupt handler routine | 738 | * External interrupt handler routine |
717 | */ | 739 | */ |
diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c index 2815bfe348a6..1f31be1ecc4b 100644 --- a/arch/s390/kernel/ptrace.c +++ b/arch/s390/kernel/ptrace.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <linux/signal.h> | 35 | #include <linux/signal.h> |
36 | #include <linux/elf.h> | 36 | #include <linux/elf.h> |
37 | #include <linux/regset.h> | 37 | #include <linux/regset.h> |
38 | #include <linux/tracehook.h> | ||
38 | 39 | ||
39 | #include <asm/segment.h> | 40 | #include <asm/segment.h> |
40 | #include <asm/page.h> | 41 | #include <asm/page.h> |
@@ -170,6 +171,13 @@ static unsigned long __peek_user(struct task_struct *child, addr_t addr) | |||
170 | */ | 171 | */ |
171 | tmp = (addr_t) task_pt_regs(child)->orig_gpr2; | 172 | tmp = (addr_t) task_pt_regs(child)->orig_gpr2; |
172 | 173 | ||
174 | } else if (addr < (addr_t) &dummy->regs.fp_regs) { | ||
175 | /* | ||
176 | * prevent reads of padding hole between | ||
177 | * orig_gpr2 and fp_regs on s390. | ||
178 | */ | ||
179 | tmp = 0; | ||
180 | |||
173 | } else if (addr < (addr_t) (&dummy->regs.fp_regs + 1)) { | 181 | } else if (addr < (addr_t) (&dummy->regs.fp_regs + 1)) { |
174 | /* | 182 | /* |
175 | * floating point regs. are stored in the thread structure | 183 | * floating point regs. are stored in the thread structure |
@@ -270,6 +278,13 @@ static int __poke_user(struct task_struct *child, addr_t addr, addr_t data) | |||
270 | */ | 278 | */ |
271 | task_pt_regs(child)->orig_gpr2 = data; | 279 | task_pt_regs(child)->orig_gpr2 = data; |
272 | 280 | ||
281 | } else if (addr < (addr_t) &dummy->regs.fp_regs) { | ||
282 | /* | ||
283 | * prevent writes of padding hole between | ||
284 | * orig_gpr2 and fp_regs on s390. | ||
285 | */ | ||
286 | return 0; | ||
287 | |||
273 | } else if (addr < (addr_t) (&dummy->regs.fp_regs + 1)) { | 288 | } else if (addr < (addr_t) (&dummy->regs.fp_regs + 1)) { |
274 | /* | 289 | /* |
275 | * floating point regs. are stored in the thread structure | 290 | * floating point regs. are stored in the thread structure |
@@ -428,6 +443,13 @@ static u32 __peek_user_compat(struct task_struct *child, addr_t addr) | |||
428 | */ | 443 | */ |
429 | tmp = *(__u32*)((addr_t) &task_pt_regs(child)->orig_gpr2 + 4); | 444 | tmp = *(__u32*)((addr_t) &task_pt_regs(child)->orig_gpr2 + 4); |
430 | 445 | ||
446 | } else if (addr < (addr_t) &dummy32->regs.fp_regs) { | ||
447 | /* | ||
448 | * prevent reads of padding hole between | ||
449 | * orig_gpr2 and fp_regs on s390. | ||
450 | */ | ||
451 | tmp = 0; | ||
452 | |||
431 | } else if (addr < (addr_t) (&dummy32->regs.fp_regs + 1)) { | 453 | } else if (addr < (addr_t) (&dummy32->regs.fp_regs + 1)) { |
432 | /* | 454 | /* |
433 | * floating point regs. are stored in the thread structure | 455 | * floating point regs. are stored in the thread structure |
@@ -514,6 +536,13 @@ static int __poke_user_compat(struct task_struct *child, | |||
514 | */ | 536 | */ |
515 | *(__u32*)((addr_t) &task_pt_regs(child)->orig_gpr2 + 4) = tmp; | 537 | *(__u32*)((addr_t) &task_pt_regs(child)->orig_gpr2 + 4) = tmp; |
516 | 538 | ||
539 | } else if (addr < (addr_t) &dummy32->regs.fp_regs) { | ||
540 | /* | ||
541 | * prevent writess of padding hole between | ||
542 | * orig_gpr2 and fp_regs on s390. | ||
543 | */ | ||
544 | return 0; | ||
545 | |||
517 | } else if (addr < (addr_t) (&dummy32->regs.fp_regs + 1)) { | 546 | } else if (addr < (addr_t) (&dummy32->regs.fp_regs + 1)) { |
518 | /* | 547 | /* |
519 | * floating point regs. are stored in the thread structure | 548 | * floating point regs. are stored in the thread structure |
@@ -611,40 +640,44 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, | |||
611 | } | 640 | } |
612 | #endif | 641 | #endif |
613 | 642 | ||
614 | asmlinkage void | 643 | asmlinkage long do_syscall_trace_enter(struct pt_regs *regs) |
615 | syscall_trace(struct pt_regs *regs, int entryexit) | ||
616 | { | 644 | { |
617 | if (unlikely(current->audit_context) && entryexit) | 645 | long ret; |
618 | audit_syscall_exit(AUDITSC_RESULT(regs->gprs[2]), regs->gprs[2]); | ||
619 | |||
620 | if (!test_thread_flag(TIF_SYSCALL_TRACE)) | ||
621 | goto out; | ||
622 | if (!(current->ptrace & PT_PTRACED)) | ||
623 | goto out; | ||
624 | ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) | ||
625 | ? 0x80 : 0)); | ||
626 | 646 | ||
627 | /* | 647 | /* |
628 | * If the debuffer has set an invalid system call number, | 648 | * The sysc_tracesys code in entry.S stored the system |
629 | * we prepare to skip the system call restart handling. | 649 | * call number to gprs[2]. |
630 | */ | 650 | */ |
631 | if (!entryexit && regs->gprs[2] >= NR_syscalls) | 651 | ret = regs->gprs[2]; |
652 | if (test_thread_flag(TIF_SYSCALL_TRACE) && | ||
653 | (tracehook_report_syscall_entry(regs) || | ||
654 | regs->gprs[2] >= NR_syscalls)) { | ||
655 | /* | ||
656 | * Tracing decided this syscall should not happen or the | ||
657 | * debugger stored an invalid system call number. Skip | ||
658 | * the system call and the system call restart handling. | ||
659 | */ | ||
632 | regs->trap = -1; | 660 | regs->trap = -1; |
633 | 661 | ret = -1; | |
634 | /* | ||
635 | * this isn't the same as continuing with a signal, but it will do | ||
636 | * for normal use. strace only continues with a signal if the | ||
637 | * stopping signal is not SIGTRAP. -brl | ||
638 | */ | ||
639 | if (current->exit_code) { | ||
640 | send_sig(current->exit_code, current, 1); | ||
641 | current->exit_code = 0; | ||
642 | } | 662 | } |
643 | out: | 663 | |
644 | if (unlikely(current->audit_context) && !entryexit) | 664 | if (unlikely(current->audit_context)) |
645 | audit_syscall_entry(test_thread_flag(TIF_31BIT)?AUDIT_ARCH_S390:AUDIT_ARCH_S390X, | 665 | audit_syscall_entry(test_thread_flag(TIF_31BIT) ? |
646 | regs->gprs[2], regs->orig_gpr2, regs->gprs[3], | 666 | AUDIT_ARCH_S390 : AUDIT_ARCH_S390X, |
647 | regs->gprs[4], regs->gprs[5]); | 667 | regs->gprs[2], regs->orig_gpr2, |
668 | regs->gprs[3], regs->gprs[4], | ||
669 | regs->gprs[5]); | ||
670 | return ret; | ||
671 | } | ||
672 | |||
673 | asmlinkage void do_syscall_trace_exit(struct pt_regs *regs) | ||
674 | { | ||
675 | if (unlikely(current->audit_context)) | ||
676 | audit_syscall_exit(AUDITSC_RESULT(regs->gprs[2]), | ||
677 | regs->gprs[2]); | ||
678 | |||
679 | if (test_thread_flag(TIF_SYSCALL_TRACE)) | ||
680 | tracehook_report_syscall_exit(regs, 0); | ||
648 | } | 681 | } |
649 | 682 | ||
650 | /* | 683 | /* |
diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c index b97682040215..4f7fc3059a8e 100644 --- a/arch/s390/kernel/signal.c +++ b/arch/s390/kernel/signal.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/tty.h> | 24 | #include <linux/tty.h> |
25 | #include <linux/personality.h> | 25 | #include <linux/personality.h> |
26 | #include <linux/binfmts.h> | 26 | #include <linux/binfmts.h> |
27 | #include <linux/tracehook.h> | ||
27 | #include <asm/ucontext.h> | 28 | #include <asm/ucontext.h> |
28 | #include <asm/uaccess.h> | 29 | #include <asm/uaccess.h> |
29 | #include <asm/lowcore.h> | 30 | #include <asm/lowcore.h> |
@@ -507,6 +508,12 @@ void do_signal(struct pt_regs *regs) | |||
507 | */ | 508 | */ |
508 | if (current->thread.per_info.single_step) | 509 | if (current->thread.per_info.single_step) |
509 | set_thread_flag(TIF_SINGLE_STEP); | 510 | set_thread_flag(TIF_SINGLE_STEP); |
511 | |||
512 | /* | ||
513 | * Let tracing know that we've done the handler setup. | ||
514 | */ | ||
515 | tracehook_signal_handler(signr, &info, &ka, regs, | ||
516 | test_thread_flag(TIF_SINGLE_STEP)); | ||
510 | } | 517 | } |
511 | return; | 518 | return; |
512 | } | 519 | } |
@@ -526,3 +533,9 @@ void do_signal(struct pt_regs *regs) | |||
526 | set_thread_flag(TIF_RESTART_SVC); | 533 | set_thread_flag(TIF_RESTART_SVC); |
527 | } | 534 | } |
528 | } | 535 | } |
536 | |||
537 | void do_notify_resume(struct pt_regs *regs) | ||
538 | { | ||
539 | clear_thread_flag(TIF_NOTIFY_RESUME); | ||
540 | tracehook_notify_resume(regs); | ||
541 | } | ||
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 00b9b4dec5eb..9e8b1f9b8f4d 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c | |||
@@ -585,6 +585,8 @@ int __cpuinit start_secondary(void *cpuvoid) | |||
585 | /* Enable pfault pseudo page faults on this cpu. */ | 585 | /* Enable pfault pseudo page faults on this cpu. */ |
586 | pfault_init(); | 586 | pfault_init(); |
587 | 587 | ||
588 | /* call cpu notifiers */ | ||
589 | notify_cpu_starting(smp_processor_id()); | ||
588 | /* Mark this cpu as online */ | 590 | /* Mark this cpu as online */ |
589 | spin_lock(&call_lock); | 591 | spin_lock(&call_lock); |
590 | cpu_set(smp_processor_id(), cpu_online_map); | 592 | cpu_set(smp_processor_id(), cpu_online_map); |
diff --git a/arch/s390/kernel/syscalls.S b/arch/s390/kernel/syscalls.S index c66d35e55142..3ae303914b42 100644 --- a/arch/s390/kernel/syscalls.S +++ b/arch/s390/kernel/syscalls.S | |||
@@ -37,7 +37,7 @@ SYSCALL(sys_stime,sys_ni_syscall,sys32_stime_wrapper) /* 25 old stime syscall * | |||
37 | SYSCALL(sys_ptrace,sys_ptrace,sys32_ptrace_wrapper) | 37 | SYSCALL(sys_ptrace,sys_ptrace,sys32_ptrace_wrapper) |
38 | SYSCALL(sys_alarm,sys_alarm,sys32_alarm_wrapper) | 38 | SYSCALL(sys_alarm,sys_alarm,sys32_alarm_wrapper) |
39 | NI_SYSCALL /* old fstat syscall */ | 39 | NI_SYSCALL /* old fstat syscall */ |
40 | SYSCALL(sys_pause,sys_pause,sys32_pause) | 40 | SYSCALL(sys_pause,sys_pause,sys_pause) |
41 | SYSCALL(sys_utime,sys_utime,compat_sys_utime_wrapper) /* 30 */ | 41 | SYSCALL(sys_utime,sys_utime,compat_sys_utime_wrapper) /* 30 */ |
42 | NI_SYSCALL /* old stty syscall */ | 42 | NI_SYSCALL /* old stty syscall */ |
43 | NI_SYSCALL /* old gtty syscall */ | 43 | NI_SYSCALL /* old gtty syscall */ |
diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c index ca114fe46ffb..b94e9e3b694a 100644 --- a/arch/s390/kernel/time.c +++ b/arch/s390/kernel/time.c | |||
@@ -169,6 +169,8 @@ void init_cpu_timer(void) | |||
169 | 169 | ||
170 | static void clock_comparator_interrupt(__u16 code) | 170 | static void clock_comparator_interrupt(__u16 code) |
171 | { | 171 | { |
172 | if (S390_lowcore.clock_comparator == -1ULL) | ||
173 | set_clock_comparator(S390_lowcore.clock_comparator); | ||
172 | } | 174 | } |
173 | 175 | ||
174 | static void etr_timing_alert(struct etr_irq_parm *); | 176 | static void etr_timing_alert(struct etr_irq_parm *); |
@@ -1354,7 +1356,7 @@ static void __init stp_reset(void) | |||
1354 | 1356 | ||
1355 | stp_page = alloc_bootmem_pages(PAGE_SIZE); | 1357 | stp_page = alloc_bootmem_pages(PAGE_SIZE); |
1356 | rc = chsc_sstpc(stp_page, STP_OP_CTRL, 0x0000); | 1358 | rc = chsc_sstpc(stp_page, STP_OP_CTRL, 0x0000); |
1357 | if (rc == 1) | 1359 | if (rc == 0) |
1358 | set_bit(CLOCK_SYNC_HAS_STP, &clock_sync_flags); | 1360 | set_bit(CLOCK_SYNC_HAS_STP, &clock_sync_flags); |
1359 | else if (stp_online) { | 1361 | else if (stp_online) { |
1360 | printk(KERN_WARNING "Running on non STP capable machine.\n"); | 1362 | printk(KERN_WARNING "Running on non STP capable machine.\n"); |
diff --git a/arch/s390/lib/delay.c b/arch/s390/lib/delay.c index fc6ab6094df8..6ccb9fab055a 100644 --- a/arch/s390/lib/delay.c +++ b/arch/s390/lib/delay.c | |||
@@ -1,14 +1,9 @@ | |||
1 | /* | 1 | /* |
2 | * arch/s390/lib/delay.c | ||
3 | * Precise Delay Loops for S390 | 2 | * Precise Delay Loops for S390 |
4 | * | 3 | * |
5 | * S390 version | 4 | * Copyright IBM Corp. 1999,2008 |
6 | * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation | 5 | * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>, |
7 | * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com), | 6 | * Heiko Carstens <heiko.carstens@de.ibm.com>, |
8 | * | ||
9 | * Derived from "arch/i386/lib/delay.c" | ||
10 | * Copyright (C) 1993 Linus Torvalds | ||
11 | * Copyright (C) 1997 Martin Mares <mj@atrey.karlin.mff.cuni.cz> | ||
12 | */ | 7 | */ |
13 | 8 | ||
14 | #include <linux/sched.h> | 9 | #include <linux/sched.h> |
@@ -29,30 +24,31 @@ void __delay(unsigned long loops) | |||
29 | asm volatile("0: brct %0,0b" : : "d" ((loops/2) + 1)); | 24 | asm volatile("0: brct %0,0b" : : "d" ((loops/2) + 1)); |
30 | } | 25 | } |
31 | 26 | ||
32 | /* | 27 | static void __udelay_disabled(unsigned long usecs) |
33 | * Waits for 'usecs' microseconds using the TOD clock comparator. | ||
34 | */ | ||
35 | void __udelay(unsigned long usecs) | ||
36 | { | 28 | { |
37 | u64 end, time, old_cc = 0; | 29 | unsigned long mask, cr0, cr0_saved; |
38 | unsigned long flags, cr0, mask, dummy; | 30 | u64 clock_saved; |
39 | int irq_context; | ||
40 | 31 | ||
41 | irq_context = in_interrupt(); | 32 | clock_saved = local_tick_disable(); |
42 | if (!irq_context) | 33 | set_clock_comparator(get_clock() + ((u64) usecs << 12)); |
43 | local_bh_disable(); | 34 | __ctl_store(cr0_saved, 0, 0); |
44 | local_irq_save(flags); | 35 | cr0 = (cr0_saved & 0xffff00e0) | 0x00000800; |
45 | if (raw_irqs_disabled_flags(flags)) { | 36 | __ctl_load(cr0 , 0, 0); |
46 | old_cc = local_tick_disable(); | 37 | mask = psw_kernel_bits | PSW_MASK_WAIT | PSW_MASK_EXT; |
47 | S390_lowcore.clock_comparator = -1ULL; | 38 | trace_hardirqs_on(); |
48 | __ctl_store(cr0, 0, 0); | 39 | __load_psw_mask(mask); |
49 | dummy = (cr0 & 0xffff00e0) | 0x00000800; | 40 | local_irq_disable(); |
50 | __ctl_load(dummy , 0, 0); | 41 | __ctl_load(cr0_saved, 0, 0); |
51 | mask = psw_kernel_bits | PSW_MASK_WAIT | PSW_MASK_EXT; | 42 | local_tick_enable(clock_saved); |
52 | } else | 43 | set_clock_comparator(S390_lowcore.clock_comparator); |
53 | mask = psw_kernel_bits | PSW_MASK_WAIT | | 44 | } |
54 | PSW_MASK_EXT | PSW_MASK_IO; | 45 | |
46 | static void __udelay_enabled(unsigned long usecs) | ||
47 | { | ||
48 | unsigned long mask; | ||
49 | u64 end, time; | ||
55 | 50 | ||
51 | mask = psw_kernel_bits | PSW_MASK_WAIT | PSW_MASK_EXT | PSW_MASK_IO; | ||
56 | end = get_clock() + ((u64) usecs << 12); | 52 | end = get_clock() + ((u64) usecs << 12); |
57 | do { | 53 | do { |
58 | time = end < S390_lowcore.clock_comparator ? | 54 | time = end < S390_lowcore.clock_comparator ? |
@@ -62,13 +58,50 @@ void __udelay(unsigned long usecs) | |||
62 | __load_psw_mask(mask); | 58 | __load_psw_mask(mask); |
63 | local_irq_disable(); | 59 | local_irq_disable(); |
64 | } while (get_clock() < end); | 60 | } while (get_clock() < end); |
61 | set_clock_comparator(S390_lowcore.clock_comparator); | ||
62 | } | ||
65 | 63 | ||
66 | if (raw_irqs_disabled_flags(flags)) { | 64 | /* |
67 | __ctl_load(cr0, 0, 0); | 65 | * Waits for 'usecs' microseconds using the TOD clock comparator. |
68 | local_tick_enable(old_cc); | 66 | */ |
67 | void __udelay(unsigned long usecs) | ||
68 | { | ||
69 | unsigned long flags; | ||
70 | |||
71 | preempt_disable(); | ||
72 | local_irq_save(flags); | ||
73 | if (in_irq()) { | ||
74 | __udelay_disabled(usecs); | ||
75 | goto out; | ||
69 | } | 76 | } |
70 | if (!irq_context) | 77 | if (in_softirq()) { |
78 | if (raw_irqs_disabled_flags(flags)) | ||
79 | __udelay_disabled(usecs); | ||
80 | else | ||
81 | __udelay_enabled(usecs); | ||
82 | goto out; | ||
83 | } | ||
84 | if (raw_irqs_disabled_flags(flags)) { | ||
85 | local_bh_disable(); | ||
86 | __udelay_disabled(usecs); | ||
71 | _local_bh_enable(); | 87 | _local_bh_enable(); |
72 | set_clock_comparator(S390_lowcore.clock_comparator); | 88 | goto out; |
89 | } | ||
90 | __udelay_enabled(usecs); | ||
91 | out: | ||
73 | local_irq_restore(flags); | 92 | local_irq_restore(flags); |
93 | preempt_enable(); | ||
94 | } | ||
95 | |||
96 | /* | ||
97 | * Simple udelay variant. To be used on startup and reboot | ||
98 | * when the interrupt handler isn't working. | ||
99 | */ | ||
100 | void udelay_simple(unsigned long usecs) | ||
101 | { | ||
102 | u64 end; | ||
103 | |||
104 | end = get_clock() + ((u64) usecs << 12); | ||
105 | while (get_clock() < end) | ||
106 | cpu_relax(); | ||
74 | } | 107 | } |
diff --git a/arch/s390/mm/extmem.c b/arch/s390/mm/extmem.c index f231f5ec74b6..580fc64cc735 100644 --- a/arch/s390/mm/extmem.c +++ b/arch/s390/mm/extmem.c | |||
@@ -43,20 +43,40 @@ | |||
43 | #define DCSS_FINDSEG 0x0c | 43 | #define DCSS_FINDSEG 0x0c |
44 | #define DCSS_LOADNOLY 0x10 | 44 | #define DCSS_LOADNOLY 0x10 |
45 | #define DCSS_SEGEXT 0x18 | 45 | #define DCSS_SEGEXT 0x18 |
46 | #define DCSS_LOADSHRX 0x20 | ||
47 | #define DCSS_LOADNSRX 0x24 | ||
48 | #define DCSS_FINDSEGX 0x2c | ||
49 | #define DCSS_SEGEXTX 0x38 | ||
46 | #define DCSS_FINDSEGA 0x0c | 50 | #define DCSS_FINDSEGA 0x0c |
47 | 51 | ||
48 | struct qrange { | 52 | struct qrange { |
49 | unsigned int start; // 3byte start address, 1 byte type | 53 | unsigned long start; /* last byte type */ |
50 | unsigned int end; // 3byte end address, 1 byte reserved | 54 | unsigned long end; /* last byte reserved */ |
51 | }; | 55 | }; |
52 | 56 | ||
53 | struct qout64 { | 57 | struct qout64 { |
58 | unsigned long segstart; | ||
59 | unsigned long segend; | ||
60 | int segcnt; | ||
61 | int segrcnt; | ||
62 | struct qrange range[6]; | ||
63 | }; | ||
64 | |||
65 | #ifdef CONFIG_64BIT | ||
66 | struct qrange_old { | ||
67 | unsigned int start; /* last byte type */ | ||
68 | unsigned int end; /* last byte reserved */ | ||
69 | }; | ||
70 | |||
71 | /* output area format for the Diag x'64' old subcode x'18' */ | ||
72 | struct qout64_old { | ||
54 | int segstart; | 73 | int segstart; |
55 | int segend; | 74 | int segend; |
56 | int segcnt; | 75 | int segcnt; |
57 | int segrcnt; | 76 | int segrcnt; |
58 | struct qrange range[6]; | 77 | struct qrange_old range[6]; |
59 | }; | 78 | }; |
79 | #endif | ||
60 | 80 | ||
61 | struct qin64 { | 81 | struct qin64 { |
62 | char qopcode; | 82 | char qopcode; |
@@ -86,6 +106,55 @@ static DEFINE_MUTEX(dcss_lock); | |||
86 | static LIST_HEAD(dcss_list); | 106 | static LIST_HEAD(dcss_list); |
87 | static char *segtype_string[] = { "SW", "EW", "SR", "ER", "SN", "EN", "SC", | 107 | static char *segtype_string[] = { "SW", "EW", "SR", "ER", "SN", "EN", "SC", |
88 | "EW/EN-MIXED" }; | 108 | "EW/EN-MIXED" }; |
109 | static int loadshr_scode, loadnsr_scode, findseg_scode; | ||
110 | static int segext_scode, purgeseg_scode; | ||
111 | static int scode_set; | ||
112 | |||
113 | /* set correct Diag x'64' subcodes. */ | ||
114 | static int | ||
115 | dcss_set_subcodes(void) | ||
116 | { | ||
117 | #ifdef CONFIG_64BIT | ||
118 | char *name = kmalloc(8 * sizeof(char), GFP_DMA); | ||
119 | unsigned long rx, ry; | ||
120 | int rc; | ||
121 | |||
122 | if (name == NULL) | ||
123 | return -ENOMEM; | ||
124 | |||
125 | rx = (unsigned long) name; | ||
126 | ry = DCSS_FINDSEGX; | ||
127 | |||
128 | strcpy(name, "dummy"); | ||
129 | asm volatile( | ||
130 | " diag %0,%1,0x64\n" | ||
131 | "0: ipm %2\n" | ||
132 | " srl %2,28\n" | ||
133 | " j 2f\n" | ||
134 | "1: la %2,3\n" | ||
135 | "2:\n" | ||
136 | EX_TABLE(0b, 1b) | ||
137 | : "+d" (rx), "+d" (ry), "=d" (rc) : : "cc"); | ||
138 | |||
139 | kfree(name); | ||
140 | /* Diag x'64' new subcodes are supported, set to new subcodes */ | ||
141 | if (rc != 3) { | ||
142 | loadshr_scode = DCSS_LOADSHRX; | ||
143 | loadnsr_scode = DCSS_LOADNSRX; | ||
144 | purgeseg_scode = DCSS_PURGESEG; | ||
145 | findseg_scode = DCSS_FINDSEGX; | ||
146 | segext_scode = DCSS_SEGEXTX; | ||
147 | return 0; | ||
148 | } | ||
149 | #endif | ||
150 | /* Diag x'64' new subcodes are not supported, set to old subcodes */ | ||
151 | loadshr_scode = DCSS_LOADNOLY; | ||
152 | loadnsr_scode = DCSS_LOADNSR; | ||
153 | purgeseg_scode = DCSS_PURGESEG; | ||
154 | findseg_scode = DCSS_FINDSEG; | ||
155 | segext_scode = DCSS_SEGEXT; | ||
156 | return 0; | ||
157 | } | ||
89 | 158 | ||
90 | /* | 159 | /* |
91 | * Create the 8 bytes, ebcdic VM segment name from | 160 | * Create the 8 bytes, ebcdic VM segment name from |
@@ -135,25 +204,45 @@ segment_by_name (char *name) | |||
135 | * Perform a function on a dcss segment. | 204 | * Perform a function on a dcss segment. |
136 | */ | 205 | */ |
137 | static inline int | 206 | static inline int |
138 | dcss_diag (__u8 func, void *parameter, | 207 | dcss_diag(int *func, void *parameter, |
139 | unsigned long *ret1, unsigned long *ret2) | 208 | unsigned long *ret1, unsigned long *ret2) |
140 | { | 209 | { |
141 | unsigned long rx, ry; | 210 | unsigned long rx, ry; |
142 | int rc; | 211 | int rc; |
143 | 212 | ||
213 | if (scode_set == 0) { | ||
214 | rc = dcss_set_subcodes(); | ||
215 | if (rc < 0) | ||
216 | return rc; | ||
217 | scode_set = 1; | ||
218 | } | ||
144 | rx = (unsigned long) parameter; | 219 | rx = (unsigned long) parameter; |
145 | ry = (unsigned long) func; | 220 | ry = (unsigned long) *func; |
146 | asm volatile( | 221 | |
147 | #ifdef CONFIG_64BIT | 222 | #ifdef CONFIG_64BIT |
148 | " sam31\n" | 223 | /* 64-bit Diag x'64' new subcode, keep in 64-bit addressing mode */ |
149 | " diag %0,%1,0x64\n" | 224 | if (*func > DCSS_SEGEXT) |
150 | " sam64\n" | 225 | asm volatile( |
226 | " diag %0,%1,0x64\n" | ||
227 | " ipm %2\n" | ||
228 | " srl %2,28\n" | ||
229 | : "+d" (rx), "+d" (ry), "=d" (rc) : : "cc"); | ||
230 | /* 31-bit Diag x'64' old subcode, switch to 31-bit addressing mode */ | ||
231 | else | ||
232 | asm volatile( | ||
233 | " sam31\n" | ||
234 | " diag %0,%1,0x64\n" | ||
235 | " sam64\n" | ||
236 | " ipm %2\n" | ||
237 | " srl %2,28\n" | ||
238 | : "+d" (rx), "+d" (ry), "=d" (rc) : : "cc"); | ||
151 | #else | 239 | #else |
240 | asm volatile( | ||
152 | " diag %0,%1,0x64\n" | 241 | " diag %0,%1,0x64\n" |
153 | #endif | ||
154 | " ipm %2\n" | 242 | " ipm %2\n" |
155 | " srl %2,28\n" | 243 | " srl %2,28\n" |
156 | : "+d" (rx), "+d" (ry), "=d" (rc) : : "cc"); | 244 | : "+d" (rx), "+d" (ry), "=d" (rc) : : "cc"); |
245 | #endif | ||
157 | *ret1 = rx; | 246 | *ret1 = rx; |
158 | *ret2 = ry; | 247 | *ret2 = ry; |
159 | return rc; | 248 | return rc; |
@@ -190,14 +279,45 @@ query_segment_type (struct dcss_segment *seg) | |||
190 | qin->qoutlen = sizeof(struct qout64); | 279 | qin->qoutlen = sizeof(struct qout64); |
191 | memcpy (qin->qname, seg->dcss_name, 8); | 280 | memcpy (qin->qname, seg->dcss_name, 8); |
192 | 281 | ||
193 | diag_cc = dcss_diag (DCSS_SEGEXT, qin, &dummy, &vmrc); | 282 | diag_cc = dcss_diag(&segext_scode, qin, &dummy, &vmrc); |
194 | 283 | ||
284 | if (diag_cc < 0) { | ||
285 | rc = diag_cc; | ||
286 | goto out_free; | ||
287 | } | ||
195 | if (diag_cc > 1) { | 288 | if (diag_cc > 1) { |
196 | PRINT_WARN ("segment_type: diag returned error %ld\n", vmrc); | 289 | PRINT_WARN ("segment_type: diag returned error %ld\n", vmrc); |
197 | rc = dcss_diag_translate_rc (vmrc); | 290 | rc = dcss_diag_translate_rc (vmrc); |
198 | goto out_free; | 291 | goto out_free; |
199 | } | 292 | } |
200 | 293 | ||
294 | #ifdef CONFIG_64BIT | ||
295 | /* Only old format of output area of Diagnose x'64' is supported, | ||
296 | copy data for the new format. */ | ||
297 | if (segext_scode == DCSS_SEGEXT) { | ||
298 | struct qout64_old *qout_old; | ||
299 | qout_old = kzalloc(sizeof(struct qout64_old), GFP_DMA); | ||
300 | if (qout_old == NULL) { | ||
301 | rc = -ENOMEM; | ||
302 | goto out_free; | ||
303 | } | ||
304 | memcpy(qout_old, qout, sizeof(struct qout64_old)); | ||
305 | qout->segstart = (unsigned long) qout_old->segstart; | ||
306 | qout->segend = (unsigned long) qout_old->segend; | ||
307 | qout->segcnt = qout_old->segcnt; | ||
308 | qout->segrcnt = qout_old->segrcnt; | ||
309 | |||
310 | if (qout->segcnt > 6) | ||
311 | qout->segrcnt = 6; | ||
312 | for (i = 0; i < qout->segrcnt; i++) { | ||
313 | qout->range[i].start = | ||
314 | (unsigned long) qout_old->range[i].start; | ||
315 | qout->range[i].end = | ||
316 | (unsigned long) qout_old->range[i].end; | ||
317 | } | ||
318 | kfree(qout_old); | ||
319 | } | ||
320 | #endif | ||
201 | if (qout->segcnt > 6) { | 321 | if (qout->segcnt > 6) { |
202 | rc = -ENOTSUPP; | 322 | rc = -ENOTSUPP; |
203 | goto out_free; | 323 | goto out_free; |
@@ -269,6 +389,30 @@ segment_type (char* name) | |||
269 | } | 389 | } |
270 | 390 | ||
271 | /* | 391 | /* |
392 | * check if segment collides with other segments that are currently loaded | ||
393 | * returns 1 if this is the case, 0 if no collision was found | ||
394 | */ | ||
395 | static int | ||
396 | segment_overlaps_others (struct dcss_segment *seg) | ||
397 | { | ||
398 | struct list_head *l; | ||
399 | struct dcss_segment *tmp; | ||
400 | |||
401 | BUG_ON(!mutex_is_locked(&dcss_lock)); | ||
402 | list_for_each(l, &dcss_list) { | ||
403 | tmp = list_entry(l, struct dcss_segment, list); | ||
404 | if ((tmp->start_addr >> 20) > (seg->end >> 20)) | ||
405 | continue; | ||
406 | if ((tmp->end >> 20) < (seg->start_addr >> 20)) | ||
407 | continue; | ||
408 | if (seg == tmp) | ||
409 | continue; | ||
410 | return 1; | ||
411 | } | ||
412 | return 0; | ||
413 | } | ||
414 | |||
415 | /* | ||
272 | * real segment loading function, called from segment_load | 416 | * real segment loading function, called from segment_load |
273 | */ | 417 | */ |
274 | static int | 418 | static int |
@@ -276,7 +420,8 @@ __segment_load (char *name, int do_nonshared, unsigned long *addr, unsigned long | |||
276 | { | 420 | { |
277 | struct dcss_segment *seg = kmalloc(sizeof(struct dcss_segment), | 421 | struct dcss_segment *seg = kmalloc(sizeof(struct dcss_segment), |
278 | GFP_DMA); | 422 | GFP_DMA); |
279 | int dcss_command, rc, diag_cc; | 423 | int rc, diag_cc; |
424 | unsigned long start_addr, end_addr, dummy; | ||
280 | 425 | ||
281 | if (seg == NULL) { | 426 | if (seg == NULL) { |
282 | rc = -ENOMEM; | 427 | rc = -ENOMEM; |
@@ -287,6 +432,13 @@ __segment_load (char *name, int do_nonshared, unsigned long *addr, unsigned long | |||
287 | if (rc < 0) | 432 | if (rc < 0) |
288 | goto out_free; | 433 | goto out_free; |
289 | 434 | ||
435 | if (loadshr_scode == DCSS_LOADSHRX) { | ||
436 | if (segment_overlaps_others(seg)) { | ||
437 | rc = -EBUSY; | ||
438 | goto out_free; | ||
439 | } | ||
440 | } | ||
441 | |||
290 | rc = vmem_add_mapping(seg->start_addr, seg->end - seg->start_addr + 1); | 442 | rc = vmem_add_mapping(seg->start_addr, seg->end - seg->start_addr + 1); |
291 | 443 | ||
292 | if (rc) | 444 | if (rc) |
@@ -316,20 +468,28 @@ __segment_load (char *name, int do_nonshared, unsigned long *addr, unsigned long | |||
316 | } | 468 | } |
317 | 469 | ||
318 | if (do_nonshared) | 470 | if (do_nonshared) |
319 | dcss_command = DCSS_LOADNSR; | 471 | diag_cc = dcss_diag(&loadnsr_scode, seg->dcss_name, |
472 | &start_addr, &end_addr); | ||
320 | else | 473 | else |
321 | dcss_command = DCSS_LOADNOLY; | 474 | diag_cc = dcss_diag(&loadshr_scode, seg->dcss_name, |
322 | 475 | &start_addr, &end_addr); | |
323 | diag_cc = dcss_diag(dcss_command, seg->dcss_name, | 476 | if (diag_cc < 0) { |
324 | &seg->start_addr, &seg->end); | 477 | dcss_diag(&purgeseg_scode, seg->dcss_name, |
478 | &dummy, &dummy); | ||
479 | rc = diag_cc; | ||
480 | goto out_resource; | ||
481 | } | ||
325 | if (diag_cc > 1) { | 482 | if (diag_cc > 1) { |
326 | PRINT_WARN ("segment_load: could not load segment %s - " | 483 | PRINT_WARN ("segment_load: could not load segment %s - " |
327 | "diag returned error (%ld)\n",name,seg->end); | 484 | "diag returned error (%ld)\n", |
328 | rc = dcss_diag_translate_rc (seg->end); | 485 | name, end_addr); |
329 | dcss_diag(DCSS_PURGESEG, seg->dcss_name, | 486 | rc = dcss_diag_translate_rc(end_addr); |
330 | &seg->start_addr, &seg->end); | 487 | dcss_diag(&purgeseg_scode, seg->dcss_name, |
488 | &dummy, &dummy); | ||
331 | goto out_resource; | 489 | goto out_resource; |
332 | } | 490 | } |
491 | seg->start_addr = start_addr; | ||
492 | seg->end = end_addr; | ||
333 | seg->do_nonshared = do_nonshared; | 493 | seg->do_nonshared = do_nonshared; |
334 | atomic_set(&seg->ref_count, 1); | 494 | atomic_set(&seg->ref_count, 1); |
335 | list_add(&seg->list, &dcss_list); | 495 | list_add(&seg->list, &dcss_list); |
@@ -423,8 +583,8 @@ int | |||
423 | segment_modify_shared (char *name, int do_nonshared) | 583 | segment_modify_shared (char *name, int do_nonshared) |
424 | { | 584 | { |
425 | struct dcss_segment *seg; | 585 | struct dcss_segment *seg; |
426 | unsigned long dummy; | 586 | unsigned long start_addr, end_addr, dummy; |
427 | int dcss_command, rc, diag_cc; | 587 | int rc, diag_cc; |
428 | 588 | ||
429 | mutex_lock(&dcss_lock); | 589 | mutex_lock(&dcss_lock); |
430 | seg = segment_by_name (name); | 590 | seg = segment_by_name (name); |
@@ -445,38 +605,51 @@ segment_modify_shared (char *name, int do_nonshared) | |||
445 | goto out_unlock; | 605 | goto out_unlock; |
446 | } | 606 | } |
447 | release_resource(seg->res); | 607 | release_resource(seg->res); |
448 | if (do_nonshared) { | 608 | if (do_nonshared) |
449 | dcss_command = DCSS_LOADNSR; | ||
450 | seg->res->flags &= ~IORESOURCE_READONLY; | 609 | seg->res->flags &= ~IORESOURCE_READONLY; |
451 | } else { | 610 | else |
452 | dcss_command = DCSS_LOADNOLY; | ||
453 | if (seg->vm_segtype == SEG_TYPE_SR || | 611 | if (seg->vm_segtype == SEG_TYPE_SR || |
454 | seg->vm_segtype == SEG_TYPE_ER) | 612 | seg->vm_segtype == SEG_TYPE_ER) |
455 | seg->res->flags |= IORESOURCE_READONLY; | 613 | seg->res->flags |= IORESOURCE_READONLY; |
456 | } | 614 | |
457 | if (request_resource(&iomem_resource, seg->res)) { | 615 | if (request_resource(&iomem_resource, seg->res)) { |
458 | PRINT_WARN("segment_modify_shared: could not reload segment %s" | 616 | PRINT_WARN("segment_modify_shared: could not reload segment %s" |
459 | " - overlapping resources\n", name); | 617 | " - overlapping resources\n", name); |
460 | rc = -EBUSY; | 618 | rc = -EBUSY; |
461 | kfree(seg->res); | 619 | kfree(seg->res); |
462 | goto out_del; | 620 | goto out_del_mem; |
621 | } | ||
622 | |||
623 | dcss_diag(&purgeseg_scode, seg->dcss_name, &dummy, &dummy); | ||
624 | if (do_nonshared) | ||
625 | diag_cc = dcss_diag(&loadnsr_scode, seg->dcss_name, | ||
626 | &start_addr, &end_addr); | ||
627 | else | ||
628 | diag_cc = dcss_diag(&loadshr_scode, seg->dcss_name, | ||
629 | &start_addr, &end_addr); | ||
630 | if (diag_cc < 0) { | ||
631 | rc = diag_cc; | ||
632 | goto out_del_res; | ||
463 | } | 633 | } |
464 | dcss_diag(DCSS_PURGESEG, seg->dcss_name, &dummy, &dummy); | ||
465 | diag_cc = dcss_diag(dcss_command, seg->dcss_name, | ||
466 | &seg->start_addr, &seg->end); | ||
467 | if (diag_cc > 1) { | 634 | if (diag_cc > 1) { |
468 | PRINT_WARN ("segment_modify_shared: could not reload segment %s" | 635 | PRINT_WARN ("segment_modify_shared: could not reload segment %s" |
469 | " - diag returned error (%ld)\n",name,seg->end); | 636 | " - diag returned error (%ld)\n", |
470 | rc = dcss_diag_translate_rc (seg->end); | 637 | name, end_addr); |
471 | goto out_del; | 638 | rc = dcss_diag_translate_rc(end_addr); |
639 | goto out_del_res; | ||
472 | } | 640 | } |
641 | seg->start_addr = start_addr; | ||
642 | seg->end = end_addr; | ||
473 | seg->do_nonshared = do_nonshared; | 643 | seg->do_nonshared = do_nonshared; |
474 | rc = 0; | 644 | rc = 0; |
475 | goto out_unlock; | 645 | goto out_unlock; |
476 | out_del: | 646 | out_del_res: |
647 | release_resource(seg->res); | ||
648 | kfree(seg->res); | ||
649 | out_del_mem: | ||
477 | vmem_remove_mapping(seg->start_addr, seg->end - seg->start_addr + 1); | 650 | vmem_remove_mapping(seg->start_addr, seg->end - seg->start_addr + 1); |
478 | list_del(&seg->list); | 651 | list_del(&seg->list); |
479 | dcss_diag(DCSS_PURGESEG, seg->dcss_name, &dummy, &dummy); | 652 | dcss_diag(&purgeseg_scode, seg->dcss_name, &dummy, &dummy); |
480 | kfree(seg); | 653 | kfree(seg); |
481 | out_unlock: | 654 | out_unlock: |
482 | mutex_unlock(&dcss_lock); | 655 | mutex_unlock(&dcss_lock); |
@@ -510,7 +683,7 @@ segment_unload(char *name) | |||
510 | kfree(seg->res); | 683 | kfree(seg->res); |
511 | vmem_remove_mapping(seg->start_addr, seg->end - seg->start_addr + 1); | 684 | vmem_remove_mapping(seg->start_addr, seg->end - seg->start_addr + 1); |
512 | list_del(&seg->list); | 685 | list_del(&seg->list); |
513 | dcss_diag(DCSS_PURGESEG, seg->dcss_name, &dummy, &dummy); | 686 | dcss_diag(&purgeseg_scode, seg->dcss_name, &dummy, &dummy); |
514 | kfree(seg); | 687 | kfree(seg); |
515 | out_unlock: | 688 | out_unlock: |
516 | mutex_unlock(&dcss_lock); | 689 | mutex_unlock(&dcss_lock); |
@@ -545,7 +718,7 @@ segment_save(char *name) | |||
545 | endpfn = (seg->end) >> PAGE_SHIFT; | 718 | endpfn = (seg->end) >> PAGE_SHIFT; |
546 | sprintf(cmd1, "DEFSEG %s", name); | 719 | sprintf(cmd1, "DEFSEG %s", name); |
547 | for (i=0; i<seg->segcnt; i++) { | 720 | for (i=0; i<seg->segcnt; i++) { |
548 | sprintf(cmd1+strlen(cmd1), " %X-%X %s", | 721 | sprintf(cmd1+strlen(cmd1), " %lX-%lX %s", |
549 | seg->range[i].start >> PAGE_SHIFT, | 722 | seg->range[i].start >> PAGE_SHIFT, |
550 | seg->range[i].end >> PAGE_SHIFT, | 723 | seg->range[i].end >> PAGE_SHIFT, |
551 | segtype_string[seg->range[i].start & 0xff]); | 724 | segtype_string[seg->range[i].start & 0xff]); |