diff options
Diffstat (limited to 'arch')
49 files changed, 1140 insertions, 996 deletions
diff --git a/arch/s390/include/asm/cmpxchg.h b/arch/s390/include/asm/cmpxchg.h index 4236408070e5..6259895fcd97 100644 --- a/arch/s390/include/asm/cmpxchg.h +++ b/arch/s390/include/asm/cmpxchg.h | |||
| @@ -11,200 +11,28 @@ | |||
| 11 | #include <linux/types.h> | 11 | #include <linux/types.h> |
| 12 | #include <linux/bug.h> | 12 | #include <linux/bug.h> |
| 13 | 13 | ||
| 14 | extern void __xchg_called_with_bad_pointer(void); | 14 | #define cmpxchg(ptr, o, n) \ |
| 15 | 15 | ({ \ | |
| 16 | static inline unsigned long __xchg(unsigned long x, void *ptr, int size) | 16 | __typeof__(*(ptr)) __o = (o); \ |
| 17 | { | 17 | __typeof__(*(ptr)) __n = (n); \ |
| 18 | unsigned long addr, old; | 18 | (__typeof__(*(ptr))) __sync_val_compare_and_swap((ptr),__o,__n);\ |
| 19 | int shift; | ||
| 20 | |||
| 21 | switch (size) { | ||
| 22 | case 1: | ||
| 23 | addr = (unsigned long) ptr; | ||
| 24 | shift = (3 ^ (addr & 3)) << 3; | ||
| 25 | addr ^= addr & 3; | ||
| 26 | asm volatile( | ||
| 27 | " l %0,%4\n" | ||
| 28 | "0: lr 0,%0\n" | ||
| 29 | " nr 0,%3\n" | ||
| 30 | " or 0,%2\n" | ||
| 31 | " cs %0,0,%4\n" | ||
| 32 | " jl 0b\n" | ||
| 33 | : "=&d" (old), "=Q" (*(int *) addr) | ||
| 34 | : "d" ((x & 0xff) << shift), "d" (~(0xff << shift)), | ||
| 35 | "Q" (*(int *) addr) : "memory", "cc", "0"); | ||
| 36 | return old >> shift; | ||
| 37 | case 2: | ||
| 38 | addr = (unsigned long) ptr; | ||
| 39 | shift = (2 ^ (addr & 2)) << 3; | ||
| 40 | addr ^= addr & 2; | ||
| 41 | asm volatile( | ||
| 42 | " l %0,%4\n" | ||
| 43 | "0: lr 0,%0\n" | ||
| 44 | " nr 0,%3\n" | ||
| 45 | " or 0,%2\n" | ||
| 46 | " cs %0,0,%4\n" | ||
| 47 | " jl 0b\n" | ||
| 48 | : "=&d" (old), "=Q" (*(int *) addr) | ||
| 49 | : "d" ((x & 0xffff) << shift), "d" (~(0xffff << shift)), | ||
| 50 | "Q" (*(int *) addr) : "memory", "cc", "0"); | ||
| 51 | return old >> shift; | ||
| 52 | case 4: | ||
| 53 | asm volatile( | ||
| 54 | " l %0,%3\n" | ||
| 55 | "0: cs %0,%2,%3\n" | ||
| 56 | " jl 0b\n" | ||
| 57 | : "=&d" (old), "=Q" (*(int *) ptr) | ||
| 58 | : "d" (x), "Q" (*(int *) ptr) | ||
| 59 | : "memory", "cc"); | ||
| 60 | return old; | ||
| 61 | #ifdef CONFIG_64BIT | ||
| 62 | case 8: | ||
| 63 | asm volatile( | ||
| 64 | " lg %0,%3\n" | ||
| 65 | "0: csg %0,%2,%3\n" | ||
| 66 | " jl 0b\n" | ||
| 67 | : "=&d" (old), "=m" (*(long *) ptr) | ||
| 68 | : "d" (x), "Q" (*(long *) ptr) | ||
| 69 | : "memory", "cc"); | ||
| 70 | return old; | ||
| 71 | #endif /* CONFIG_64BIT */ | ||
| 72 | } | ||
| 73 | __xchg_called_with_bad_pointer(); | ||
| 74 | return x; | ||
| 75 | } | ||
| 76 | |||
| 77 | #define xchg(ptr, x) \ | ||
| 78 | ({ \ | ||
| 79 | __typeof__(*(ptr)) __ret; \ | ||
| 80 | __ret = (__typeof__(*(ptr))) \ | ||
| 81 | __xchg((unsigned long)(x), (void *)(ptr), sizeof(*(ptr)));\ | ||
| 82 | __ret; \ | ||
| 83 | }) | 19 | }) |
| 84 | 20 | ||
| 85 | /* | 21 | #define cmpxchg64 cmpxchg |
| 86 | * Atomic compare and exchange. Compare OLD with MEM, if identical, | 22 | #define cmpxchg_local cmpxchg |
| 87 | * store NEW in MEM. Return the initial value in MEM. Success is | 23 | #define cmpxchg64_local cmpxchg |
| 88 | * indicated by comparing RETURN with OLD. | ||
| 89 | */ | ||
| 90 | |||
| 91 | #define __HAVE_ARCH_CMPXCHG | ||
| 92 | |||
| 93 | extern void __cmpxchg_called_with_bad_pointer(void); | ||
| 94 | |||
| 95 | static inline unsigned long __cmpxchg(void *ptr, unsigned long old, | ||
| 96 | unsigned long new, int size) | ||
| 97 | { | ||
| 98 | unsigned long addr, prev, tmp; | ||
| 99 | int shift; | ||
| 100 | |||
| 101 | switch (size) { | ||
| 102 | case 1: | ||
| 103 | addr = (unsigned long) ptr; | ||
| 104 | shift = (3 ^ (addr & 3)) << 3; | ||
| 105 | addr ^= addr & 3; | ||
| 106 | asm volatile( | ||
| 107 | " l %0,%2\n" | ||
| 108 | "0: nr %0,%5\n" | ||
| 109 | " lr %1,%0\n" | ||
| 110 | " or %0,%3\n" | ||
| 111 | " or %1,%4\n" | ||
| 112 | " cs %0,%1,%2\n" | ||
| 113 | " jnl 1f\n" | ||
| 114 | " xr %1,%0\n" | ||
| 115 | " nr %1,%5\n" | ||
| 116 | " jnz 0b\n" | ||
| 117 | "1:" | ||
| 118 | : "=&d" (prev), "=&d" (tmp), "+Q" (*(int *) addr) | ||
| 119 | : "d" ((old & 0xff) << shift), | ||
| 120 | "d" ((new & 0xff) << shift), | ||
| 121 | "d" (~(0xff << shift)) | ||
| 122 | : "memory", "cc"); | ||
| 123 | return prev >> shift; | ||
| 124 | case 2: | ||
| 125 | addr = (unsigned long) ptr; | ||
| 126 | shift = (2 ^ (addr & 2)) << 3; | ||
| 127 | addr ^= addr & 2; | ||
| 128 | asm volatile( | ||
| 129 | " l %0,%2\n" | ||
| 130 | "0: nr %0,%5\n" | ||
| 131 | " lr %1,%0\n" | ||
| 132 | " or %0,%3\n" | ||
| 133 | " or %1,%4\n" | ||
| 134 | " cs %0,%1,%2\n" | ||
| 135 | " jnl 1f\n" | ||
| 136 | " xr %1,%0\n" | ||
| 137 | " nr %1,%5\n" | ||
| 138 | " jnz 0b\n" | ||
| 139 | "1:" | ||
| 140 | : "=&d" (prev), "=&d" (tmp), "+Q" (*(int *) addr) | ||
| 141 | : "d" ((old & 0xffff) << shift), | ||
| 142 | "d" ((new & 0xffff) << shift), | ||
| 143 | "d" (~(0xffff << shift)) | ||
| 144 | : "memory", "cc"); | ||
| 145 | return prev >> shift; | ||
| 146 | case 4: | ||
| 147 | asm volatile( | ||
| 148 | " cs %0,%3,%1\n" | ||
| 149 | : "=&d" (prev), "=Q" (*(int *) ptr) | ||
| 150 | : "0" (old), "d" (new), "Q" (*(int *) ptr) | ||
| 151 | : "memory", "cc"); | ||
| 152 | return prev; | ||
| 153 | #ifdef CONFIG_64BIT | ||
| 154 | case 8: | ||
| 155 | asm volatile( | ||
| 156 | " csg %0,%3,%1\n" | ||
| 157 | : "=&d" (prev), "=Q" (*(long *) ptr) | ||
| 158 | : "0" (old), "d" (new), "Q" (*(long *) ptr) | ||
| 159 | : "memory", "cc"); | ||
| 160 | return prev; | ||
| 161 | #endif /* CONFIG_64BIT */ | ||
| 162 | } | ||
| 163 | __cmpxchg_called_with_bad_pointer(); | ||
| 164 | return old; | ||
| 165 | } | ||
| 166 | |||
| 167 | #define cmpxchg(ptr, o, n) \ | ||
| 168 | ({ \ | ||
| 169 | __typeof__(*(ptr)) __ret; \ | ||
| 170 | __ret = (__typeof__(*(ptr))) \ | ||
| 171 | __cmpxchg((ptr), (unsigned long)(o), (unsigned long)(n), \ | ||
| 172 | sizeof(*(ptr))); \ | ||
| 173 | __ret; \ | ||
| 174 | }) | ||
| 175 | 24 | ||
| 176 | #ifdef CONFIG_64BIT | 25 | #define xchg(ptr, x) \ |
| 177 | #define cmpxchg64(ptr, o, n) \ | ||
| 178 | ({ \ | 26 | ({ \ |
| 179 | cmpxchg((ptr), (o), (n)); \ | 27 | __typeof__(ptr) __ptr = (ptr); \ |
| 28 | __typeof__(*(ptr)) __old; \ | ||
| 29 | do { \ | ||
| 30 | __old = *__ptr; \ | ||
| 31 | } while (!__sync_bool_compare_and_swap(__ptr, __old, x)); \ | ||
| 32 | __old; \ | ||
| 180 | }) | 33 | }) |
| 181 | #else /* CONFIG_64BIT */ | ||
| 182 | static inline unsigned long long __cmpxchg64(void *ptr, | ||
| 183 | unsigned long long old, | ||
| 184 | unsigned long long new) | ||
| 185 | { | ||
| 186 | register_pair rp_old = {.pair = old}; | ||
| 187 | register_pair rp_new = {.pair = new}; | ||
| 188 | unsigned long long *ullptr = ptr; | ||
| 189 | 34 | ||
| 190 | asm volatile( | 35 | #define __HAVE_ARCH_CMPXCHG |
| 191 | " cds %0,%2,%1" | ||
| 192 | : "+d" (rp_old), "+Q" (*ullptr) | ||
| 193 | : "d" (rp_new) | ||
| 194 | : "memory", "cc"); | ||
| 195 | return rp_old.pair; | ||
| 196 | } | ||
| 197 | |||
| 198 | #define cmpxchg64(ptr, o, n) \ | ||
| 199 | ({ \ | ||
| 200 | __typeof__(*(ptr)) __ret; \ | ||
| 201 | __ret = (__typeof__(*(ptr))) \ | ||
| 202 | __cmpxchg64((ptr), \ | ||
| 203 | (unsigned long long)(o), \ | ||
| 204 | (unsigned long long)(n)); \ | ||
| 205 | __ret; \ | ||
| 206 | }) | ||
| 207 | #endif /* CONFIG_64BIT */ | ||
| 208 | 36 | ||
| 209 | #define __cmpxchg_double_op(p1, p2, o1, o2, n1, n2, insn) \ | 37 | #define __cmpxchg_double_op(p1, p2, o1, o2, n1, n2, insn) \ |
| 210 | ({ \ | 38 | ({ \ |
| @@ -265,40 +93,4 @@ extern void __cmpxchg_double_called_with_bad_pointer(void); | |||
| 265 | 93 | ||
| 266 | #define system_has_cmpxchg_double() 1 | 94 | #define system_has_cmpxchg_double() 1 |
| 267 | 95 | ||
| 268 | #include <asm-generic/cmpxchg-local.h> | ||
| 269 | |||
| 270 | static inline unsigned long __cmpxchg_local(void *ptr, | ||
| 271 | unsigned long old, | ||
| 272 | unsigned long new, int size) | ||
| 273 | { | ||
| 274 | switch (size) { | ||
| 275 | case 1: | ||
| 276 | case 2: | ||
| 277 | case 4: | ||
| 278 | #ifdef CONFIG_64BIT | ||
| 279 | case 8: | ||
| 280 | #endif | ||
| 281 | return __cmpxchg(ptr, old, new, size); | ||
| 282 | default: | ||
| 283 | return __cmpxchg_local_generic(ptr, old, new, size); | ||
| 284 | } | ||
| 285 | |||
| 286 | return old; | ||
| 287 | } | ||
| 288 | |||
| 289 | /* | ||
| 290 | * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make | ||
| 291 | * them available. | ||
| 292 | */ | ||
| 293 | #define cmpxchg_local(ptr, o, n) \ | ||
| 294 | ({ \ | ||
| 295 | __typeof__(*(ptr)) __ret; \ | ||
| 296 | __ret = (__typeof__(*(ptr))) \ | ||
| 297 | __cmpxchg_local((ptr), (unsigned long)(o), \ | ||
| 298 | (unsigned long)(n), sizeof(*(ptr))); \ | ||
| 299 | __ret; \ | ||
| 300 | }) | ||
| 301 | |||
| 302 | #define cmpxchg64_local(ptr, o, n) cmpxchg64((ptr), (o), (n)) | ||
| 303 | |||
| 304 | #endif /* __ASM_CMPXCHG_H */ | 96 | #endif /* __ASM_CMPXCHG_H */ |
diff --git a/arch/s390/include/asm/cputime.h b/arch/s390/include/asm/cputime.h index f8c196984853..b91e960e4045 100644 --- a/arch/s390/include/asm/cputime.h +++ b/arch/s390/include/asm/cputime.h | |||
| @@ -10,6 +10,8 @@ | |||
| 10 | #include <linux/types.h> | 10 | #include <linux/types.h> |
| 11 | #include <asm/div64.h> | 11 | #include <asm/div64.h> |
| 12 | 12 | ||
| 13 | #define CPUTIME_PER_USEC 4096ULL | ||
| 14 | #define CPUTIME_PER_SEC (CPUTIME_PER_USEC * USEC_PER_SEC) | ||
| 13 | 15 | ||
| 14 | /* We want to use full resolution of the CPU timer: 2**-12 micro-seconds. */ | 16 | /* We want to use full resolution of the CPU timer: 2**-12 micro-seconds. */ |
| 15 | 17 | ||
| @@ -38,24 +40,24 @@ static inline unsigned long __div(unsigned long long n, unsigned long base) | |||
| 38 | */ | 40 | */ |
| 39 | static inline unsigned long cputime_to_jiffies(const cputime_t cputime) | 41 | static inline unsigned long cputime_to_jiffies(const cputime_t cputime) |
| 40 | { | 42 | { |
| 41 | return __div((__force unsigned long long) cputime, 4096000000ULL / HZ); | 43 | return __div((__force unsigned long long) cputime, CPUTIME_PER_SEC / HZ); |
| 42 | } | 44 | } |
| 43 | 45 | ||
| 44 | static inline cputime_t jiffies_to_cputime(const unsigned int jif) | 46 | static inline cputime_t jiffies_to_cputime(const unsigned int jif) |
| 45 | { | 47 | { |
| 46 | return (__force cputime_t)(jif * (4096000000ULL / HZ)); | 48 | return (__force cputime_t)(jif * (CPUTIME_PER_SEC / HZ)); |
| 47 | } | 49 | } |
| 48 | 50 | ||
| 49 | static inline u64 cputime64_to_jiffies64(cputime64_t cputime) | 51 | static inline u64 cputime64_to_jiffies64(cputime64_t cputime) |
| 50 | { | 52 | { |
| 51 | unsigned long long jif = (__force unsigned long long) cputime; | 53 | unsigned long long jif = (__force unsigned long long) cputime; |
| 52 | do_div(jif, 4096000000ULL / HZ); | 54 | do_div(jif, CPUTIME_PER_SEC / HZ); |
| 53 | return jif; | 55 | return jif; |
| 54 | } | 56 | } |
| 55 | 57 | ||
| 56 | static inline cputime64_t jiffies64_to_cputime64(const u64 jif) | 58 | static inline cputime64_t jiffies64_to_cputime64(const u64 jif) |
| 57 | { | 59 | { |
| 58 | return (__force cputime64_t)(jif * (4096000000ULL / HZ)); | 60 | return (__force cputime64_t)(jif * (CPUTIME_PER_SEC / HZ)); |
| 59 | } | 61 | } |
| 60 | 62 | ||
| 61 | /* | 63 | /* |
| @@ -68,7 +70,7 @@ static inline unsigned int cputime_to_usecs(const cputime_t cputime) | |||
| 68 | 70 | ||
| 69 | static inline cputime_t usecs_to_cputime(const unsigned int m) | 71 | static inline cputime_t usecs_to_cputime(const unsigned int m) |
| 70 | { | 72 | { |
| 71 | return (__force cputime_t)(m * 4096ULL); | 73 | return (__force cputime_t)(m * CPUTIME_PER_USEC); |
| 72 | } | 74 | } |
| 73 | 75 | ||
| 74 | #define usecs_to_cputime64(m) usecs_to_cputime(m) | 76 | #define usecs_to_cputime64(m) usecs_to_cputime(m) |
| @@ -78,12 +80,12 @@ static inline cputime_t usecs_to_cputime(const unsigned int m) | |||
| 78 | */ | 80 | */ |
| 79 | static inline unsigned int cputime_to_secs(const cputime_t cputime) | 81 | static inline unsigned int cputime_to_secs(const cputime_t cputime) |
| 80 | { | 82 | { |
| 81 | return __div((__force unsigned long long) cputime, 2048000000) >> 1; | 83 | return __div((__force unsigned long long) cputime, CPUTIME_PER_SEC / 2) >> 1; |
| 82 | } | 84 | } |
| 83 | 85 | ||
| 84 | static inline cputime_t secs_to_cputime(const unsigned int s) | 86 | static inline cputime_t secs_to_cputime(const unsigned int s) |
| 85 | { | 87 | { |
| 86 | return (__force cputime_t)(s * 4096000000ULL); | 88 | return (__force cputime_t)(s * CPUTIME_PER_SEC); |
| 87 | } | 89 | } |
| 88 | 90 | ||
| 89 | /* | 91 | /* |
| @@ -91,8 +93,8 @@ static inline cputime_t secs_to_cputime(const unsigned int s) | |||
| 91 | */ | 93 | */ |
| 92 | static inline cputime_t timespec_to_cputime(const struct timespec *value) | 94 | static inline cputime_t timespec_to_cputime(const struct timespec *value) |
| 93 | { | 95 | { |
| 94 | unsigned long long ret = value->tv_sec * 4096000000ULL; | 96 | unsigned long long ret = value->tv_sec * CPUTIME_PER_SEC; |
| 95 | return (__force cputime_t)(ret + value->tv_nsec * 4096 / 1000); | 97 | return (__force cputime_t)(ret + __div(value->tv_nsec * CPUTIME_PER_USEC, NSEC_PER_USEC)); |
| 96 | } | 98 | } |
| 97 | 99 | ||
| 98 | static inline void cputime_to_timespec(const cputime_t cputime, | 100 | static inline void cputime_to_timespec(const cputime_t cputime, |
| @@ -103,12 +105,12 @@ static inline void cputime_to_timespec(const cputime_t cputime, | |||
| 103 | register_pair rp; | 105 | register_pair rp; |
| 104 | 106 | ||
| 105 | rp.pair = __cputime >> 1; | 107 | rp.pair = __cputime >> 1; |
| 106 | asm ("dr %0,%1" : "+d" (rp) : "d" (2048000000UL)); | 108 | asm ("dr %0,%1" : "+d" (rp) : "d" (CPUTIME_PER_SEC / 2)); |
| 107 | value->tv_nsec = rp.subreg.even * 1000 / 4096; | 109 | value->tv_nsec = rp.subreg.even * NSEC_PER_USEC / CPUTIME_PER_USEC; |
| 108 | value->tv_sec = rp.subreg.odd; | 110 | value->tv_sec = rp.subreg.odd; |
| 109 | #else | 111 | #else |
| 110 | value->tv_nsec = (__cputime % 4096000000ULL) * 1000 / 4096; | 112 | value->tv_nsec = (__cputime % CPUTIME_PER_SEC) * NSEC_PER_USEC / CPUTIME_PER_USEC; |
| 111 | value->tv_sec = __cputime / 4096000000ULL; | 113 | value->tv_sec = __cputime / CPUTIME_PER_SEC; |
| 112 | #endif | 114 | #endif |
| 113 | } | 115 | } |
| 114 | 116 | ||
| @@ -119,8 +121,8 @@ static inline void cputime_to_timespec(const cputime_t cputime, | |||
| 119 | */ | 121 | */ |
| 120 | static inline cputime_t timeval_to_cputime(const struct timeval *value) | 122 | static inline cputime_t timeval_to_cputime(const struct timeval *value) |
| 121 | { | 123 | { |
| 122 | unsigned long long ret = value->tv_sec * 4096000000ULL; | 124 | unsigned long long ret = value->tv_sec * CPUTIME_PER_SEC; |
| 123 | return (__force cputime_t)(ret + value->tv_usec * 4096ULL); | 125 | return (__force cputime_t)(ret + value->tv_usec * CPUTIME_PER_USEC); |
| 124 | } | 126 | } |
| 125 | 127 | ||
| 126 | static inline void cputime_to_timeval(const cputime_t cputime, | 128 | static inline void cputime_to_timeval(const cputime_t cputime, |
| @@ -131,12 +133,12 @@ static inline void cputime_to_timeval(const cputime_t cputime, | |||
| 131 | register_pair rp; | 133 | register_pair rp; |
| 132 | 134 | ||
| 133 | rp.pair = __cputime >> 1; | 135 | rp.pair = __cputime >> 1; |
| 134 | asm ("dr %0,%1" : "+d" (rp) : "d" (2048000000UL)); | 136 | asm ("dr %0,%1" : "+d" (rp) : "d" (CPUTIME_PER_USEC / 2)); |
| 135 | value->tv_usec = rp.subreg.even / 4096; | 137 | value->tv_usec = rp.subreg.even / CPUTIME_PER_USEC; |
| 136 | value->tv_sec = rp.subreg.odd; | 138 | value->tv_sec = rp.subreg.odd; |
| 137 | #else | 139 | #else |
| 138 | value->tv_usec = (__cputime % 4096000000ULL) / 4096; | 140 | value->tv_usec = (__cputime % CPUTIME_PER_SEC) / CPUTIME_PER_USEC; |
| 139 | value->tv_sec = __cputime / 4096000000ULL; | 141 | value->tv_sec = __cputime / CPUTIME_PER_SEC; |
| 140 | #endif | 142 | #endif |
| 141 | } | 143 | } |
| 142 | 144 | ||
| @@ -146,13 +148,13 @@ static inline void cputime_to_timeval(const cputime_t cputime, | |||
| 146 | static inline clock_t cputime_to_clock_t(cputime_t cputime) | 148 | static inline clock_t cputime_to_clock_t(cputime_t cputime) |
| 147 | { | 149 | { |
| 148 | unsigned long long clock = (__force unsigned long long) cputime; | 150 | unsigned long long clock = (__force unsigned long long) cputime; |
| 149 | do_div(clock, 4096000000ULL / USER_HZ); | 151 | do_div(clock, CPUTIME_PER_SEC / USER_HZ); |
| 150 | return clock; | 152 | return clock; |
| 151 | } | 153 | } |
| 152 | 154 | ||
| 153 | static inline cputime_t clock_t_to_cputime(unsigned long x) | 155 | static inline cputime_t clock_t_to_cputime(unsigned long x) |
| 154 | { | 156 | { |
| 155 | return (__force cputime_t)(x * (4096000000ULL / USER_HZ)); | 157 | return (__force cputime_t)(x * (CPUTIME_PER_SEC / USER_HZ)); |
| 156 | } | 158 | } |
| 157 | 159 | ||
| 158 | /* | 160 | /* |
| @@ -161,7 +163,7 @@ static inline cputime_t clock_t_to_cputime(unsigned long x) | |||
| 161 | static inline clock_t cputime64_to_clock_t(cputime64_t cputime) | 163 | static inline clock_t cputime64_to_clock_t(cputime64_t cputime) |
| 162 | { | 164 | { |
| 163 | unsigned long long clock = (__force unsigned long long) cputime; | 165 | unsigned long long clock = (__force unsigned long long) cputime; |
| 164 | do_div(clock, 4096000000ULL / USER_HZ); | 166 | do_div(clock, CPUTIME_PER_SEC / USER_HZ); |
| 165 | return clock; | 167 | return clock; |
| 166 | } | 168 | } |
| 167 | 169 | ||
diff --git a/arch/s390/include/asm/debug.h b/arch/s390/include/asm/debug.h index 530c15eb01e9..0206c8052328 100644 --- a/arch/s390/include/asm/debug.h +++ b/arch/s390/include/asm/debug.h | |||
| @@ -151,9 +151,21 @@ debug_text_event(debug_info_t* id, int level, const char* txt) | |||
| 151 | * stored in the s390dbf. See Documentation/s390/s390dbf.txt for more details! | 151 | * stored in the s390dbf. See Documentation/s390/s390dbf.txt for more details! |
| 152 | */ | 152 | */ |
| 153 | extern debug_entry_t * | 153 | extern debug_entry_t * |
| 154 | debug_sprintf_event(debug_info_t* id,int level,char *string,...) | 154 | __debug_sprintf_event(debug_info_t *id, int level, char *string, ...) |
| 155 | __attribute__ ((format(printf, 3, 4))); | 155 | __attribute__ ((format(printf, 3, 4))); |
| 156 | 156 | ||
| 157 | #define debug_sprintf_event(_id, _level, _fmt, ...) \ | ||
| 158 | ({ \ | ||
| 159 | debug_entry_t *__ret; \ | ||
| 160 | debug_info_t *__id = _id; \ | ||
| 161 | int __level = _level; \ | ||
| 162 | if ((!__id) || (__level > __id->level)) \ | ||
| 163 | __ret = NULL; \ | ||
| 164 | else \ | ||
| 165 | __ret = __debug_sprintf_event(__id, __level, \ | ||
| 166 | _fmt, ## __VA_ARGS__); \ | ||
| 167 | __ret; \ | ||
| 168 | }) | ||
| 157 | 169 | ||
| 158 | static inline debug_entry_t* | 170 | static inline debug_entry_t* |
| 159 | debug_exception(debug_info_t* id, int level, void* data, int length) | 171 | debug_exception(debug_info_t* id, int level, void* data, int length) |
| @@ -194,9 +206,22 @@ debug_text_exception(debug_info_t* id, int level, const char* txt) | |||
| 194 | * stored in the s390dbf. See Documentation/s390/s390dbf.txt for more details! | 206 | * stored in the s390dbf. See Documentation/s390/s390dbf.txt for more details! |
| 195 | */ | 207 | */ |
| 196 | extern debug_entry_t * | 208 | extern debug_entry_t * |
| 197 | debug_sprintf_exception(debug_info_t* id,int level,char *string,...) | 209 | __debug_sprintf_exception(debug_info_t *id, int level, char *string, ...) |
| 198 | __attribute__ ((format(printf, 3, 4))); | 210 | __attribute__ ((format(printf, 3, 4))); |
| 199 | 211 | ||
| 212 | #define debug_sprintf_exception(_id, _level, _fmt, ...) \ | ||
| 213 | ({ \ | ||
| 214 | debug_entry_t *__ret; \ | ||
| 215 | debug_info_t *__id = _id; \ | ||
| 216 | int __level = _level; \ | ||
| 217 | if ((!__id) || (__level > __id->level)) \ | ||
| 218 | __ret = NULL; \ | ||
| 219 | else \ | ||
| 220 | __ret = __debug_sprintf_exception(__id, __level, \ | ||
| 221 | _fmt, ## __VA_ARGS__);\ | ||
| 222 | __ret; \ | ||
| 223 | }) | ||
| 224 | |||
| 200 | int debug_register_view(debug_info_t* id, struct debug_view* view); | 225 | int debug_register_view(debug_info_t* id, struct debug_view* view); |
| 201 | int debug_unregister_view(debug_info_t* id, struct debug_view* view); | 226 | int debug_unregister_view(debug_info_t* id, struct debug_view* view); |
| 202 | 227 | ||
diff --git a/arch/s390/include/asm/ftrace.h b/arch/s390/include/asm/ftrace.h index 3aef8afec336..abb618f1ead2 100644 --- a/arch/s390/include/asm/ftrace.h +++ b/arch/s390/include/asm/ftrace.h | |||
| @@ -1,25 +1,69 @@ | |||
| 1 | #ifndef _ASM_S390_FTRACE_H | 1 | #ifndef _ASM_S390_FTRACE_H |
| 2 | #define _ASM_S390_FTRACE_H | 2 | #define _ASM_S390_FTRACE_H |
| 3 | 3 | ||
| 4 | #define ARCH_SUPPORTS_FTRACE_OPS 1 | ||
| 5 | |||
| 6 | #define MCOUNT_INSN_SIZE 24 | ||
| 7 | #define MCOUNT_RETURN_FIXUP 18 | ||
| 8 | |||
| 4 | #ifndef __ASSEMBLY__ | 9 | #ifndef __ASSEMBLY__ |
| 5 | 10 | ||
| 6 | extern void _mcount(void); | 11 | #define ftrace_return_address(n) __builtin_return_address(n) |
| 12 | |||
| 13 | void _mcount(void); | ||
| 14 | void ftrace_caller(void); | ||
| 15 | |||
| 7 | extern char ftrace_graph_caller_end; | 16 | extern char ftrace_graph_caller_end; |
| 17 | extern unsigned long ftrace_plt; | ||
| 8 | 18 | ||
| 9 | struct dyn_arch_ftrace { }; | 19 | struct dyn_arch_ftrace { }; |
| 10 | 20 | ||
| 11 | #define MCOUNT_ADDR ((long)_mcount) | 21 | #define MCOUNT_ADDR ((unsigned long)_mcount) |
| 22 | #define FTRACE_ADDR ((unsigned long)ftrace_caller) | ||
| 12 | 23 | ||
| 24 | #define KPROBE_ON_FTRACE_NOP 0 | ||
| 25 | #define KPROBE_ON_FTRACE_CALL 1 | ||
| 13 | 26 | ||
| 14 | static inline unsigned long ftrace_call_adjust(unsigned long addr) | 27 | static inline unsigned long ftrace_call_adjust(unsigned long addr) |
| 15 | { | 28 | { |
| 16 | return addr; | 29 | return addr; |
| 17 | } | 30 | } |
| 18 | 31 | ||
| 19 | #endif /* __ASSEMBLY__ */ | 32 | struct ftrace_insn { |
| 33 | u16 opc; | ||
| 34 | s32 disp; | ||
| 35 | } __packed; | ||
| 36 | |||
| 37 | static inline void ftrace_generate_nop_insn(struct ftrace_insn *insn) | ||
| 38 | { | ||
| 39 | #ifdef CONFIG_FUNCTION_TRACER | ||
| 40 | /* jg .+24 */ | ||
| 41 | insn->opc = 0xc0f4; | ||
| 42 | insn->disp = MCOUNT_INSN_SIZE / 2; | ||
| 43 | #endif | ||
| 44 | } | ||
| 20 | 45 | ||
| 21 | #define MCOUNT_INSN_SIZE 18 | 46 | static inline int is_ftrace_nop(struct ftrace_insn *insn) |
| 47 | { | ||
| 48 | #ifdef CONFIG_FUNCTION_TRACER | ||
| 49 | if (insn->disp == MCOUNT_INSN_SIZE / 2) | ||
| 50 | return 1; | ||
| 51 | #endif | ||
| 52 | return 0; | ||
| 53 | } | ||
| 22 | 54 | ||
| 23 | #define ARCH_SUPPORTS_FTRACE_OPS 1 | 55 | static inline void ftrace_generate_call_insn(struct ftrace_insn *insn, |
| 56 | unsigned long ip) | ||
| 57 | { | ||
| 58 | #ifdef CONFIG_FUNCTION_TRACER | ||
| 59 | unsigned long target; | ||
| 60 | |||
| 61 | /* brasl r0,ftrace_caller */ | ||
| 62 | target = is_module_addr((void *) ip) ? ftrace_plt : FTRACE_ADDR; | ||
| 63 | insn->opc = 0xc005; | ||
| 64 | insn->disp = (target - ip) / 2; | ||
| 65 | #endif | ||
| 66 | } | ||
| 24 | 67 | ||
| 68 | #endif /* __ASSEMBLY__ */ | ||
| 25 | #endif /* _ASM_S390_FTRACE_H */ | 69 | #endif /* _ASM_S390_FTRACE_H */ |
diff --git a/arch/s390/include/asm/idle.h b/arch/s390/include/asm/idle.h index 6af037f574b8..113cd963dbbe 100644 --- a/arch/s390/include/asm/idle.h +++ b/arch/s390/include/asm/idle.h | |||
| @@ -9,9 +9,10 @@ | |||
| 9 | 9 | ||
| 10 | #include <linux/types.h> | 10 | #include <linux/types.h> |
| 11 | #include <linux/device.h> | 11 | #include <linux/device.h> |
| 12 | #include <linux/seqlock.h> | ||
| 12 | 13 | ||
| 13 | struct s390_idle_data { | 14 | struct s390_idle_data { |
| 14 | unsigned int sequence; | 15 | seqcount_t seqcount; |
| 15 | unsigned long long idle_count; | 16 | unsigned long long idle_count; |
| 16 | unsigned long long idle_time; | 17 | unsigned long long idle_time; |
| 17 | unsigned long long clock_idle_enter; | 18 | unsigned long long clock_idle_enter; |
diff --git a/arch/s390/include/asm/io.h b/arch/s390/include/asm/io.h index 6ad9013c67e7..30fd5c84680e 100644 --- a/arch/s390/include/asm/io.h +++ b/arch/s390/include/asm/io.h | |||
| @@ -39,6 +39,15 @@ static inline void iounmap(volatile void __iomem *addr) | |||
| 39 | { | 39 | { |
| 40 | } | 40 | } |
| 41 | 41 | ||
| 42 | static inline void __iomem *ioport_map(unsigned long port, unsigned int nr) | ||
| 43 | { | ||
| 44 | return NULL; | ||
| 45 | } | ||
| 46 | |||
| 47 | static inline void ioport_unmap(void __iomem *p) | ||
| 48 | { | ||
| 49 | } | ||
| 50 | |||
| 42 | /* | 51 | /* |
| 43 | * s390 needs a private implementation of pci_iomap since ioremap with its | 52 | * s390 needs a private implementation of pci_iomap since ioremap with its |
| 44 | * offset parameter isn't sufficient. That's because BAR spaces are not | 53 | * offset parameter isn't sufficient. That's because BAR spaces are not |
diff --git a/arch/s390/include/asm/irq.h b/arch/s390/include/asm/irq.h index b0d5f0a97a01..343ea7c987aa 100644 --- a/arch/s390/include/asm/irq.h +++ b/arch/s390/include/asm/irq.h | |||
| @@ -1,11 +1,11 @@ | |||
| 1 | #ifndef _ASM_IRQ_H | 1 | #ifndef _ASM_IRQ_H |
| 2 | #define _ASM_IRQ_H | 2 | #define _ASM_IRQ_H |
| 3 | 3 | ||
| 4 | #define EXT_INTERRUPT 1 | 4 | #define EXT_INTERRUPT 0 |
| 5 | #define IO_INTERRUPT 2 | 5 | #define IO_INTERRUPT 1 |
| 6 | #define THIN_INTERRUPT 3 | 6 | #define THIN_INTERRUPT 2 |
| 7 | 7 | ||
| 8 | #define NR_IRQS_BASE 4 | 8 | #define NR_IRQS_BASE 3 |
| 9 | 9 | ||
| 10 | #ifdef CONFIG_PCI_NR_MSI | 10 | #ifdef CONFIG_PCI_NR_MSI |
| 11 | # define NR_IRQS (NR_IRQS_BASE + CONFIG_PCI_NR_MSI) | 11 | # define NR_IRQS (NR_IRQS_BASE + CONFIG_PCI_NR_MSI) |
| @@ -13,9 +13,6 @@ | |||
| 13 | # define NR_IRQS NR_IRQS_BASE | 13 | # define NR_IRQS NR_IRQS_BASE |
| 14 | #endif | 14 | #endif |
| 15 | 15 | ||
| 16 | /* This number is used when no interrupt has been assigned */ | ||
| 17 | #define NO_IRQ 0 | ||
| 18 | |||
| 19 | /* External interruption codes */ | 16 | /* External interruption codes */ |
| 20 | #define EXT_IRQ_INTERRUPT_KEY 0x0040 | 17 | #define EXT_IRQ_INTERRUPT_KEY 0x0040 |
| 21 | #define EXT_IRQ_CLK_COMP 0x1004 | 18 | #define EXT_IRQ_CLK_COMP 0x1004 |
diff --git a/arch/s390/include/asm/kprobes.h b/arch/s390/include/asm/kprobes.h index 98629173ce3b..b47ad3b642cc 100644 --- a/arch/s390/include/asm/kprobes.h +++ b/arch/s390/include/asm/kprobes.h | |||
| @@ -60,6 +60,7 @@ typedef u16 kprobe_opcode_t; | |||
| 60 | struct arch_specific_insn { | 60 | struct arch_specific_insn { |
| 61 | /* copy of original instruction */ | 61 | /* copy of original instruction */ |
| 62 | kprobe_opcode_t *insn; | 62 | kprobe_opcode_t *insn; |
| 63 | unsigned int is_ftrace_insn : 1; | ||
| 63 | }; | 64 | }; |
| 64 | 65 | ||
| 65 | struct prev_kprobe { | 66 | struct prev_kprobe { |
diff --git a/arch/s390/include/asm/lowcore.h b/arch/s390/include/asm/lowcore.h index 6cc51fe84410..34fbcac61133 100644 --- a/arch/s390/include/asm/lowcore.h +++ b/arch/s390/include/asm/lowcore.h | |||
| @@ -147,7 +147,7 @@ struct _lowcore { | |||
| 147 | __u32 softirq_pending; /* 0x02ec */ | 147 | __u32 softirq_pending; /* 0x02ec */ |
| 148 | __u32 percpu_offset; /* 0x02f0 */ | 148 | __u32 percpu_offset; /* 0x02f0 */ |
| 149 | __u32 machine_flags; /* 0x02f4 */ | 149 | __u32 machine_flags; /* 0x02f4 */ |
| 150 | __u32 ftrace_func; /* 0x02f8 */ | 150 | __u8 pad_0x02f8[0x02fc-0x02f8]; /* 0x02f8 */ |
| 151 | __u32 spinlock_lockval; /* 0x02fc */ | 151 | __u32 spinlock_lockval; /* 0x02fc */ |
| 152 | 152 | ||
| 153 | __u8 pad_0x0300[0x0e00-0x0300]; /* 0x0300 */ | 153 | __u8 pad_0x0300[0x0e00-0x0300]; /* 0x0300 */ |
| @@ -297,7 +297,7 @@ struct _lowcore { | |||
| 297 | __u64 percpu_offset; /* 0x0378 */ | 297 | __u64 percpu_offset; /* 0x0378 */ |
| 298 | __u64 vdso_per_cpu_data; /* 0x0380 */ | 298 | __u64 vdso_per_cpu_data; /* 0x0380 */ |
| 299 | __u64 machine_flags; /* 0x0388 */ | 299 | __u64 machine_flags; /* 0x0388 */ |
| 300 | __u64 ftrace_func; /* 0x0390 */ | 300 | __u8 pad_0x0390[0x0398-0x0390]; /* 0x0390 */ |
| 301 | __u64 gmap; /* 0x0398 */ | 301 | __u64 gmap; /* 0x0398 */ |
| 302 | __u32 spinlock_lockval; /* 0x03a0 */ | 302 | __u32 spinlock_lockval; /* 0x03a0 */ |
| 303 | __u8 pad_0x03a0[0x0400-0x03a4]; /* 0x03a4 */ | 303 | __u8 pad_0x03a0[0x0400-0x03a4]; /* 0x03a4 */ |
diff --git a/arch/s390/include/asm/pci.h b/arch/s390/include/asm/pci.h index c030900320e0..ef803c202d42 100644 --- a/arch/s390/include/asm/pci.h +++ b/arch/s390/include/asm/pci.h | |||
| @@ -50,10 +50,6 @@ struct zpci_fmb { | |||
| 50 | atomic64_t unmapped_pages; | 50 | atomic64_t unmapped_pages; |
| 51 | } __packed __aligned(16); | 51 | } __packed __aligned(16); |
| 52 | 52 | ||
| 53 | #define ZPCI_MSI_VEC_BITS 11 | ||
| 54 | #define ZPCI_MSI_VEC_MAX (1 << ZPCI_MSI_VEC_BITS) | ||
| 55 | #define ZPCI_MSI_VEC_MASK (ZPCI_MSI_VEC_MAX - 1) | ||
| 56 | |||
| 57 | enum zpci_state { | 53 | enum zpci_state { |
| 58 | ZPCI_FN_STATE_RESERVED, | 54 | ZPCI_FN_STATE_RESERVED, |
| 59 | ZPCI_FN_STATE_STANDBY, | 55 | ZPCI_FN_STATE_STANDBY, |
| @@ -90,6 +86,7 @@ struct zpci_dev { | |||
| 90 | 86 | ||
| 91 | /* IRQ stuff */ | 87 | /* IRQ stuff */ |
| 92 | u64 msi_addr; /* MSI address */ | 88 | u64 msi_addr; /* MSI address */ |
| 89 | unsigned int max_msi; /* maximum number of MSI's */ | ||
| 93 | struct airq_iv *aibv; /* adapter interrupt bit vector */ | 90 | struct airq_iv *aibv; /* adapter interrupt bit vector */ |
| 94 | unsigned int aisb; /* number of the summary bit */ | 91 | unsigned int aisb; /* number of the summary bit */ |
| 95 | 92 | ||
diff --git a/arch/s390/include/asm/pci_io.h b/arch/s390/include/asm/pci_io.h index d194d544d694..f664e96f48c7 100644 --- a/arch/s390/include/asm/pci_io.h +++ b/arch/s390/include/asm/pci_io.h | |||
| @@ -139,7 +139,8 @@ static inline int zpci_memcpy_fromio(void *dst, | |||
| 139 | int size, rc = 0; | 139 | int size, rc = 0; |
| 140 | 140 | ||
| 141 | while (n > 0) { | 141 | while (n > 0) { |
| 142 | size = zpci_get_max_write_size((u64) src, (u64) dst, n, 8); | 142 | size = zpci_get_max_write_size((u64 __force) src, |
| 143 | (u64) dst, n, 8); | ||
| 143 | req = ZPCI_CREATE_REQ(entry->fh, entry->bar, size); | 144 | req = ZPCI_CREATE_REQ(entry->fh, entry->bar, size); |
| 144 | rc = zpci_read_single(req, dst, offset, size); | 145 | rc = zpci_read_single(req, dst, offset, size); |
| 145 | if (rc) | 146 | if (rc) |
| @@ -162,7 +163,8 @@ static inline int zpci_memcpy_toio(volatile void __iomem *dst, | |||
| 162 | return -EINVAL; | 163 | return -EINVAL; |
| 163 | 164 | ||
| 164 | while (n > 0) { | 165 | while (n > 0) { |
| 165 | size = zpci_get_max_write_size((u64) dst, (u64) src, n, 128); | 166 | size = zpci_get_max_write_size((u64 __force) dst, |
| 167 | (u64) src, n, 128); | ||
| 166 | req = ZPCI_CREATE_REQ(entry->fh, entry->bar, size); | 168 | req = ZPCI_CREATE_REQ(entry->fh, entry->bar, size); |
| 167 | 169 | ||
| 168 | if (size > 8) /* main path */ | 170 | if (size > 8) /* main path */ |
diff --git a/arch/s390/include/asm/pgalloc.h b/arch/s390/include/asm/pgalloc.h index d39a31c3cdf2..e510b9460efa 100644 --- a/arch/s390/include/asm/pgalloc.h +++ b/arch/s390/include/asm/pgalloc.h | |||
| @@ -22,8 +22,6 @@ unsigned long *page_table_alloc(struct mm_struct *); | |||
| 22 | void page_table_free(struct mm_struct *, unsigned long *); | 22 | void page_table_free(struct mm_struct *, unsigned long *); |
| 23 | void page_table_free_rcu(struct mmu_gather *, unsigned long *, unsigned long); | 23 | void page_table_free_rcu(struct mmu_gather *, unsigned long *, unsigned long); |
| 24 | 24 | ||
| 25 | void page_table_reset_pgste(struct mm_struct *, unsigned long, unsigned long, | ||
| 26 | bool init_skey); | ||
| 27 | int set_guest_storage_key(struct mm_struct *mm, unsigned long addr, | 25 | int set_guest_storage_key(struct mm_struct *mm, unsigned long addr, |
| 28 | unsigned long key, bool nq); | 26 | unsigned long key, bool nq); |
| 29 | 27 | ||
diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h index 57c882761dea..5e102422c9ab 100644 --- a/arch/s390/include/asm/pgtable.h +++ b/arch/s390/include/asm/pgtable.h | |||
| @@ -133,6 +133,18 @@ extern unsigned long MODULES_END; | |||
| 133 | #define MODULES_LEN (1UL << 31) | 133 | #define MODULES_LEN (1UL << 31) |
| 134 | #endif | 134 | #endif |
| 135 | 135 | ||
| 136 | static inline int is_module_addr(void *addr) | ||
| 137 | { | ||
| 138 | #ifdef CONFIG_64BIT | ||
| 139 | BUILD_BUG_ON(MODULES_LEN > (1UL << 31)); | ||
| 140 | if (addr < (void *)MODULES_VADDR) | ||
| 141 | return 0; | ||
| 142 | if (addr > (void *)MODULES_END) | ||
| 143 | return 0; | ||
| 144 | #endif | ||
| 145 | return 1; | ||
| 146 | } | ||
| 147 | |||
| 136 | /* | 148 | /* |
| 137 | * A 31 bit pagetable entry of S390 has following format: | 149 | * A 31 bit pagetable entry of S390 has following format: |
| 138 | * | PFRA | | OS | | 150 | * | PFRA | | OS | |
| @@ -479,6 +491,11 @@ static inline int mm_has_pgste(struct mm_struct *mm) | |||
| 479 | return 0; | 491 | return 0; |
| 480 | } | 492 | } |
| 481 | 493 | ||
| 494 | /* | ||
| 495 | * In the case that a guest uses storage keys | ||
| 496 | * faults should no longer be backed by zero pages | ||
| 497 | */ | ||
| 498 | #define mm_forbids_zeropage mm_use_skey | ||
| 482 | static inline int mm_use_skey(struct mm_struct *mm) | 499 | static inline int mm_use_skey(struct mm_struct *mm) |
| 483 | { | 500 | { |
| 484 | #ifdef CONFIG_PGSTE | 501 | #ifdef CONFIG_PGSTE |
| @@ -1634,6 +1651,19 @@ static inline pmd_t pmdp_get_and_clear(struct mm_struct *mm, | |||
| 1634 | return pmd; | 1651 | return pmd; |
| 1635 | } | 1652 | } |
| 1636 | 1653 | ||
| 1654 | #define __HAVE_ARCH_PMDP_GET_AND_CLEAR_FULL | ||
| 1655 | static inline pmd_t pmdp_get_and_clear_full(struct mm_struct *mm, | ||
| 1656 | unsigned long address, | ||
| 1657 | pmd_t *pmdp, int full) | ||
| 1658 | { | ||
| 1659 | pmd_t pmd = *pmdp; | ||
| 1660 | |||
| 1661 | if (!full) | ||
| 1662 | pmdp_flush_lazy(mm, address, pmdp); | ||
| 1663 | pmd_clear(pmdp); | ||
| 1664 | return pmd; | ||
| 1665 | } | ||
| 1666 | |||
| 1637 | #define __HAVE_ARCH_PMDP_CLEAR_FLUSH | 1667 | #define __HAVE_ARCH_PMDP_CLEAR_FLUSH |
| 1638 | static inline pmd_t pmdp_clear_flush(struct vm_area_struct *vma, | 1668 | static inline pmd_t pmdp_clear_flush(struct vm_area_struct *vma, |
| 1639 | unsigned long address, pmd_t *pmdp) | 1669 | unsigned long address, pmd_t *pmdp) |
| @@ -1746,7 +1776,8 @@ static inline pte_t mk_swap_pte(unsigned long type, unsigned long offset) | |||
| 1746 | extern int vmem_add_mapping(unsigned long start, unsigned long size); | 1776 | extern int vmem_add_mapping(unsigned long start, unsigned long size); |
| 1747 | extern int vmem_remove_mapping(unsigned long start, unsigned long size); | 1777 | extern int vmem_remove_mapping(unsigned long start, unsigned long size); |
| 1748 | extern int s390_enable_sie(void); | 1778 | extern int s390_enable_sie(void); |
| 1749 | extern void s390_enable_skey(void); | 1779 | extern int s390_enable_skey(void); |
| 1780 | extern void s390_reset_cmma(struct mm_struct *mm); | ||
| 1750 | 1781 | ||
| 1751 | /* | 1782 | /* |
| 1752 | * No page table caches to initialise | 1783 | * No page table caches to initialise |
diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h index d559bdb03d18..bed05ea7ec27 100644 --- a/arch/s390/include/asm/processor.h +++ b/arch/s390/include/asm/processor.h | |||
| @@ -217,8 +217,6 @@ static inline unsigned short stap(void) | |||
| 217 | */ | 217 | */ |
| 218 | static inline void cpu_relax(void) | 218 | static inline void cpu_relax(void) |
| 219 | { | 219 | { |
| 220 | if (MACHINE_HAS_DIAG44) | ||
| 221 | asm volatile("diag 0,0,68"); | ||
| 222 | barrier(); | 220 | barrier(); |
| 223 | } | 221 | } |
| 224 | 222 | ||
diff --git a/arch/s390/include/asm/spinlock.h b/arch/s390/include/asm/spinlock.h index d6bdf906caa5..0e37cd041241 100644 --- a/arch/s390/include/asm/spinlock.h +++ b/arch/s390/include/asm/spinlock.h | |||
| @@ -18,14 +18,7 @@ extern int spin_retry; | |||
| 18 | static inline int | 18 | static inline int |
| 19 | _raw_compare_and_swap(unsigned int *lock, unsigned int old, unsigned int new) | 19 | _raw_compare_and_swap(unsigned int *lock, unsigned int old, unsigned int new) |
| 20 | { | 20 | { |
| 21 | unsigned int old_expected = old; | 21 | return __sync_bool_compare_and_swap(lock, old, new); |
| 22 | |||
| 23 | asm volatile( | ||
| 24 | " cs %0,%3,%1" | ||
| 25 | : "=d" (old), "=Q" (*lock) | ||
| 26 | : "0" (old), "d" (new), "Q" (*lock) | ||
| 27 | : "cc", "memory" ); | ||
| 28 | return old == old_expected; | ||
| 29 | } | 22 | } |
| 30 | 23 | ||
| 31 | /* | 24 | /* |
diff --git a/arch/s390/include/asm/tlb.h b/arch/s390/include/asm/tlb.h index 572c59949004..06d8741ad6f4 100644 --- a/arch/s390/include/asm/tlb.h +++ b/arch/s390/include/asm/tlb.h | |||
| @@ -121,6 +121,7 @@ static inline void pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd, | |||
| 121 | #ifdef CONFIG_64BIT | 121 | #ifdef CONFIG_64BIT |
| 122 | if (tlb->mm->context.asce_limit <= (1UL << 31)) | 122 | if (tlb->mm->context.asce_limit <= (1UL << 31)) |
| 123 | return; | 123 | return; |
| 124 | pgtable_pmd_page_dtor(virt_to_page(pmd)); | ||
| 124 | tlb_remove_table(tlb, pmd); | 125 | tlb_remove_table(tlb, pmd); |
| 125 | #endif | 126 | #endif |
| 126 | } | 127 | } |
diff --git a/arch/s390/include/uapi/asm/unistd.h b/arch/s390/include/uapi/asm/unistd.h index 4197c89c52d4..2b446cf0cc65 100644 --- a/arch/s390/include/uapi/asm/unistd.h +++ b/arch/s390/include/uapi/asm/unistd.h | |||
| @@ -287,7 +287,9 @@ | |||
| 287 | #define __NR_getrandom 349 | 287 | #define __NR_getrandom 349 |
| 288 | #define __NR_memfd_create 350 | 288 | #define __NR_memfd_create 350 |
| 289 | #define __NR_bpf 351 | 289 | #define __NR_bpf 351 |
| 290 | #define NR_syscalls 352 | 290 | #define __NR_s390_pci_mmio_write 352 |
| 291 | #define __NR_s390_pci_mmio_read 353 | ||
| 292 | #define NR_syscalls 354 | ||
| 291 | 293 | ||
| 292 | /* | 294 | /* |
| 293 | * There are some system calls that are not present on 64 bit, some | 295 | * There are some system calls that are not present on 64 bit, some |
diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c index ef279a136801..e07e91605353 100644 --- a/arch/s390/kernel/asm-offsets.c +++ b/arch/s390/kernel/asm-offsets.c | |||
| @@ -17,8 +17,8 @@ | |||
| 17 | * Make sure that the compiler is new enough. We want a compiler that | 17 | * Make sure that the compiler is new enough. We want a compiler that |
| 18 | * is known to work with the "Q" assembler constraint. | 18 | * is known to work with the "Q" assembler constraint. |
| 19 | */ | 19 | */ |
| 20 | #if __GNUC__ < 3 || (__GNUC__ == 3 && __GNUC_MINOR__ < 3) | 20 | #if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 3) |
| 21 | #error Your compiler is too old; please use version 3.3.3 or newer | 21 | #error Your compiler is too old; please use version 4.3 or newer |
| 22 | #endif | 22 | #endif |
| 23 | 23 | ||
| 24 | int main(void) | 24 | int main(void) |
| @@ -156,7 +156,6 @@ int main(void) | |||
| 156 | DEFINE(__LC_INT_CLOCK, offsetof(struct _lowcore, int_clock)); | 156 | DEFINE(__LC_INT_CLOCK, offsetof(struct _lowcore, int_clock)); |
| 157 | DEFINE(__LC_MCCK_CLOCK, offsetof(struct _lowcore, mcck_clock)); | 157 | DEFINE(__LC_MCCK_CLOCK, offsetof(struct _lowcore, mcck_clock)); |
| 158 | DEFINE(__LC_MACHINE_FLAGS, offsetof(struct _lowcore, machine_flags)); | 158 | DEFINE(__LC_MACHINE_FLAGS, offsetof(struct _lowcore, machine_flags)); |
| 159 | DEFINE(__LC_FTRACE_FUNC, offsetof(struct _lowcore, ftrace_func)); | ||
| 160 | DEFINE(__LC_DUMP_REIPL, offsetof(struct _lowcore, ipib)); | 159 | DEFINE(__LC_DUMP_REIPL, offsetof(struct _lowcore, ipib)); |
| 161 | BLANK(); | 160 | BLANK(); |
| 162 | DEFINE(__LC_CPU_TIMER_SAVE_AREA, offsetof(struct _lowcore, cpu_timer_save_area)); | 161 | DEFINE(__LC_CPU_TIMER_SAVE_AREA, offsetof(struct _lowcore, cpu_timer_save_area)); |
diff --git a/arch/s390/kernel/compat_signal.c b/arch/s390/kernel/compat_signal.c index 009f5eb11125..34d5fa7b01b5 100644 --- a/arch/s390/kernel/compat_signal.c +++ b/arch/s390/kernel/compat_signal.c | |||
| @@ -434,7 +434,7 @@ static int setup_frame32(struct ksignal *ksig, sigset_t *set, | |||
| 434 | ksig->ka.sa.sa_restorer | PSW32_ADDR_AMODE; | 434 | ksig->ka.sa.sa_restorer | PSW32_ADDR_AMODE; |
| 435 | } else { | 435 | } else { |
| 436 | /* Signal frames without vectors registers are short ! */ | 436 | /* Signal frames without vectors registers are short ! */ |
| 437 | __u16 __user *svc = (void *) frame + frame_size - 2; | 437 | __u16 __user *svc = (void __user *) frame + frame_size - 2; |
| 438 | if (__put_user(S390_SYSCALL_OPCODE | __NR_sigreturn, svc)) | 438 | if (__put_user(S390_SYSCALL_OPCODE | __NR_sigreturn, svc)) |
| 439 | return -EFAULT; | 439 | return -EFAULT; |
| 440 | restorer = (unsigned long __force) svc | PSW32_ADDR_AMODE; | 440 | restorer = (unsigned long __force) svc | PSW32_ADDR_AMODE; |
diff --git a/arch/s390/kernel/compat_wrapper.c b/arch/s390/kernel/compat_wrapper.c index c4f7a3d655b8..d7fa2f0f1425 100644 --- a/arch/s390/kernel/compat_wrapper.c +++ b/arch/s390/kernel/compat_wrapper.c | |||
| @@ -218,3 +218,5 @@ COMPAT_SYSCALL_WRAP3(seccomp, unsigned int, op, unsigned int, flags, const char | |||
| 218 | COMPAT_SYSCALL_WRAP3(getrandom, char __user *, buf, size_t, count, unsigned int, flags) | 218 | COMPAT_SYSCALL_WRAP3(getrandom, char __user *, buf, size_t, count, unsigned int, flags) |
| 219 | COMPAT_SYSCALL_WRAP2(memfd_create, const char __user *, uname, unsigned int, flags) | 219 | COMPAT_SYSCALL_WRAP2(memfd_create, const char __user *, uname, unsigned int, flags) |
| 220 | COMPAT_SYSCALL_WRAP3(bpf, int, cmd, union bpf_attr *, attr, unsigned int, size); | 220 | COMPAT_SYSCALL_WRAP3(bpf, int, cmd, union bpf_attr *, attr, unsigned int, size); |
| 221 | COMPAT_SYSCALL_WRAP3(s390_pci_mmio_write, const unsigned long, mmio_addr, const void __user *, user_buffer, const size_t, length); | ||
| 222 | COMPAT_SYSCALL_WRAP3(s390_pci_mmio_read, const unsigned long, mmio_addr, void __user *, user_buffer, const size_t, length); | ||
diff --git a/arch/s390/kernel/debug.c b/arch/s390/kernel/debug.c index ee8390da6ea7..c1f21aca76e7 100644 --- a/arch/s390/kernel/debug.c +++ b/arch/s390/kernel/debug.c | |||
| @@ -1019,7 +1019,7 @@ debug_count_numargs(char *string) | |||
| 1019 | */ | 1019 | */ |
| 1020 | 1020 | ||
| 1021 | debug_entry_t* | 1021 | debug_entry_t* |
| 1022 | debug_sprintf_event(debug_info_t* id, int level,char *string,...) | 1022 | __debug_sprintf_event(debug_info_t *id, int level, char *string, ...) |
| 1023 | { | 1023 | { |
| 1024 | va_list ap; | 1024 | va_list ap; |
| 1025 | int numargs,idx; | 1025 | int numargs,idx; |
| @@ -1027,8 +1027,6 @@ debug_sprintf_event(debug_info_t* id, int level,char *string,...) | |||
| 1027 | debug_sprintf_entry_t *curr_event; | 1027 | debug_sprintf_entry_t *curr_event; |
| 1028 | debug_entry_t *active; | 1028 | debug_entry_t *active; |
| 1029 | 1029 | ||
| 1030 | if((!id) || (level > id->level)) | ||
| 1031 | return NULL; | ||
| 1032 | if (!debug_active || !id->areas) | 1030 | if (!debug_active || !id->areas) |
| 1033 | return NULL; | 1031 | return NULL; |
| 1034 | numargs=debug_count_numargs(string); | 1032 | numargs=debug_count_numargs(string); |
| @@ -1050,14 +1048,14 @@ debug_sprintf_event(debug_info_t* id, int level,char *string,...) | |||
| 1050 | 1048 | ||
| 1051 | return active; | 1049 | return active; |
| 1052 | } | 1050 | } |
| 1053 | EXPORT_SYMBOL(debug_sprintf_event); | 1051 | EXPORT_SYMBOL(__debug_sprintf_event); |
| 1054 | 1052 | ||
| 1055 | /* | 1053 | /* |
| 1056 | * debug_sprintf_exception: | 1054 | * debug_sprintf_exception: |
| 1057 | */ | 1055 | */ |
| 1058 | 1056 | ||
| 1059 | debug_entry_t* | 1057 | debug_entry_t* |
| 1060 | debug_sprintf_exception(debug_info_t* id, int level,char *string,...) | 1058 | __debug_sprintf_exception(debug_info_t *id, int level, char *string, ...) |
| 1061 | { | 1059 | { |
| 1062 | va_list ap; | 1060 | va_list ap; |
| 1063 | int numargs,idx; | 1061 | int numargs,idx; |
| @@ -1065,8 +1063,6 @@ debug_sprintf_exception(debug_info_t* id, int level,char *string,...) | |||
| 1065 | debug_sprintf_entry_t *curr_event; | 1063 | debug_sprintf_entry_t *curr_event; |
| 1066 | debug_entry_t *active; | 1064 | debug_entry_t *active; |
| 1067 | 1065 | ||
| 1068 | if((!id) || (level > id->level)) | ||
| 1069 | return NULL; | ||
| 1070 | if (!debug_active || !id->areas) | 1066 | if (!debug_active || !id->areas) |
| 1071 | return NULL; | 1067 | return NULL; |
| 1072 | 1068 | ||
| @@ -1089,7 +1085,7 @@ debug_sprintf_exception(debug_info_t* id, int level,char *string,...) | |||
| 1089 | 1085 | ||
| 1090 | return active; | 1086 | return active; |
| 1091 | } | 1087 | } |
| 1092 | EXPORT_SYMBOL(debug_sprintf_exception); | 1088 | EXPORT_SYMBOL(__debug_sprintf_exception); |
| 1093 | 1089 | ||
| 1094 | /* | 1090 | /* |
| 1095 | * debug_register_view: | 1091 | * debug_register_view: |
diff --git a/arch/s390/kernel/dumpstack.c b/arch/s390/kernel/dumpstack.c index acb412442e5e..a99852e96a77 100644 --- a/arch/s390/kernel/dumpstack.c +++ b/arch/s390/kernel/dumpstack.c | |||
| @@ -191,7 +191,8 @@ void die(struct pt_regs *regs, const char *str) | |||
| 191 | console_verbose(); | 191 | console_verbose(); |
| 192 | spin_lock_irq(&die_lock); | 192 | spin_lock_irq(&die_lock); |
| 193 | bust_spinlocks(1); | 193 | bust_spinlocks(1); |
| 194 | printk("%s: %04x [#%d] ", str, regs->int_code & 0xffff, ++die_counter); | 194 | printk("%s: %04x ilc:%d [#%d] ", str, regs->int_code & 0xffff, |
| 195 | regs->int_code >> 17, ++die_counter); | ||
| 195 | #ifdef CONFIG_PREEMPT | 196 | #ifdef CONFIG_PREEMPT |
| 196 | printk("PREEMPT "); | 197 | printk("PREEMPT "); |
| 197 | #endif | 198 | #endif |
diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c index cef2879edff3..302ac1f7f8e7 100644 --- a/arch/s390/kernel/early.c +++ b/arch/s390/kernel/early.c | |||
| @@ -12,7 +12,6 @@ | |||
| 12 | #include <linux/errno.h> | 12 | #include <linux/errno.h> |
| 13 | #include <linux/string.h> | 13 | #include <linux/string.h> |
| 14 | #include <linux/ctype.h> | 14 | #include <linux/ctype.h> |
| 15 | #include <linux/ftrace.h> | ||
| 16 | #include <linux/lockdep.h> | 15 | #include <linux/lockdep.h> |
| 17 | #include <linux/module.h> | 16 | #include <linux/module.h> |
| 18 | #include <linux/pfn.h> | 17 | #include <linux/pfn.h> |
| @@ -490,8 +489,5 @@ void __init startup_init(void) | |||
| 490 | detect_machine_facilities(); | 489 | detect_machine_facilities(); |
| 491 | setup_topology(); | 490 | setup_topology(); |
| 492 | sclp_early_detect(); | 491 | sclp_early_detect(); |
| 493 | #ifdef CONFIG_DYNAMIC_FTRACE | ||
| 494 | S390_lowcore.ftrace_func = (unsigned long)ftrace_caller; | ||
| 495 | #endif | ||
| 496 | lockdep_on(); | 492 | lockdep_on(); |
| 497 | } | 493 | } |
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index 70203265196f..398329b2b518 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S | |||
| @@ -53,7 +53,7 @@ _PIF_WORK = (_PIF_PER_TRAP) | |||
| 53 | .macro TRACE_IRQS_ON | 53 | .macro TRACE_IRQS_ON |
| 54 | #ifdef CONFIG_TRACE_IRQFLAGS | 54 | #ifdef CONFIG_TRACE_IRQFLAGS |
| 55 | basr %r2,%r0 | 55 | basr %r2,%r0 |
| 56 | l %r1,BASED(.Lhardirqs_on) | 56 | l %r1,BASED(.Lc_hardirqs_on) |
| 57 | basr %r14,%r1 # call trace_hardirqs_on_caller | 57 | basr %r14,%r1 # call trace_hardirqs_on_caller |
| 58 | #endif | 58 | #endif |
| 59 | .endm | 59 | .endm |
| @@ -61,7 +61,7 @@ _PIF_WORK = (_PIF_PER_TRAP) | |||
| 61 | .macro TRACE_IRQS_OFF | 61 | .macro TRACE_IRQS_OFF |
| 62 | #ifdef CONFIG_TRACE_IRQFLAGS | 62 | #ifdef CONFIG_TRACE_IRQFLAGS |
| 63 | basr %r2,%r0 | 63 | basr %r2,%r0 |
| 64 | l %r1,BASED(.Lhardirqs_off) | 64 | l %r1,BASED(.Lc_hardirqs_off) |
| 65 | basr %r14,%r1 # call trace_hardirqs_off_caller | 65 | basr %r14,%r1 # call trace_hardirqs_off_caller |
| 66 | #endif | 66 | #endif |
| 67 | .endm | 67 | .endm |
| @@ -70,7 +70,7 @@ _PIF_WORK = (_PIF_PER_TRAP) | |||
| 70 | #ifdef CONFIG_LOCKDEP | 70 | #ifdef CONFIG_LOCKDEP |
| 71 | tm __PT_PSW+1(%r11),0x01 # returning to user ? | 71 | tm __PT_PSW+1(%r11),0x01 # returning to user ? |
| 72 | jz .+10 | 72 | jz .+10 |
| 73 | l %r1,BASED(.Llockdep_sys_exit) | 73 | l %r1,BASED(.Lc_lockdep_sys_exit) |
| 74 | basr %r14,%r1 # call lockdep_sys_exit | 74 | basr %r14,%r1 # call lockdep_sys_exit |
| 75 | #endif | 75 | #endif |
| 76 | .endm | 76 | .endm |
| @@ -87,8 +87,8 @@ _PIF_WORK = (_PIF_PER_TRAP) | |||
| 87 | tmh %r8,0x0001 # interrupting from user ? | 87 | tmh %r8,0x0001 # interrupting from user ? |
| 88 | jnz 1f | 88 | jnz 1f |
| 89 | lr %r14,%r9 | 89 | lr %r14,%r9 |
| 90 | sl %r14,BASED(.Lcritical_start) | 90 | sl %r14,BASED(.Lc_critical_start) |
| 91 | cl %r14,BASED(.Lcritical_length) | 91 | cl %r14,BASED(.Lc_critical_length) |
| 92 | jhe 0f | 92 | jhe 0f |
| 93 | la %r11,\savearea # inside critical section, do cleanup | 93 | la %r11,\savearea # inside critical section, do cleanup |
| 94 | bras %r14,cleanup_critical | 94 | bras %r14,cleanup_critical |
| @@ -162,7 +162,7 @@ ENTRY(__switch_to) | |||
| 162 | lm %r6,%r15,__SF_GPRS(%r15) # load gprs of next task | 162 | lm %r6,%r15,__SF_GPRS(%r15) # load gprs of next task |
| 163 | br %r14 | 163 | br %r14 |
| 164 | 164 | ||
| 165 | __critical_start: | 165 | .L__critical_start: |
| 166 | /* | 166 | /* |
| 167 | * SVC interrupt handler routine. System calls are synchronous events and | 167 | * SVC interrupt handler routine. System calls are synchronous events and |
| 168 | * are executed with interrupts enabled. | 168 | * are executed with interrupts enabled. |
| @@ -170,145 +170,145 @@ __critical_start: | |||
| 170 | 170 | ||
| 171 | ENTRY(system_call) | 171 | ENTRY(system_call) |
| 172 | stpt __LC_SYNC_ENTER_TIMER | 172 | stpt __LC_SYNC_ENTER_TIMER |
| 173 | sysc_stm: | 173 | .Lsysc_stm: |
| 174 | stm %r8,%r15,__LC_SAVE_AREA_SYNC | 174 | stm %r8,%r15,__LC_SAVE_AREA_SYNC |
| 175 | l %r12,__LC_THREAD_INFO | 175 | l %r12,__LC_THREAD_INFO |
| 176 | l %r13,__LC_SVC_NEW_PSW+4 | 176 | l %r13,__LC_SVC_NEW_PSW+4 |
| 177 | lhi %r14,_PIF_SYSCALL | 177 | lhi %r14,_PIF_SYSCALL |
| 178 | sysc_per: | 178 | .Lsysc_per: |
| 179 | l %r15,__LC_KERNEL_STACK | 179 | l %r15,__LC_KERNEL_STACK |
| 180 | la %r11,STACK_FRAME_OVERHEAD(%r15) # pointer to pt_regs | 180 | la %r11,STACK_FRAME_OVERHEAD(%r15) # pointer to pt_regs |
| 181 | sysc_vtime: | 181 | .Lsysc_vtime: |
| 182 | UPDATE_VTIME %r8,%r9,__LC_SYNC_ENTER_TIMER | 182 | UPDATE_VTIME %r8,%r9,__LC_SYNC_ENTER_TIMER |
| 183 | stm %r0,%r7,__PT_R0(%r11) | 183 | stm %r0,%r7,__PT_R0(%r11) |
| 184 | mvc __PT_R8(32,%r11),__LC_SAVE_AREA_SYNC | 184 | mvc __PT_R8(32,%r11),__LC_SAVE_AREA_SYNC |
| 185 | mvc __PT_PSW(8,%r11),__LC_SVC_OLD_PSW | 185 | mvc __PT_PSW(8,%r11),__LC_SVC_OLD_PSW |
| 186 | mvc __PT_INT_CODE(4,%r11),__LC_SVC_ILC | 186 | mvc __PT_INT_CODE(4,%r11),__LC_SVC_ILC |
| 187 | st %r14,__PT_FLAGS(%r11) | 187 | st %r14,__PT_FLAGS(%r11) |
| 188 | sysc_do_svc: | 188 | .Lsysc_do_svc: |
| 189 | l %r10,__TI_sysc_table(%r12) # 31 bit system call table | 189 | l %r10,__TI_sysc_table(%r12) # 31 bit system call table |
| 190 | lh %r8,__PT_INT_CODE+2(%r11) | 190 | lh %r8,__PT_INT_CODE+2(%r11) |
| 191 | sla %r8,2 # shift and test for svc0 | 191 | sla %r8,2 # shift and test for svc0 |
| 192 | jnz sysc_nr_ok | 192 | jnz .Lsysc_nr_ok |
| 193 | # svc 0: system call number in %r1 | 193 | # svc 0: system call number in %r1 |
| 194 | cl %r1,BASED(.Lnr_syscalls) | 194 | cl %r1,BASED(.Lnr_syscalls) |
| 195 | jnl sysc_nr_ok | 195 | jnl .Lsysc_nr_ok |
| 196 | sth %r1,__PT_INT_CODE+2(%r11) | 196 | sth %r1,__PT_INT_CODE+2(%r11) |
| 197 | lr %r8,%r1 | 197 | lr %r8,%r1 |
| 198 | sla %r8,2 | 198 | sla %r8,2 |
| 199 | sysc_nr_ok: | 199 | .Lsysc_nr_ok: |
| 200 | xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) | 200 | xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) |
| 201 | st %r2,__PT_ORIG_GPR2(%r11) | 201 | st %r2,__PT_ORIG_GPR2(%r11) |
| 202 | st %r7,STACK_FRAME_OVERHEAD(%r15) | 202 | st %r7,STACK_FRAME_OVERHEAD(%r15) |
| 203 | l %r9,0(%r8,%r10) # get system call addr. | 203 | l %r9,0(%r8,%r10) # get system call addr. |
| 204 | tm __TI_flags+3(%r12),_TIF_TRACE | 204 | tm __TI_flags+3(%r12),_TIF_TRACE |
| 205 | jnz sysc_tracesys | 205 | jnz .Lsysc_tracesys |
| 206 | basr %r14,%r9 # call sys_xxxx | 206 | basr %r14,%r9 # call sys_xxxx |
| 207 | st %r2,__PT_R2(%r11) # store return value | 207 | st %r2,__PT_R2(%r11) # store return value |
| 208 | 208 | ||
| 209 | sysc_return: | 209 | .Lsysc_return: |
| 210 | LOCKDEP_SYS_EXIT | 210 | LOCKDEP_SYS_EXIT |
| 211 | sysc_tif: | 211 | .Lsysc_tif: |
| 212 | tm __PT_PSW+1(%r11),0x01 # returning to user ? | 212 | tm __PT_PSW+1(%r11),0x01 # returning to user ? |
| 213 | jno sysc_restore | 213 | jno .Lsysc_restore |
| 214 | tm __PT_FLAGS+3(%r11),_PIF_WORK | 214 | tm __PT_FLAGS+3(%r11),_PIF_WORK |
| 215 | jnz sysc_work | 215 | jnz .Lsysc_work |
| 216 | tm __TI_flags+3(%r12),_TIF_WORK | 216 | tm __TI_flags+3(%r12),_TIF_WORK |
| 217 | jnz sysc_work # check for thread work | 217 | jnz .Lsysc_work # check for thread work |
| 218 | tm __LC_CPU_FLAGS+3,_CIF_WORK | 218 | tm __LC_CPU_FLAGS+3,_CIF_WORK |
| 219 | jnz sysc_work | 219 | jnz .Lsysc_work |
| 220 | sysc_restore: | 220 | .Lsysc_restore: |
| 221 | mvc __LC_RETURN_PSW(8),__PT_PSW(%r11) | 221 | mvc __LC_RETURN_PSW(8),__PT_PSW(%r11) |
| 222 | stpt __LC_EXIT_TIMER | 222 | stpt __LC_EXIT_TIMER |
| 223 | lm %r0,%r15,__PT_R0(%r11) | 223 | lm %r0,%r15,__PT_R0(%r11) |
| 224 | lpsw __LC_RETURN_PSW | 224 | lpsw __LC_RETURN_PSW |
| 225 | sysc_done: | 225 | .Lsysc_done: |
| 226 | 226 | ||
| 227 | # | 227 | # |
| 228 | # One of the work bits is on. Find out which one. | 228 | # One of the work bits is on. Find out which one. |
| 229 | # | 229 | # |
| 230 | sysc_work: | 230 | .Lsysc_work: |
| 231 | tm __LC_CPU_FLAGS+3,_CIF_MCCK_PENDING | 231 | tm __LC_CPU_FLAGS+3,_CIF_MCCK_PENDING |
| 232 | jo sysc_mcck_pending | 232 | jo .Lsysc_mcck_pending |
| 233 | tm __TI_flags+3(%r12),_TIF_NEED_RESCHED | 233 | tm __TI_flags+3(%r12),_TIF_NEED_RESCHED |
| 234 | jo sysc_reschedule | 234 | jo .Lsysc_reschedule |
| 235 | tm __PT_FLAGS+3(%r11),_PIF_PER_TRAP | 235 | tm __PT_FLAGS+3(%r11),_PIF_PER_TRAP |
| 236 | jo sysc_singlestep | 236 | jo .Lsysc_singlestep |
| 237 | tm __TI_flags+3(%r12),_TIF_SIGPENDING | 237 | tm __TI_flags+3(%r12),_TIF_SIGPENDING |
| 238 | jo sysc_sigpending | 238 | jo .Lsysc_sigpending |
| 239 | tm __TI_flags+3(%r12),_TIF_NOTIFY_RESUME | 239 | tm __TI_flags+3(%r12),_TIF_NOTIFY_RESUME |
| 240 | jo sysc_notify_resume | 240 | jo .Lsysc_notify_resume |
| 241 | tm __LC_CPU_FLAGS+3,_CIF_ASCE | 241 | tm __LC_CPU_FLAGS+3,_CIF_ASCE |
| 242 | jo sysc_uaccess | 242 | jo .Lsysc_uaccess |
| 243 | j sysc_return # beware of critical section cleanup | 243 | j .Lsysc_return # beware of critical section cleanup |
| 244 | 244 | ||
| 245 | # | 245 | # |
| 246 | # _TIF_NEED_RESCHED is set, call schedule | 246 | # _TIF_NEED_RESCHED is set, call schedule |
| 247 | # | 247 | # |
| 248 | sysc_reschedule: | 248 | .Lsysc_reschedule: |
| 249 | l %r1,BASED(.Lschedule) | 249 | l %r1,BASED(.Lc_schedule) |
| 250 | la %r14,BASED(sysc_return) | 250 | la %r14,BASED(.Lsysc_return) |
| 251 | br %r1 # call schedule | 251 | br %r1 # call schedule |
| 252 | 252 | ||
| 253 | # | 253 | # |
| 254 | # _CIF_MCCK_PENDING is set, call handler | 254 | # _CIF_MCCK_PENDING is set, call handler |
| 255 | # | 255 | # |
| 256 | sysc_mcck_pending: | 256 | .Lsysc_mcck_pending: |
| 257 | l %r1,BASED(.Lhandle_mcck) | 257 | l %r1,BASED(.Lc_handle_mcck) |
| 258 | la %r14,BASED(sysc_return) | 258 | la %r14,BASED(.Lsysc_return) |
| 259 | br %r1 # TIF bit will be cleared by handler | 259 | br %r1 # TIF bit will be cleared by handler |
| 260 | 260 | ||
| 261 | # | 261 | # |
| 262 | # _CIF_ASCE is set, load user space asce | 262 | # _CIF_ASCE is set, load user space asce |
| 263 | # | 263 | # |
| 264 | sysc_uaccess: | 264 | .Lsysc_uaccess: |
| 265 | ni __LC_CPU_FLAGS+3,255-_CIF_ASCE | 265 | ni __LC_CPU_FLAGS+3,255-_CIF_ASCE |
| 266 | lctl %c1,%c1,__LC_USER_ASCE # load primary asce | 266 | lctl %c1,%c1,__LC_USER_ASCE # load primary asce |
| 267 | j sysc_return | 267 | j .Lsysc_return |
| 268 | 268 | ||
| 269 | # | 269 | # |
| 270 | # _TIF_SIGPENDING is set, call do_signal | 270 | # _TIF_SIGPENDING is set, call do_signal |
| 271 | # | 271 | # |
| 272 | sysc_sigpending: | 272 | .Lsysc_sigpending: |
| 273 | lr %r2,%r11 # pass pointer to pt_regs | 273 | lr %r2,%r11 # pass pointer to pt_regs |
| 274 | l %r1,BASED(.Ldo_signal) | 274 | l %r1,BASED(.Lc_do_signal) |
| 275 | basr %r14,%r1 # call do_signal | 275 | basr %r14,%r1 # call do_signal |
| 276 | tm __PT_FLAGS+3(%r11),_PIF_SYSCALL | 276 | tm __PT_FLAGS+3(%r11),_PIF_SYSCALL |
| 277 | jno sysc_return | 277 | jno .Lsysc_return |
| 278 | lm %r2,%r7,__PT_R2(%r11) # load svc arguments | 278 | lm %r2,%r7,__PT_R2(%r11) # load svc arguments |
| 279 | l %r10,__TI_sysc_table(%r12) # 31 bit system call table | 279 | l %r10,__TI_sysc_table(%r12) # 31 bit system call table |
| 280 | xr %r8,%r8 # svc 0 returns -ENOSYS | 280 | xr %r8,%r8 # svc 0 returns -ENOSYS |
| 281 | clc __PT_INT_CODE+2(2,%r11),BASED(.Lnr_syscalls+2) | 281 | clc __PT_INT_CODE+2(2,%r11),BASED(.Lnr_syscalls+2) |
| 282 | jnl sysc_nr_ok # invalid svc number -> do svc 0 | 282 | jnl .Lsysc_nr_ok # invalid svc number -> do svc 0 |
| 283 | lh %r8,__PT_INT_CODE+2(%r11) # load new svc number | 283 | lh %r8,__PT_INT_CODE+2(%r11) # load new svc number |
| 284 | sla %r8,2 | 284 | sla %r8,2 |
| 285 | j sysc_nr_ok # restart svc | 285 | j .Lsysc_nr_ok # restart svc |
| 286 | 286 | ||
| 287 | # | 287 | # |
| 288 | # _TIF_NOTIFY_RESUME is set, call do_notify_resume | 288 | # _TIF_NOTIFY_RESUME is set, call do_notify_resume |
| 289 | # | 289 | # |
| 290 | sysc_notify_resume: | 290 | .Lsysc_notify_resume: |
| 291 | lr %r2,%r11 # pass pointer to pt_regs | 291 | lr %r2,%r11 # pass pointer to pt_regs |
| 292 | l %r1,BASED(.Ldo_notify_resume) | 292 | l %r1,BASED(.Lc_do_notify_resume) |
| 293 | la %r14,BASED(sysc_return) | 293 | la %r14,BASED(.Lsysc_return) |
| 294 | br %r1 # call do_notify_resume | 294 | br %r1 # call do_notify_resume |
| 295 | 295 | ||
| 296 | # | 296 | # |
| 297 | # _PIF_PER_TRAP is set, call do_per_trap | 297 | # _PIF_PER_TRAP is set, call do_per_trap |
| 298 | # | 298 | # |
| 299 | sysc_singlestep: | 299 | .Lsysc_singlestep: |
| 300 | ni __PT_FLAGS+3(%r11),255-_PIF_PER_TRAP | 300 | ni __PT_FLAGS+3(%r11),255-_PIF_PER_TRAP |
| 301 | lr %r2,%r11 # pass pointer to pt_regs | 301 | lr %r2,%r11 # pass pointer to pt_regs |
| 302 | l %r1,BASED(.Ldo_per_trap) | 302 | l %r1,BASED(.Lc_do_per_trap) |
| 303 | la %r14,BASED(sysc_return) | 303 | la %r14,BASED(.Lsysc_return) |
| 304 | br %r1 # call do_per_trap | 304 | br %r1 # call do_per_trap |
| 305 | 305 | ||
| 306 | # | 306 | # |
| 307 | # call tracehook_report_syscall_entry/tracehook_report_syscall_exit before | 307 | # call tracehook_report_syscall_entry/tracehook_report_syscall_exit before |
| 308 | # and after the system call | 308 | # and after the system call |
| 309 | # | 309 | # |
| 310 | sysc_tracesys: | 310 | .Lsysc_tracesys: |
| 311 | l %r1,BASED(.Ltrace_enter) | 311 | l %r1,BASED(.Lc_trace_enter) |
| 312 | lr %r2,%r11 # pass pointer to pt_regs | 312 | lr %r2,%r11 # pass pointer to pt_regs |
| 313 | la %r3,0 | 313 | la %r3,0 |
| 314 | xr %r0,%r0 | 314 | xr %r0,%r0 |
| @@ -316,22 +316,22 @@ sysc_tracesys: | |||
| 316 | st %r0,__PT_R2(%r11) | 316 | st %r0,__PT_R2(%r11) |
| 317 | basr %r14,%r1 # call do_syscall_trace_enter | 317 | basr %r14,%r1 # call do_syscall_trace_enter |
| 318 | cl %r2,BASED(.Lnr_syscalls) | 318 | cl %r2,BASED(.Lnr_syscalls) |
| 319 | jnl sysc_tracenogo | 319 | jnl .Lsysc_tracenogo |
| 320 | lr %r8,%r2 | 320 | lr %r8,%r2 |
| 321 | sll %r8,2 | 321 | sll %r8,2 |
| 322 | l %r9,0(%r8,%r10) | 322 | l %r9,0(%r8,%r10) |
| 323 | sysc_tracego: | 323 | .Lsysc_tracego: |
| 324 | lm %r3,%r7,__PT_R3(%r11) | 324 | lm %r3,%r7,__PT_R3(%r11) |
| 325 | st %r7,STACK_FRAME_OVERHEAD(%r15) | 325 | st %r7,STACK_FRAME_OVERHEAD(%r15) |
| 326 | l %r2,__PT_ORIG_GPR2(%r11) | 326 | l %r2,__PT_ORIG_GPR2(%r11) |
| 327 | basr %r14,%r9 # call sys_xxx | 327 | basr %r14,%r9 # call sys_xxx |
| 328 | st %r2,__PT_R2(%r11) # store return value | 328 | st %r2,__PT_R2(%r11) # store return value |
| 329 | sysc_tracenogo: | 329 | .Lsysc_tracenogo: |
| 330 | tm __TI_flags+3(%r12),_TIF_TRACE | 330 | tm __TI_flags+3(%r12),_TIF_TRACE |
| 331 | jz sysc_return | 331 | jz .Lsysc_return |
| 332 | l %r1,BASED(.Ltrace_exit) | 332 | l %r1,BASED(.Lc_trace_exit) |
| 333 | lr %r2,%r11 # pass pointer to pt_regs | 333 | lr %r2,%r11 # pass pointer to pt_regs |
| 334 | la %r14,BASED(sysc_return) | 334 | la %r14,BASED(.Lsysc_return) |
| 335 | br %r1 # call do_syscall_trace_exit | 335 | br %r1 # call do_syscall_trace_exit |
| 336 | 336 | ||
| 337 | # | 337 | # |
| @@ -341,18 +341,18 @@ ENTRY(ret_from_fork) | |||
| 341 | la %r11,STACK_FRAME_OVERHEAD(%r15) | 341 | la %r11,STACK_FRAME_OVERHEAD(%r15) |
| 342 | l %r12,__LC_THREAD_INFO | 342 | l %r12,__LC_THREAD_INFO |
| 343 | l %r13,__LC_SVC_NEW_PSW+4 | 343 | l %r13,__LC_SVC_NEW_PSW+4 |
| 344 | l %r1,BASED(.Lschedule_tail) | 344 | l %r1,BASED(.Lc_schedule_tail) |
| 345 | basr %r14,%r1 # call schedule_tail | 345 | basr %r14,%r1 # call schedule_tail |
| 346 | TRACE_IRQS_ON | 346 | TRACE_IRQS_ON |
| 347 | ssm __LC_SVC_NEW_PSW # reenable interrupts | 347 | ssm __LC_SVC_NEW_PSW # reenable interrupts |
| 348 | tm __PT_PSW+1(%r11),0x01 # forking a kernel thread ? | 348 | tm __PT_PSW+1(%r11),0x01 # forking a kernel thread ? |
| 349 | jne sysc_tracenogo | 349 | jne .Lsysc_tracenogo |
| 350 | # it's a kernel thread | 350 | # it's a kernel thread |
| 351 | lm %r9,%r10,__PT_R9(%r11) # load gprs | 351 | lm %r9,%r10,__PT_R9(%r11) # load gprs |
| 352 | ENTRY(kernel_thread_starter) | 352 | ENTRY(kernel_thread_starter) |
| 353 | la %r2,0(%r10) | 353 | la %r2,0(%r10) |
| 354 | basr %r14,%r9 | 354 | basr %r14,%r9 |
| 355 | j sysc_tracenogo | 355 | j .Lsysc_tracenogo |
| 356 | 356 | ||
| 357 | /* | 357 | /* |
| 358 | * Program check handler routine | 358 | * Program check handler routine |
| @@ -369,7 +369,7 @@ ENTRY(pgm_check_handler) | |||
| 369 | tmh %r8,0x4000 # PER bit set in old PSW ? | 369 | tmh %r8,0x4000 # PER bit set in old PSW ? |
| 370 | jnz 0f # -> enabled, can't be a double fault | 370 | jnz 0f # -> enabled, can't be a double fault |
| 371 | tm __LC_PGM_ILC+3,0x80 # check for per exception | 371 | tm __LC_PGM_ILC+3,0x80 # check for per exception |
| 372 | jnz pgm_svcper # -> single stepped svc | 372 | jnz .Lpgm_svcper # -> single stepped svc |
| 373 | 0: CHECK_STACK STACK_SIZE,__LC_SAVE_AREA_SYNC | 373 | 0: CHECK_STACK STACK_SIZE,__LC_SAVE_AREA_SYNC |
| 374 | ahi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE) | 374 | ahi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE) |
| 375 | j 2f | 375 | j 2f |
| @@ -386,42 +386,42 @@ ENTRY(pgm_check_handler) | |||
| 386 | jz 0f | 386 | jz 0f |
| 387 | l %r1,__TI_task(%r12) | 387 | l %r1,__TI_task(%r12) |
| 388 | tmh %r8,0x0001 # kernel per event ? | 388 | tmh %r8,0x0001 # kernel per event ? |
| 389 | jz pgm_kprobe | 389 | jz .Lpgm_kprobe |
| 390 | oi __PT_FLAGS+3(%r11),_PIF_PER_TRAP | 390 | oi __PT_FLAGS+3(%r11),_PIF_PER_TRAP |
| 391 | mvc __THREAD_per_address(4,%r1),__LC_PER_ADDRESS | 391 | mvc __THREAD_per_address(4,%r1),__LC_PER_ADDRESS |
| 392 | mvc __THREAD_per_cause(2,%r1),__LC_PER_CODE | 392 | mvc __THREAD_per_cause(2,%r1),__LC_PER_CODE |
| 393 | mvc __THREAD_per_paid(1,%r1),__LC_PER_ACCESS_ID | 393 | mvc __THREAD_per_paid(1,%r1),__LC_PER_ACCESS_ID |
| 394 | 0: REENABLE_IRQS | 394 | 0: REENABLE_IRQS |
| 395 | xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) | 395 | xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) |
| 396 | l %r1,BASED(.Ljump_table) | 396 | l %r1,BASED(.Lc_jump_table) |
| 397 | la %r10,0x7f | 397 | la %r10,0x7f |
| 398 | n %r10,__PT_INT_CODE(%r11) | 398 | n %r10,__PT_INT_CODE(%r11) |
| 399 | je sysc_return | 399 | je .Lsysc_return |
| 400 | sll %r10,2 | 400 | sll %r10,2 |
| 401 | l %r1,0(%r10,%r1) # load address of handler routine | 401 | l %r1,0(%r10,%r1) # load address of handler routine |
| 402 | lr %r2,%r11 # pass pointer to pt_regs | 402 | lr %r2,%r11 # pass pointer to pt_regs |
| 403 | basr %r14,%r1 # branch to interrupt-handler | 403 | basr %r14,%r1 # branch to interrupt-handler |
| 404 | j sysc_return | 404 | j .Lsysc_return |
| 405 | 405 | ||
| 406 | # | 406 | # |
| 407 | # PER event in supervisor state, must be kprobes | 407 | # PER event in supervisor state, must be kprobes |
| 408 | # | 408 | # |
| 409 | pgm_kprobe: | 409 | .Lpgm_kprobe: |
| 410 | REENABLE_IRQS | 410 | REENABLE_IRQS |
| 411 | xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) | 411 | xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) |
| 412 | l %r1,BASED(.Ldo_per_trap) | 412 | l %r1,BASED(.Lc_do_per_trap) |
| 413 | lr %r2,%r11 # pass pointer to pt_regs | 413 | lr %r2,%r11 # pass pointer to pt_regs |
| 414 | basr %r14,%r1 # call do_per_trap | 414 | basr %r14,%r1 # call do_per_trap |
| 415 | j sysc_return | 415 | j .Lsysc_return |
| 416 | 416 | ||
| 417 | # | 417 | # |
| 418 | # single stepped system call | 418 | # single stepped system call |
| 419 | # | 419 | # |
| 420 | pgm_svcper: | 420 | .Lpgm_svcper: |
| 421 | mvc __LC_RETURN_PSW(4),__LC_SVC_NEW_PSW | 421 | mvc __LC_RETURN_PSW(4),__LC_SVC_NEW_PSW |
| 422 | mvc __LC_RETURN_PSW+4(4),BASED(.Lsysc_per) | 422 | mvc __LC_RETURN_PSW+4(4),BASED(.Lc_sysc_per) |
| 423 | lhi %r14,_PIF_SYSCALL | _PIF_PER_TRAP | 423 | lhi %r14,_PIF_SYSCALL | _PIF_PER_TRAP |
| 424 | lpsw __LC_RETURN_PSW # branch to sysc_per and enable irqs | 424 | lpsw __LC_RETURN_PSW # branch to .Lsysc_per and enable irqs |
| 425 | 425 | ||
| 426 | /* | 426 | /* |
| 427 | * IO interrupt handler routine | 427 | * IO interrupt handler routine |
| @@ -435,9 +435,9 @@ ENTRY(io_int_handler) | |||
| 435 | l %r13,__LC_SVC_NEW_PSW+4 | 435 | l %r13,__LC_SVC_NEW_PSW+4 |
| 436 | lm %r8,%r9,__LC_IO_OLD_PSW | 436 | lm %r8,%r9,__LC_IO_OLD_PSW |
| 437 | tmh %r8,0x0001 # interrupting from user ? | 437 | tmh %r8,0x0001 # interrupting from user ? |
| 438 | jz io_skip | 438 | jz .Lio_skip |
| 439 | UPDATE_VTIME %r14,%r15,__LC_ASYNC_ENTER_TIMER | 439 | UPDATE_VTIME %r14,%r15,__LC_ASYNC_ENTER_TIMER |
| 440 | io_skip: | 440 | .Lio_skip: |
| 441 | SWITCH_ASYNC __LC_SAVE_AREA_ASYNC,__LC_ASYNC_STACK,STACK_SHIFT | 441 | SWITCH_ASYNC __LC_SAVE_AREA_ASYNC,__LC_ASYNC_STACK,STACK_SHIFT |
| 442 | stm %r0,%r7,__PT_R0(%r11) | 442 | stm %r0,%r7,__PT_R0(%r11) |
| 443 | mvc __PT_R8(32,%r11),__LC_SAVE_AREA_ASYNC | 443 | mvc __PT_R8(32,%r11),__LC_SAVE_AREA_ASYNC |
| @@ -446,35 +446,35 @@ io_skip: | |||
| 446 | xc __PT_FLAGS(4,%r11),__PT_FLAGS(%r11) | 446 | xc __PT_FLAGS(4,%r11),__PT_FLAGS(%r11) |
| 447 | TRACE_IRQS_OFF | 447 | TRACE_IRQS_OFF |
| 448 | xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) | 448 | xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) |
| 449 | io_loop: | 449 | .Lio_loop: |
| 450 | l %r1,BASED(.Ldo_IRQ) | 450 | l %r1,BASED(.Lc_do_IRQ) |
| 451 | lr %r2,%r11 # pass pointer to pt_regs | 451 | lr %r2,%r11 # pass pointer to pt_regs |
| 452 | lhi %r3,IO_INTERRUPT | 452 | lhi %r3,IO_INTERRUPT |
| 453 | tm __PT_INT_CODE+8(%r11),0x80 # adapter interrupt ? | 453 | tm __PT_INT_CODE+8(%r11),0x80 # adapter interrupt ? |
| 454 | jz io_call | 454 | jz .Lio_call |
| 455 | lhi %r3,THIN_INTERRUPT | 455 | lhi %r3,THIN_INTERRUPT |
| 456 | io_call: | 456 | .Lio_call: |
| 457 | basr %r14,%r1 # call do_IRQ | 457 | basr %r14,%r1 # call do_IRQ |
| 458 | tm __LC_MACHINE_FLAGS+2,0x10 # MACHINE_FLAG_LPAR | 458 | tm __LC_MACHINE_FLAGS+2,0x10 # MACHINE_FLAG_LPAR |
| 459 | jz io_return | 459 | jz .Lio_return |
| 460 | tpi 0 | 460 | tpi 0 |
| 461 | jz io_return | 461 | jz .Lio_return |
| 462 | mvc __PT_INT_CODE(12,%r11),__LC_SUBCHANNEL_ID | 462 | mvc __PT_INT_CODE(12,%r11),__LC_SUBCHANNEL_ID |
| 463 | j io_loop | 463 | j .Lio_loop |
| 464 | io_return: | 464 | .Lio_return: |
| 465 | LOCKDEP_SYS_EXIT | 465 | LOCKDEP_SYS_EXIT |
| 466 | TRACE_IRQS_ON | 466 | TRACE_IRQS_ON |
| 467 | io_tif: | 467 | .Lio_tif: |
| 468 | tm __TI_flags+3(%r12),_TIF_WORK | 468 | tm __TI_flags+3(%r12),_TIF_WORK |
| 469 | jnz io_work # there is work to do (signals etc.) | 469 | jnz .Lio_work # there is work to do (signals etc.) |
| 470 | tm __LC_CPU_FLAGS+3,_CIF_WORK | 470 | tm __LC_CPU_FLAGS+3,_CIF_WORK |
| 471 | jnz io_work | 471 | jnz .Lio_work |
| 472 | io_restore: | 472 | .Lio_restore: |
| 473 | mvc __LC_RETURN_PSW(8),__PT_PSW(%r11) | 473 | mvc __LC_RETURN_PSW(8),__PT_PSW(%r11) |
| 474 | stpt __LC_EXIT_TIMER | 474 | stpt __LC_EXIT_TIMER |
| 475 | lm %r0,%r15,__PT_R0(%r11) | 475 | lm %r0,%r15,__PT_R0(%r11) |
| 476 | lpsw __LC_RETURN_PSW | 476 | lpsw __LC_RETURN_PSW |
| 477 | io_done: | 477 | .Lio_done: |
| 478 | 478 | ||
| 479 | # | 479 | # |
| 480 | # There is work todo, find out in which context we have been interrupted: | 480 | # There is work todo, find out in which context we have been interrupted: |
| @@ -483,15 +483,15 @@ io_done: | |||
| 483 | # the preemption counter and if it is zero call preempt_schedule_irq | 483 | # the preemption counter and if it is zero call preempt_schedule_irq |
| 484 | # Before any work can be done, a switch to the kernel stack is required. | 484 | # Before any work can be done, a switch to the kernel stack is required. |
| 485 | # | 485 | # |
| 486 | io_work: | 486 | .Lio_work: |
| 487 | tm __PT_PSW+1(%r11),0x01 # returning to user ? | 487 | tm __PT_PSW+1(%r11),0x01 # returning to user ? |
| 488 | jo io_work_user # yes -> do resched & signal | 488 | jo .Lio_work_user # yes -> do resched & signal |
| 489 | #ifdef CONFIG_PREEMPT | 489 | #ifdef CONFIG_PREEMPT |
| 490 | # check for preemptive scheduling | 490 | # check for preemptive scheduling |
| 491 | icm %r0,15,__TI_precount(%r12) | 491 | icm %r0,15,__TI_precount(%r12) |
| 492 | jnz io_restore # preemption disabled | 492 | jnz .Lio_restore # preemption disabled |
| 493 | tm __TI_flags+3(%r12),_TIF_NEED_RESCHED | 493 | tm __TI_flags+3(%r12),_TIF_NEED_RESCHED |
| 494 | jno io_restore | 494 | jno .Lio_restore |
| 495 | # switch to kernel stack | 495 | # switch to kernel stack |
| 496 | l %r1,__PT_R15(%r11) | 496 | l %r1,__PT_R15(%r11) |
| 497 | ahi %r1,-(STACK_FRAME_OVERHEAD + __PT_SIZE) | 497 | ahi %r1,-(STACK_FRAME_OVERHEAD + __PT_SIZE) |
| @@ -499,20 +499,20 @@ io_work: | |||
| 499 | xc __SF_BACKCHAIN(4,%r1),__SF_BACKCHAIN(%r1) | 499 | xc __SF_BACKCHAIN(4,%r1),__SF_BACKCHAIN(%r1) |
| 500 | la %r11,STACK_FRAME_OVERHEAD(%r1) | 500 | la %r11,STACK_FRAME_OVERHEAD(%r1) |
| 501 | lr %r15,%r1 | 501 | lr %r15,%r1 |
| 502 | # TRACE_IRQS_ON already done at io_return, call | 502 | # TRACE_IRQS_ON already done at .Lio_return, call |
| 503 | # TRACE_IRQS_OFF to keep things symmetrical | 503 | # TRACE_IRQS_OFF to keep things symmetrical |
| 504 | TRACE_IRQS_OFF | 504 | TRACE_IRQS_OFF |
| 505 | l %r1,BASED(.Lpreempt_irq) | 505 | l %r1,BASED(.Lc_preempt_irq) |
| 506 | basr %r14,%r1 # call preempt_schedule_irq | 506 | basr %r14,%r1 # call preempt_schedule_irq |
| 507 | j io_return | 507 | j .Lio_return |
| 508 | #else | 508 | #else |
| 509 | j io_restore | 509 | j .Lio_restore |
| 510 | #endif | 510 | #endif |
| 511 | 511 | ||
| 512 | # | 512 | # |
| 513 | # Need to do work before returning to userspace, switch to kernel stack | 513 | # Need to do work before returning to userspace, switch to kernel stack |
| 514 | # | 514 | # |
| 515 | io_work_user: | 515 | .Lio_work_user: |
| 516 | l %r1,__LC_KERNEL_STACK | 516 | l %r1,__LC_KERNEL_STACK |
| 517 | mvc STACK_FRAME_OVERHEAD(__PT_SIZE,%r1),0(%r11) | 517 | mvc STACK_FRAME_OVERHEAD(__PT_SIZE,%r1),0(%r11) |
| 518 | xc __SF_BACKCHAIN(4,%r1),__SF_BACKCHAIN(%r1) | 518 | xc __SF_BACKCHAIN(4,%r1),__SF_BACKCHAIN(%r1) |
| @@ -522,74 +522,74 @@ io_work_user: | |||
| 522 | # | 522 | # |
| 523 | # One of the work bits is on. Find out which one. | 523 | # One of the work bits is on. Find out which one. |
| 524 | # | 524 | # |
| 525 | io_work_tif: | 525 | .Lio_work_tif: |
| 526 | tm __LC_CPU_FLAGS+3(%r12),_CIF_MCCK_PENDING | 526 | tm __LC_CPU_FLAGS+3(%r12),_CIF_MCCK_PENDING |
| 527 | jo io_mcck_pending | 527 | jo .Lio_mcck_pending |
| 528 | tm __TI_flags+3(%r12),_TIF_NEED_RESCHED | 528 | tm __TI_flags+3(%r12),_TIF_NEED_RESCHED |
| 529 | jo io_reschedule | 529 | jo .Lio_reschedule |
| 530 | tm __TI_flags+3(%r12),_TIF_SIGPENDING | 530 | tm __TI_flags+3(%r12),_TIF_SIGPENDING |
| 531 | jo io_sigpending | 531 | jo .Lio_sigpending |
| 532 | tm __TI_flags+3(%r12),_TIF_NOTIFY_RESUME | 532 | tm __TI_flags+3(%r12),_TIF_NOTIFY_RESUME |
| 533 | jo io_notify_resume | 533 | jo .Lio_notify_resume |
| 534 | tm __LC_CPU_FLAGS+3,_CIF_ASCE | 534 | tm __LC_CPU_FLAGS+3,_CIF_ASCE |
| 535 | jo io_uaccess | 535 | jo .Lio_uaccess |
| 536 | j io_return # beware of critical section cleanup | 536 | j .Lio_return # beware of critical section cleanup |
| 537 | 537 | ||
| 538 | # | 538 | # |
| 539 | # _CIF_MCCK_PENDING is set, call handler | 539 | # _CIF_MCCK_PENDING is set, call handler |
| 540 | # | 540 | # |
| 541 | io_mcck_pending: | 541 | .Lio_mcck_pending: |
| 542 | # TRACE_IRQS_ON already done at io_return | 542 | # TRACE_IRQS_ON already done at .Lio_return |
| 543 | l %r1,BASED(.Lhandle_mcck) | 543 | l %r1,BASED(.Lc_handle_mcck) |
| 544 | basr %r14,%r1 # TIF bit will be cleared by handler | 544 | basr %r14,%r1 # TIF bit will be cleared by handler |
| 545 | TRACE_IRQS_OFF | 545 | TRACE_IRQS_OFF |
| 546 | j io_return | 546 | j .Lio_return |
| 547 | 547 | ||
| 548 | # | 548 | # |
| 549 | # _CIF_ASCE is set, load user space asce | 549 | # _CIF_ASCE is set, load user space asce |
| 550 | # | 550 | # |
| 551 | io_uaccess: | 551 | .Lio_uaccess: |
| 552 | ni __LC_CPU_FLAGS+3,255-_CIF_ASCE | 552 | ni __LC_CPU_FLAGS+3,255-_CIF_ASCE |
| 553 | lctl %c1,%c1,__LC_USER_ASCE # load primary asce | 553 | lctl %c1,%c1,__LC_USER_ASCE # load primary asce |
| 554 | j io_return | 554 | j .Lio_return |
| 555 | 555 | ||
| 556 | # | 556 | # |
| 557 | # _TIF_NEED_RESCHED is set, call schedule | 557 | # _TIF_NEED_RESCHED is set, call schedule |
| 558 | # | 558 | # |
| 559 | io_reschedule: | 559 | .Lio_reschedule: |
| 560 | # TRACE_IRQS_ON already done at io_return | 560 | # TRACE_IRQS_ON already done at .Lio_return |
| 561 | l %r1,BASED(.Lschedule) | 561 | l %r1,BASED(.Lc_schedule) |
| 562 | ssm __LC_SVC_NEW_PSW # reenable interrupts | 562 | ssm __LC_SVC_NEW_PSW # reenable interrupts |
| 563 | basr %r14,%r1 # call scheduler | 563 | basr %r14,%r1 # call scheduler |
| 564 | ssm __LC_PGM_NEW_PSW # disable I/O and ext. interrupts | 564 | ssm __LC_PGM_NEW_PSW # disable I/O and ext. interrupts |
| 565 | TRACE_IRQS_OFF | 565 | TRACE_IRQS_OFF |
| 566 | j io_return | 566 | j .Lio_return |
| 567 | 567 | ||
| 568 | # | 568 | # |
| 569 | # _TIF_SIGPENDING is set, call do_signal | 569 | # _TIF_SIGPENDING is set, call do_signal |
| 570 | # | 570 | # |
| 571 | io_sigpending: | 571 | .Lio_sigpending: |
| 572 | # TRACE_IRQS_ON already done at io_return | 572 | # TRACE_IRQS_ON already done at .Lio_return |
| 573 | l %r1,BASED(.Ldo_signal) | 573 | l %r1,BASED(.Lc_do_signal) |
| 574 | ssm __LC_SVC_NEW_PSW # reenable interrupts | 574 | ssm __LC_SVC_NEW_PSW # reenable interrupts |
| 575 | lr %r2,%r11 # pass pointer to pt_regs | 575 | lr %r2,%r11 # pass pointer to pt_regs |
| 576 | basr %r14,%r1 # call do_signal | 576 | basr %r14,%r1 # call do_signal |
| 577 | ssm __LC_PGM_NEW_PSW # disable I/O and ext. interrupts | 577 | ssm __LC_PGM_NEW_PSW # disable I/O and ext. interrupts |
| 578 | TRACE_IRQS_OFF | 578 | TRACE_IRQS_OFF |
| 579 | j io_return | 579 | j .Lio_return |
| 580 | 580 | ||
| 581 | # | 581 | # |
| 582 | # _TIF_SIGPENDING is set, call do_signal | 582 | # _TIF_SIGPENDING is set, call do_signal |
| 583 | # | 583 | # |
| 584 | io_notify_resume: | 584 | .Lio_notify_resume: |
| 585 | # TRACE_IRQS_ON already done at io_return | 585 | # TRACE_IRQS_ON already done at .Lio_return |
| 586 | l %r1,BASED(.Ldo_notify_resume) | 586 | l %r1,BASED(.Lc_do_notify_resume) |
| 587 | ssm __LC_SVC_NEW_PSW # reenable interrupts | 587 | ssm __LC_SVC_NEW_PSW # reenable interrupts |
| 588 | lr %r2,%r11 # pass pointer to pt_regs | 588 | lr %r2,%r11 # pass pointer to pt_regs |
| 589 | basr %r14,%r1 # call do_notify_resume | 589 | basr %r14,%r1 # call do_notify_resume |
| 590 | ssm __LC_PGM_NEW_PSW # disable I/O and ext. interrupts | 590 | ssm __LC_PGM_NEW_PSW # disable I/O and ext. interrupts |
| 591 | TRACE_IRQS_OFF | 591 | TRACE_IRQS_OFF |
| 592 | j io_return | 592 | j .Lio_return |
| 593 | 593 | ||
| 594 | /* | 594 | /* |
| 595 | * External interrupt handler routine | 595 | * External interrupt handler routine |
| @@ -603,9 +603,9 @@ ENTRY(ext_int_handler) | |||
| 603 | l %r13,__LC_SVC_NEW_PSW+4 | 603 | l %r13,__LC_SVC_NEW_PSW+4 |
| 604 | lm %r8,%r9,__LC_EXT_OLD_PSW | 604 | lm %r8,%r9,__LC_EXT_OLD_PSW |
| 605 | tmh %r8,0x0001 # interrupting from user ? | 605 | tmh %r8,0x0001 # interrupting from user ? |
| 606 | jz ext_skip | 606 | jz .Lext_skip |
| 607 | UPDATE_VTIME %r14,%r15,__LC_ASYNC_ENTER_TIMER | 607 | UPDATE_VTIME %r14,%r15,__LC_ASYNC_ENTER_TIMER |
| 608 | ext_skip: | 608 | .Lext_skip: |
| 609 | SWITCH_ASYNC __LC_SAVE_AREA_ASYNC,__LC_ASYNC_STACK,STACK_SHIFT | 609 | SWITCH_ASYNC __LC_SAVE_AREA_ASYNC,__LC_ASYNC_STACK,STACK_SHIFT |
| 610 | stm %r0,%r7,__PT_R0(%r11) | 610 | stm %r0,%r7,__PT_R0(%r11) |
| 611 | mvc __PT_R8(32,%r11),__LC_SAVE_AREA_ASYNC | 611 | mvc __PT_R8(32,%r11),__LC_SAVE_AREA_ASYNC |
| @@ -614,29 +614,29 @@ ext_skip: | |||
| 614 | mvc __PT_INT_PARM(4,%r11),__LC_EXT_PARAMS | 614 | mvc __PT_INT_PARM(4,%r11),__LC_EXT_PARAMS |
| 615 | xc __PT_FLAGS(4,%r11),__PT_FLAGS(%r11) | 615 | xc __PT_FLAGS(4,%r11),__PT_FLAGS(%r11) |
| 616 | TRACE_IRQS_OFF | 616 | TRACE_IRQS_OFF |
| 617 | l %r1,BASED(.Ldo_IRQ) | 617 | l %r1,BASED(.Lc_do_IRQ) |
| 618 | lr %r2,%r11 # pass pointer to pt_regs | 618 | lr %r2,%r11 # pass pointer to pt_regs |
| 619 | lhi %r3,EXT_INTERRUPT | 619 | lhi %r3,EXT_INTERRUPT |
| 620 | basr %r14,%r1 # call do_IRQ | 620 | basr %r14,%r1 # call do_IRQ |
| 621 | j io_return | 621 | j .Lio_return |
| 622 | 622 | ||
| 623 | /* | 623 | /* |
| 624 | * Load idle PSW. The second "half" of this function is in cleanup_idle. | 624 | * Load idle PSW. The second "half" of this function is in .Lcleanup_idle. |
| 625 | */ | 625 | */ |
| 626 | ENTRY(psw_idle) | 626 | ENTRY(psw_idle) |
| 627 | st %r3,__SF_EMPTY(%r15) | 627 | st %r3,__SF_EMPTY(%r15) |
| 628 | basr %r1,0 | 628 | basr %r1,0 |
| 629 | la %r1,psw_idle_lpsw+4-.(%r1) | 629 | la %r1,.Lpsw_idle_lpsw+4-.(%r1) |
| 630 | st %r1,__SF_EMPTY+4(%r15) | 630 | st %r1,__SF_EMPTY+4(%r15) |
| 631 | oi __SF_EMPTY+4(%r15),0x80 | 631 | oi __SF_EMPTY+4(%r15),0x80 |
| 632 | stck __CLOCK_IDLE_ENTER(%r2) | 632 | stck __CLOCK_IDLE_ENTER(%r2) |
| 633 | stpt __TIMER_IDLE_ENTER(%r2) | 633 | stpt __TIMER_IDLE_ENTER(%r2) |
| 634 | psw_idle_lpsw: | 634 | .Lpsw_idle_lpsw: |
| 635 | lpsw __SF_EMPTY(%r15) | 635 | lpsw __SF_EMPTY(%r15) |
| 636 | br %r14 | 636 | br %r14 |
| 637 | psw_idle_end: | 637 | .Lpsw_idle_end: |
| 638 | 638 | ||
| 639 | __critical_end: | 639 | .L__critical_end: |
| 640 | 640 | ||
| 641 | /* | 641 | /* |
| 642 | * Machine check handler routines | 642 | * Machine check handler routines |
| @@ -650,7 +650,7 @@ ENTRY(mcck_int_handler) | |||
| 650 | l %r13,__LC_SVC_NEW_PSW+4 | 650 | l %r13,__LC_SVC_NEW_PSW+4 |
| 651 | lm %r8,%r9,__LC_MCK_OLD_PSW | 651 | lm %r8,%r9,__LC_MCK_OLD_PSW |
| 652 | tm __LC_MCCK_CODE,0x80 # system damage? | 652 | tm __LC_MCCK_CODE,0x80 # system damage? |
| 653 | jo mcck_panic # yes -> rest of mcck code invalid | 653 | jo .Lmcck_panic # yes -> rest of mcck code invalid |
| 654 | la %r14,__LC_CPU_TIMER_SAVE_AREA | 654 | la %r14,__LC_CPU_TIMER_SAVE_AREA |
| 655 | mvc __LC_MCCK_ENTER_TIMER(8),0(%r14) | 655 | mvc __LC_MCCK_ENTER_TIMER(8),0(%r14) |
| 656 | tm __LC_MCCK_CODE+5,0x02 # stored cpu timer value valid? | 656 | tm __LC_MCCK_CODE+5,0x02 # stored cpu timer value valid? |
| @@ -668,22 +668,22 @@ ENTRY(mcck_int_handler) | |||
| 668 | 2: spt 0(%r14) | 668 | 2: spt 0(%r14) |
| 669 | mvc __LC_MCCK_ENTER_TIMER(8),0(%r14) | 669 | mvc __LC_MCCK_ENTER_TIMER(8),0(%r14) |
| 670 | 3: tm __LC_MCCK_CODE+2,0x09 # mwp + ia of old psw valid? | 670 | 3: tm __LC_MCCK_CODE+2,0x09 # mwp + ia of old psw valid? |
| 671 | jno mcck_panic # no -> skip cleanup critical | 671 | jno .Lmcck_panic # no -> skip cleanup critical |
| 672 | tm %r8,0x0001 # interrupting from user ? | 672 | tm %r8,0x0001 # interrupting from user ? |
| 673 | jz mcck_skip | 673 | jz .Lmcck_skip |
| 674 | UPDATE_VTIME %r14,%r15,__LC_MCCK_ENTER_TIMER | 674 | UPDATE_VTIME %r14,%r15,__LC_MCCK_ENTER_TIMER |
| 675 | mcck_skip: | 675 | .Lmcck_skip: |
| 676 | SWITCH_ASYNC __LC_GPREGS_SAVE_AREA+32,__LC_PANIC_STACK,PAGE_SHIFT | 676 | SWITCH_ASYNC __LC_GPREGS_SAVE_AREA+32,__LC_PANIC_STACK,PAGE_SHIFT |
| 677 | stm %r0,%r7,__PT_R0(%r11) | 677 | stm %r0,%r7,__PT_R0(%r11) |
| 678 | mvc __PT_R8(32,%r11),__LC_GPREGS_SAVE_AREA+32 | 678 | mvc __PT_R8(32,%r11),__LC_GPREGS_SAVE_AREA+32 |
| 679 | stm %r8,%r9,__PT_PSW(%r11) | 679 | stm %r8,%r9,__PT_PSW(%r11) |
| 680 | xc __PT_FLAGS(4,%r11),__PT_FLAGS(%r11) | 680 | xc __PT_FLAGS(4,%r11),__PT_FLAGS(%r11) |
| 681 | xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) | 681 | xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) |
| 682 | l %r1,BASED(.Ldo_machine_check) | 682 | l %r1,BASED(.Lc_do_machine_check) |
| 683 | lr %r2,%r11 # pass pointer to pt_regs | 683 | lr %r2,%r11 # pass pointer to pt_regs |
| 684 | basr %r14,%r1 # call s390_do_machine_check | 684 | basr %r14,%r1 # call s390_do_machine_check |
| 685 | tm __PT_PSW+1(%r11),0x01 # returning to user ? | 685 | tm __PT_PSW+1(%r11),0x01 # returning to user ? |
| 686 | jno mcck_return | 686 | jno .Lmcck_return |
| 687 | l %r1,__LC_KERNEL_STACK # switch to kernel stack | 687 | l %r1,__LC_KERNEL_STACK # switch to kernel stack |
| 688 | mvc STACK_FRAME_OVERHEAD(__PT_SIZE,%r1),0(%r11) | 688 | mvc STACK_FRAME_OVERHEAD(__PT_SIZE,%r1),0(%r11) |
| 689 | xc __SF_BACKCHAIN(4,%r1),__SF_BACKCHAIN(%r1) | 689 | xc __SF_BACKCHAIN(4,%r1),__SF_BACKCHAIN(%r1) |
| @@ -691,12 +691,12 @@ mcck_skip: | |||
| 691 | lr %r15,%r1 | 691 | lr %r15,%r1 |
| 692 | ssm __LC_PGM_NEW_PSW # turn dat on, keep irqs off | 692 | ssm __LC_PGM_NEW_PSW # turn dat on, keep irqs off |
| 693 | tm __LC_CPU_FLAGS+3,_CIF_MCCK_PENDING | 693 | tm __LC_CPU_FLAGS+3,_CIF_MCCK_PENDING |
| 694 | jno mcck_return | 694 | jno .Lmcck_return |
| 695 | TRACE_IRQS_OFF | 695 | TRACE_IRQS_OFF |
| 696 | l %r1,BASED(.Lhandle_mcck) | 696 | l %r1,BASED(.Lc_handle_mcck) |
| 697 | basr %r14,%r1 # call s390_handle_mcck | 697 | basr %r14,%r1 # call s390_handle_mcck |
| 698 | TRACE_IRQS_ON | 698 | TRACE_IRQS_ON |
| 699 | mcck_return: | 699 | .Lmcck_return: |
| 700 | mvc __LC_RETURN_MCCK_PSW(8),__PT_PSW(%r11) # move return PSW | 700 | mvc __LC_RETURN_MCCK_PSW(8),__PT_PSW(%r11) # move return PSW |
| 701 | tm __LC_RETURN_MCCK_PSW+1,0x01 # returning to user ? | 701 | tm __LC_RETURN_MCCK_PSW+1,0x01 # returning to user ? |
| 702 | jno 0f | 702 | jno 0f |
| @@ -706,15 +706,15 @@ mcck_return: | |||
| 706 | 0: lm %r0,%r15,__PT_R0(%r11) | 706 | 0: lm %r0,%r15,__PT_R0(%r11) |
| 707 | lpsw __LC_RETURN_MCCK_PSW | 707 | lpsw __LC_RETURN_MCCK_PSW |
| 708 | 708 | ||
| 709 | mcck_panic: | 709 | .Lmcck_panic: |
| 710 | l %r14,__LC_PANIC_STACK | 710 | l %r14,__LC_PANIC_STACK |
| 711 | slr %r14,%r15 | 711 | slr %r14,%r15 |
| 712 | sra %r14,PAGE_SHIFT | 712 | sra %r14,PAGE_SHIFT |
| 713 | jz 0f | 713 | jz 0f |
| 714 | l %r15,__LC_PANIC_STACK | 714 | l %r15,__LC_PANIC_STACK |
| 715 | j mcck_skip | 715 | j .Lmcck_skip |
| 716 | 0: ahi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE) | 716 | 0: ahi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE) |
| 717 | j mcck_skip | 717 | j .Lmcck_skip |
| 718 | 718 | ||
| 719 | # | 719 | # |
| 720 | # PSW restart interrupt handler | 720 | # PSW restart interrupt handler |
| @@ -764,58 +764,58 @@ stack_overflow: | |||
| 764 | 1: .long kernel_stack_overflow | 764 | 1: .long kernel_stack_overflow |
| 765 | #endif | 765 | #endif |
| 766 | 766 | ||
| 767 | cleanup_table: | 767 | .Lcleanup_table: |
| 768 | .long system_call + 0x80000000 | 768 | .long system_call + 0x80000000 |
| 769 | .long sysc_do_svc + 0x80000000 | 769 | .long .Lsysc_do_svc + 0x80000000 |
| 770 | .long sysc_tif + 0x80000000 | 770 | .long .Lsysc_tif + 0x80000000 |
| 771 | .long sysc_restore + 0x80000000 | 771 | .long .Lsysc_restore + 0x80000000 |
| 772 | .long sysc_done + 0x80000000 | 772 | .long .Lsysc_done + 0x80000000 |
| 773 | .long io_tif + 0x80000000 | 773 | .long .Lio_tif + 0x80000000 |
| 774 | .long io_restore + 0x80000000 | 774 | .long .Lio_restore + 0x80000000 |
| 775 | .long io_done + 0x80000000 | 775 | .long .Lio_done + 0x80000000 |
| 776 | .long psw_idle + 0x80000000 | 776 | .long psw_idle + 0x80000000 |
| 777 | .long psw_idle_end + 0x80000000 | 777 | .long .Lpsw_idle_end + 0x80000000 |
| 778 | 778 | ||
| 779 | cleanup_critical: | 779 | cleanup_critical: |
| 780 | cl %r9,BASED(cleanup_table) # system_call | 780 | cl %r9,BASED(.Lcleanup_table) # system_call |
| 781 | jl 0f | 781 | jl 0f |
| 782 | cl %r9,BASED(cleanup_table+4) # sysc_do_svc | 782 | cl %r9,BASED(.Lcleanup_table+4) # .Lsysc_do_svc |
| 783 | jl cleanup_system_call | 783 | jl .Lcleanup_system_call |
| 784 | cl %r9,BASED(cleanup_table+8) # sysc_tif | 784 | cl %r9,BASED(.Lcleanup_table+8) # .Lsysc_tif |
| 785 | jl 0f | 785 | jl 0f |
| 786 | cl %r9,BASED(cleanup_table+12) # sysc_restore | 786 | cl %r9,BASED(.Lcleanup_table+12) # .Lsysc_restore |
| 787 | jl cleanup_sysc_tif | 787 | jl .Lcleanup_sysc_tif |
| 788 | cl %r9,BASED(cleanup_table+16) # sysc_done | 788 | cl %r9,BASED(.Lcleanup_table+16) # .Lsysc_done |
| 789 | jl cleanup_sysc_restore | 789 | jl .Lcleanup_sysc_restore |
| 790 | cl %r9,BASED(cleanup_table+20) # io_tif | 790 | cl %r9,BASED(.Lcleanup_table+20) # .Lio_tif |
| 791 | jl 0f | 791 | jl 0f |
| 792 | cl %r9,BASED(cleanup_table+24) # io_restore | 792 | cl %r9,BASED(.Lcleanup_table+24) # .Lio_restore |
| 793 | jl cleanup_io_tif | 793 | jl .Lcleanup_io_tif |
| 794 | cl %r9,BASED(cleanup_table+28) # io_done | 794 | cl %r9,BASED(.Lcleanup_table+28) # .Lio_done |
| 795 | jl cleanup_io_restore | 795 | jl .Lcleanup_io_restore |
| 796 | cl %r9,BASED(cleanup_table+32) # psw_idle | 796 | cl %r9,BASED(.Lcleanup_table+32) # psw_idle |
| 797 | jl 0f | 797 | jl 0f |
| 798 | cl %r9,BASED(cleanup_table+36) # psw_idle_end | 798 | cl %r9,BASED(.Lcleanup_table+36) # .Lpsw_idle_end |
| 799 | jl cleanup_idle | 799 | jl .Lcleanup_idle |
| 800 | 0: br %r14 | 800 | 0: br %r14 |
| 801 | 801 | ||
| 802 | cleanup_system_call: | 802 | .Lcleanup_system_call: |
| 803 | # check if stpt has been executed | 803 | # check if stpt has been executed |
| 804 | cl %r9,BASED(cleanup_system_call_insn) | 804 | cl %r9,BASED(.Lcleanup_system_call_insn) |
| 805 | jh 0f | 805 | jh 0f |
| 806 | mvc __LC_SYNC_ENTER_TIMER(8),__LC_ASYNC_ENTER_TIMER | 806 | mvc __LC_SYNC_ENTER_TIMER(8),__LC_ASYNC_ENTER_TIMER |
| 807 | chi %r11,__LC_SAVE_AREA_ASYNC | 807 | chi %r11,__LC_SAVE_AREA_ASYNC |
| 808 | je 0f | 808 | je 0f |
| 809 | mvc __LC_SYNC_ENTER_TIMER(8),__LC_MCCK_ENTER_TIMER | 809 | mvc __LC_SYNC_ENTER_TIMER(8),__LC_MCCK_ENTER_TIMER |
| 810 | 0: # check if stm has been executed | 810 | 0: # check if stm has been executed |
| 811 | cl %r9,BASED(cleanup_system_call_insn+4) | 811 | cl %r9,BASED(.Lcleanup_system_call_insn+4) |
| 812 | jh 0f | 812 | jh 0f |
| 813 | mvc __LC_SAVE_AREA_SYNC(32),0(%r11) | 813 | mvc __LC_SAVE_AREA_SYNC(32),0(%r11) |
| 814 | 0: # set up saved registers r12, and r13 | 814 | 0: # set up saved registers r12, and r13 |
| 815 | st %r12,16(%r11) # r12 thread-info pointer | 815 | st %r12,16(%r11) # r12 thread-info pointer |
| 816 | st %r13,20(%r11) # r13 literal-pool pointer | 816 | st %r13,20(%r11) # r13 literal-pool pointer |
| 817 | # check if the user time calculation has been done | 817 | # check if the user time calculation has been done |
| 818 | cl %r9,BASED(cleanup_system_call_insn+8) | 818 | cl %r9,BASED(.Lcleanup_system_call_insn+8) |
| 819 | jh 0f | 819 | jh 0f |
| 820 | l %r10,__LC_EXIT_TIMER | 820 | l %r10,__LC_EXIT_TIMER |
| 821 | l %r15,__LC_EXIT_TIMER+4 | 821 | l %r15,__LC_EXIT_TIMER+4 |
| @@ -824,7 +824,7 @@ cleanup_system_call: | |||
| 824 | st %r10,__LC_USER_TIMER | 824 | st %r10,__LC_USER_TIMER |
| 825 | st %r15,__LC_USER_TIMER+4 | 825 | st %r15,__LC_USER_TIMER+4 |
| 826 | 0: # check if the system time calculation has been done | 826 | 0: # check if the system time calculation has been done |
| 827 | cl %r9,BASED(cleanup_system_call_insn+12) | 827 | cl %r9,BASED(.Lcleanup_system_call_insn+12) |
| 828 | jh 0f | 828 | jh 0f |
| 829 | l %r10,__LC_LAST_UPDATE_TIMER | 829 | l %r10,__LC_LAST_UPDATE_TIMER |
| 830 | l %r15,__LC_LAST_UPDATE_TIMER+4 | 830 | l %r15,__LC_LAST_UPDATE_TIMER+4 |
| @@ -848,20 +848,20 @@ cleanup_system_call: | |||
| 848 | # setup saved register 15 | 848 | # setup saved register 15 |
| 849 | st %r15,28(%r11) # r15 stack pointer | 849 | st %r15,28(%r11) # r15 stack pointer |
| 850 | # set new psw address and exit | 850 | # set new psw address and exit |
| 851 | l %r9,BASED(cleanup_table+4) # sysc_do_svc + 0x80000000 | 851 | l %r9,BASED(.Lcleanup_table+4) # .Lsysc_do_svc + 0x80000000 |
| 852 | br %r14 | 852 | br %r14 |
| 853 | cleanup_system_call_insn: | 853 | .Lcleanup_system_call_insn: |
| 854 | .long system_call + 0x80000000 | 854 | .long system_call + 0x80000000 |
| 855 | .long sysc_stm + 0x80000000 | 855 | .long .Lsysc_stm + 0x80000000 |
| 856 | .long sysc_vtime + 0x80000000 + 36 | 856 | .long .Lsysc_vtime + 0x80000000 + 36 |
| 857 | .long sysc_vtime + 0x80000000 + 76 | 857 | .long .Lsysc_vtime + 0x80000000 + 76 |
| 858 | 858 | ||
| 859 | cleanup_sysc_tif: | 859 | .Lcleanup_sysc_tif: |
| 860 | l %r9,BASED(cleanup_table+8) # sysc_tif + 0x80000000 | 860 | l %r9,BASED(.Lcleanup_table+8) # .Lsysc_tif + 0x80000000 |
| 861 | br %r14 | 861 | br %r14 |
| 862 | 862 | ||
| 863 | cleanup_sysc_restore: | 863 | .Lcleanup_sysc_restore: |
| 864 | cl %r9,BASED(cleanup_sysc_restore_insn) | 864 | cl %r9,BASED(.Lcleanup_sysc_restore_insn) |
| 865 | jhe 0f | 865 | jhe 0f |
| 866 | l %r9,12(%r11) # get saved pointer to pt_regs | 866 | l %r9,12(%r11) # get saved pointer to pt_regs |
| 867 | mvc __LC_RETURN_PSW(8),__PT_PSW(%r9) | 867 | mvc __LC_RETURN_PSW(8),__PT_PSW(%r9) |
| @@ -869,15 +869,15 @@ cleanup_sysc_restore: | |||
| 869 | lm %r0,%r7,__PT_R0(%r9) | 869 | lm %r0,%r7,__PT_R0(%r9) |
| 870 | 0: lm %r8,%r9,__LC_RETURN_PSW | 870 | 0: lm %r8,%r9,__LC_RETURN_PSW |
| 871 | br %r14 | 871 | br %r14 |
| 872 | cleanup_sysc_restore_insn: | 872 | .Lcleanup_sysc_restore_insn: |
| 873 | .long sysc_done - 4 + 0x80000000 | 873 | .long .Lsysc_done - 4 + 0x80000000 |
| 874 | 874 | ||
| 875 | cleanup_io_tif: | 875 | .Lcleanup_io_tif: |
| 876 | l %r9,BASED(cleanup_table+20) # io_tif + 0x80000000 | 876 | l %r9,BASED(.Lcleanup_table+20) # .Lio_tif + 0x80000000 |
| 877 | br %r14 | 877 | br %r14 |
| 878 | 878 | ||
| 879 | cleanup_io_restore: | 879 | .Lcleanup_io_restore: |
| 880 | cl %r9,BASED(cleanup_io_restore_insn) | 880 | cl %r9,BASED(.Lcleanup_io_restore_insn) |
| 881 | jhe 0f | 881 | jhe 0f |
| 882 | l %r9,12(%r11) # get saved r11 pointer to pt_regs | 882 | l %r9,12(%r11) # get saved r11 pointer to pt_regs |
| 883 | mvc __LC_RETURN_PSW(8),__PT_PSW(%r9) | 883 | mvc __LC_RETURN_PSW(8),__PT_PSW(%r9) |
| @@ -885,10 +885,10 @@ cleanup_io_restore: | |||
| 885 | lm %r0,%r7,__PT_R0(%r9) | 885 | lm %r0,%r7,__PT_R0(%r9) |
| 886 | 0: lm %r8,%r9,__LC_RETURN_PSW | 886 | 0: lm %r8,%r9,__LC_RETURN_PSW |
| 887 | br %r14 | 887 | br %r14 |
| 888 | cleanup_io_restore_insn: | 888 | .Lcleanup_io_restore_insn: |
| 889 | .long io_done - 4 + 0x80000000 | 889 | .long .Lio_done - 4 + 0x80000000 |
| 890 | 890 | ||
| 891 | cleanup_idle: | 891 | .Lcleanup_idle: |
| 892 | # copy interrupt clock & cpu timer | 892 | # copy interrupt clock & cpu timer |
| 893 | mvc __CLOCK_IDLE_EXIT(8,%r2),__LC_INT_CLOCK | 893 | mvc __CLOCK_IDLE_EXIT(8,%r2),__LC_INT_CLOCK |
| 894 | mvc __TIMER_IDLE_EXIT(8,%r2),__LC_ASYNC_ENTER_TIMER | 894 | mvc __TIMER_IDLE_EXIT(8,%r2),__LC_ASYNC_ENTER_TIMER |
| @@ -897,7 +897,7 @@ cleanup_idle: | |||
| 897 | mvc __CLOCK_IDLE_EXIT(8,%r2),__LC_MCCK_CLOCK | 897 | mvc __CLOCK_IDLE_EXIT(8,%r2),__LC_MCCK_CLOCK |
| 898 | mvc __TIMER_IDLE_EXIT(8,%r2),__LC_MCCK_ENTER_TIMER | 898 | mvc __TIMER_IDLE_EXIT(8,%r2),__LC_MCCK_ENTER_TIMER |
| 899 | 0: # check if stck has been executed | 899 | 0: # check if stck has been executed |
| 900 | cl %r9,BASED(cleanup_idle_insn) | 900 | cl %r9,BASED(.Lcleanup_idle_insn) |
| 901 | jhe 1f | 901 | jhe 1f |
| 902 | mvc __CLOCK_IDLE_ENTER(8,%r2),__CLOCK_IDLE_EXIT(%r2) | 902 | mvc __CLOCK_IDLE_ENTER(8,%r2),__CLOCK_IDLE_EXIT(%r2) |
| 903 | mvc __TIMER_IDLE_ENTER(8,%r2),__TIMER_IDLE_EXIT(%r3) | 903 | mvc __TIMER_IDLE_ENTER(8,%r2),__TIMER_IDLE_EXIT(%r3) |
| @@ -913,12 +913,12 @@ cleanup_idle: | |||
| 913 | stm %r9,%r10,__LC_SYSTEM_TIMER | 913 | stm %r9,%r10,__LC_SYSTEM_TIMER |
| 914 | mvc __LC_LAST_UPDATE_TIMER(8),__TIMER_IDLE_EXIT(%r2) | 914 | mvc __LC_LAST_UPDATE_TIMER(8),__TIMER_IDLE_EXIT(%r2) |
| 915 | # prepare return psw | 915 | # prepare return psw |
| 916 | n %r8,BASED(cleanup_idle_wait) # clear irq & wait state bits | 916 | n %r8,BASED(.Lcleanup_idle_wait) # clear irq & wait state bits |
| 917 | l %r9,24(%r11) # return from psw_idle | 917 | l %r9,24(%r11) # return from psw_idle |
| 918 | br %r14 | 918 | br %r14 |
| 919 | cleanup_idle_insn: | 919 | .Lcleanup_idle_insn: |
| 920 | .long psw_idle_lpsw + 0x80000000 | 920 | .long .Lpsw_idle_lpsw + 0x80000000 |
| 921 | cleanup_idle_wait: | 921 | .Lcleanup_idle_wait: |
| 922 | .long 0xfcfdffff | 922 | .long 0xfcfdffff |
| 923 | 923 | ||
| 924 | /* | 924 | /* |
| @@ -933,30 +933,30 @@ cleanup_idle_wait: | |||
| 933 | /* | 933 | /* |
| 934 | * Symbol constants | 934 | * Symbol constants |
| 935 | */ | 935 | */ |
| 936 | .Ldo_machine_check: .long s390_do_machine_check | 936 | .Lc_do_machine_check: .long s390_do_machine_check |
| 937 | .Lhandle_mcck: .long s390_handle_mcck | 937 | .Lc_handle_mcck: .long s390_handle_mcck |
| 938 | .Ldo_IRQ: .long do_IRQ | 938 | .Lc_do_IRQ: .long do_IRQ |
| 939 | .Ldo_signal: .long do_signal | 939 | .Lc_do_signal: .long do_signal |
| 940 | .Ldo_notify_resume: .long do_notify_resume | 940 | .Lc_do_notify_resume: .long do_notify_resume |
| 941 | .Ldo_per_trap: .long do_per_trap | 941 | .Lc_do_per_trap: .long do_per_trap |
| 942 | .Ljump_table: .long pgm_check_table | 942 | .Lc_jump_table: .long pgm_check_table |
| 943 | .Lschedule: .long schedule | 943 | .Lc_schedule: .long schedule |
| 944 | #ifdef CONFIG_PREEMPT | 944 | #ifdef CONFIG_PREEMPT |
| 945 | .Lpreempt_irq: .long preempt_schedule_irq | 945 | .Lc_preempt_irq: .long preempt_schedule_irq |
| 946 | #endif | 946 | #endif |
| 947 | .Ltrace_enter: .long do_syscall_trace_enter | 947 | .Lc_trace_enter: .long do_syscall_trace_enter |
| 948 | .Ltrace_exit: .long do_syscall_trace_exit | 948 | .Lc_trace_exit: .long do_syscall_trace_exit |
| 949 | .Lschedule_tail: .long schedule_tail | 949 | .Lc_schedule_tail: .long schedule_tail |
| 950 | .Lsysc_per: .long sysc_per + 0x80000000 | 950 | .Lc_sysc_per: .long .Lsysc_per + 0x80000000 |
| 951 | #ifdef CONFIG_TRACE_IRQFLAGS | 951 | #ifdef CONFIG_TRACE_IRQFLAGS |
| 952 | .Lhardirqs_on: .long trace_hardirqs_on_caller | 952 | .Lc_hardirqs_on: .long trace_hardirqs_on_caller |
| 953 | .Lhardirqs_off: .long trace_hardirqs_off_caller | 953 | .Lc_hardirqs_off: .long trace_hardirqs_off_caller |
| 954 | #endif | 954 | #endif |
| 955 | #ifdef CONFIG_LOCKDEP | 955 | #ifdef CONFIG_LOCKDEP |
| 956 | .Llockdep_sys_exit: .long lockdep_sys_exit | 956 | .Lc_lockdep_sys_exit: .long lockdep_sys_exit |
| 957 | #endif | 957 | #endif |
| 958 | .Lcritical_start: .long __critical_start + 0x80000000 | 958 | .Lc_critical_start: .long .L__critical_start + 0x80000000 |
| 959 | .Lcritical_length: .long __critical_end - __critical_start | 959 | .Lc_critical_length: .long .L__critical_end - .L__critical_start |
| 960 | 960 | ||
| 961 | .section .rodata, "a" | 961 | .section .rodata, "a" |
| 962 | #define SYSCALL(esa,esame,emu) .long esa | 962 | #define SYSCALL(esa,esame,emu) .long esa |
diff --git a/arch/s390/kernel/entry.h b/arch/s390/kernel/entry.h index 0554b9771c9f..8e61393c8275 100644 --- a/arch/s390/kernel/entry.h +++ b/arch/s390/kernel/entry.h | |||
| @@ -74,4 +74,6 @@ struct old_sigaction; | |||
| 74 | long sys_s390_personality(unsigned int personality); | 74 | long sys_s390_personality(unsigned int personality); |
| 75 | long sys_s390_runtime_instr(int command, int signum); | 75 | long sys_s390_runtime_instr(int command, int signum); |
| 76 | 76 | ||
| 77 | long sys_s390_pci_mmio_write(unsigned long, const void __user *, size_t); | ||
| 78 | long sys_s390_pci_mmio_read(unsigned long, void __user *, size_t); | ||
| 77 | #endif /* _ENTRY_H */ | 79 | #endif /* _ENTRY_H */ |
diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S index 7b2e03afd017..c329446a951d 100644 --- a/arch/s390/kernel/entry64.S +++ b/arch/s390/kernel/entry64.S | |||
| @@ -91,7 +91,7 @@ _PIF_WORK = (_PIF_PER_TRAP) | |||
| 91 | .if \reason==1 | 91 | .if \reason==1 |
| 92 | # Some program interrupts are suppressing (e.g. protection). | 92 | # Some program interrupts are suppressing (e.g. protection). |
| 93 | # We must also check the instruction after SIE in that case. | 93 | # We must also check the instruction after SIE in that case. |
| 94 | # do_protection_exception will rewind to rewind_pad | 94 | # do_protection_exception will rewind to .Lrewind_pad |
| 95 | jh .+42 | 95 | jh .+42 |
| 96 | .else | 96 | .else |
| 97 | jhe .+42 | 97 | jhe .+42 |
| @@ -192,7 +192,7 @@ ENTRY(__switch_to) | |||
| 192 | lmg %r6,%r15,__SF_GPRS(%r15) # load gprs of next task | 192 | lmg %r6,%r15,__SF_GPRS(%r15) # load gprs of next task |
| 193 | br %r14 | 193 | br %r14 |
| 194 | 194 | ||
| 195 | __critical_start: | 195 | .L__critical_start: |
| 196 | /* | 196 | /* |
| 197 | * SVC interrupt handler routine. System calls are synchronous events and | 197 | * SVC interrupt handler routine. System calls are synchronous events and |
| 198 | * are executed with interrupts enabled. | 198 | * are executed with interrupts enabled. |
| @@ -200,15 +200,15 @@ __critical_start: | |||
| 200 | 200 | ||
| 201 | ENTRY(system_call) | 201 | ENTRY(system_call) |
| 202 | stpt __LC_SYNC_ENTER_TIMER | 202 | stpt __LC_SYNC_ENTER_TIMER |
| 203 | sysc_stmg: | 203 | .Lsysc_stmg: |
| 204 | stmg %r8,%r15,__LC_SAVE_AREA_SYNC | 204 | stmg %r8,%r15,__LC_SAVE_AREA_SYNC |
| 205 | lg %r10,__LC_LAST_BREAK | 205 | lg %r10,__LC_LAST_BREAK |
| 206 | lg %r12,__LC_THREAD_INFO | 206 | lg %r12,__LC_THREAD_INFO |
| 207 | lghi %r14,_PIF_SYSCALL | 207 | lghi %r14,_PIF_SYSCALL |
| 208 | sysc_per: | 208 | .Lsysc_per: |
| 209 | lg %r15,__LC_KERNEL_STACK | 209 | lg %r15,__LC_KERNEL_STACK |
| 210 | la %r11,STACK_FRAME_OVERHEAD(%r15) # pointer to pt_regs | 210 | la %r11,STACK_FRAME_OVERHEAD(%r15) # pointer to pt_regs |
| 211 | sysc_vtime: | 211 | .Lsysc_vtime: |
| 212 | UPDATE_VTIME %r13,__LC_SYNC_ENTER_TIMER | 212 | UPDATE_VTIME %r13,__LC_SYNC_ENTER_TIMER |
| 213 | LAST_BREAK %r13 | 213 | LAST_BREAK %r13 |
| 214 | stmg %r0,%r7,__PT_R0(%r11) | 214 | stmg %r0,%r7,__PT_R0(%r11) |
| @@ -216,39 +216,39 @@ sysc_vtime: | |||
| 216 | mvc __PT_PSW(16,%r11),__LC_SVC_OLD_PSW | 216 | mvc __PT_PSW(16,%r11),__LC_SVC_OLD_PSW |
| 217 | mvc __PT_INT_CODE(4,%r11),__LC_SVC_ILC | 217 | mvc __PT_INT_CODE(4,%r11),__LC_SVC_ILC |
| 218 | stg %r14,__PT_FLAGS(%r11) | 218 | stg %r14,__PT_FLAGS(%r11) |
| 219 | sysc_do_svc: | 219 | .Lsysc_do_svc: |
| 220 | lg %r10,__TI_sysc_table(%r12) # address of system call table | 220 | lg %r10,__TI_sysc_table(%r12) # address of system call table |
| 221 | llgh %r8,__PT_INT_CODE+2(%r11) | 221 | llgh %r8,__PT_INT_CODE+2(%r11) |
| 222 | slag %r8,%r8,2 # shift and test for svc 0 | 222 | slag %r8,%r8,2 # shift and test for svc 0 |
| 223 | jnz sysc_nr_ok | 223 | jnz .Lsysc_nr_ok |
| 224 | # svc 0: system call number in %r1 | 224 | # svc 0: system call number in %r1 |
| 225 | llgfr %r1,%r1 # clear high word in r1 | 225 | llgfr %r1,%r1 # clear high word in r1 |
| 226 | cghi %r1,NR_syscalls | 226 | cghi %r1,NR_syscalls |
| 227 | jnl sysc_nr_ok | 227 | jnl .Lsysc_nr_ok |
| 228 | sth %r1,__PT_INT_CODE+2(%r11) | 228 | sth %r1,__PT_INT_CODE+2(%r11) |
| 229 | slag %r8,%r1,2 | 229 | slag %r8,%r1,2 |
| 230 | sysc_nr_ok: | 230 | .Lsysc_nr_ok: |
| 231 | xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) | 231 | xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) |
| 232 | stg %r2,__PT_ORIG_GPR2(%r11) | 232 | stg %r2,__PT_ORIG_GPR2(%r11) |
| 233 | stg %r7,STACK_FRAME_OVERHEAD(%r15) | 233 | stg %r7,STACK_FRAME_OVERHEAD(%r15) |
| 234 | lgf %r9,0(%r8,%r10) # get system call add. | 234 | lgf %r9,0(%r8,%r10) # get system call add. |
| 235 | tm __TI_flags+7(%r12),_TIF_TRACE | 235 | tm __TI_flags+7(%r12),_TIF_TRACE |
| 236 | jnz sysc_tracesys | 236 | jnz .Lsysc_tracesys |
| 237 | basr %r14,%r9 # call sys_xxxx | 237 | basr %r14,%r9 # call sys_xxxx |
| 238 | stg %r2,__PT_R2(%r11) # store return value | 238 | stg %r2,__PT_R2(%r11) # store return value |
| 239 | 239 | ||
| 240 | sysc_return: | 240 | .Lsysc_return: |
| 241 | LOCKDEP_SYS_EXIT | 241 | LOCKDEP_SYS_EXIT |
| 242 | sysc_tif: | 242 | .Lsysc_tif: |
| 243 | tm __PT_PSW+1(%r11),0x01 # returning to user ? | 243 | tm __PT_PSW+1(%r11),0x01 # returning to user ? |
| 244 | jno sysc_restore | 244 | jno .Lsysc_restore |
| 245 | tm __PT_FLAGS+7(%r11),_PIF_WORK | 245 | tm __PT_FLAGS+7(%r11),_PIF_WORK |
| 246 | jnz sysc_work | 246 | jnz .Lsysc_work |
| 247 | tm __TI_flags+7(%r12),_TIF_WORK | 247 | tm __TI_flags+7(%r12),_TIF_WORK |
| 248 | jnz sysc_work # check for work | 248 | jnz .Lsysc_work # check for work |
| 249 | tm __LC_CPU_FLAGS+7,_CIF_WORK | 249 | tm __LC_CPU_FLAGS+7,_CIF_WORK |
| 250 | jnz sysc_work | 250 | jnz .Lsysc_work |
| 251 | sysc_restore: | 251 | .Lsysc_restore: |
| 252 | lg %r14,__LC_VDSO_PER_CPU | 252 | lg %r14,__LC_VDSO_PER_CPU |
| 253 | lmg %r0,%r10,__PT_R0(%r11) | 253 | lmg %r0,%r10,__PT_R0(%r11) |
| 254 | mvc __LC_RETURN_PSW(16),__PT_PSW(%r11) | 254 | mvc __LC_RETURN_PSW(16),__PT_PSW(%r11) |
| @@ -256,101 +256,101 @@ sysc_restore: | |||
| 256 | mvc __VDSO_ECTG_BASE(16,%r14),__LC_EXIT_TIMER | 256 | mvc __VDSO_ECTG_BASE(16,%r14),__LC_EXIT_TIMER |
| 257 | lmg %r11,%r15,__PT_R11(%r11) | 257 | lmg %r11,%r15,__PT_R11(%r11) |
| 258 | lpswe __LC_RETURN_PSW | 258 | lpswe __LC_RETURN_PSW |
| 259 | sysc_done: | 259 | .Lsysc_done: |
| 260 | 260 | ||
| 261 | # | 261 | # |
| 262 | # One of the work bits is on. Find out which one. | 262 | # One of the work bits is on. Find out which one. |
| 263 | # | 263 | # |
| 264 | sysc_work: | 264 | .Lsysc_work: |
| 265 | tm __LC_CPU_FLAGS+7,_CIF_MCCK_PENDING | 265 | tm __LC_CPU_FLAGS+7,_CIF_MCCK_PENDING |
| 266 | jo sysc_mcck_pending | 266 | jo .Lsysc_mcck_pending |
| 267 | tm __TI_flags+7(%r12),_TIF_NEED_RESCHED | 267 | tm __TI_flags+7(%r12),_TIF_NEED_RESCHED |
| 268 | jo sysc_reschedule | 268 | jo .Lsysc_reschedule |
| 269 | #ifdef CONFIG_UPROBES | 269 | #ifdef CONFIG_UPROBES |
| 270 | tm __TI_flags+7(%r12),_TIF_UPROBE | 270 | tm __TI_flags+7(%r12),_TIF_UPROBE |
| 271 | jo sysc_uprobe_notify | 271 | jo .Lsysc_uprobe_notify |
| 272 | #endif | 272 | #endif |
| 273 | tm __PT_FLAGS+7(%r11),_PIF_PER_TRAP | 273 | tm __PT_FLAGS+7(%r11),_PIF_PER_TRAP |
| 274 | jo sysc_singlestep | 274 | jo .Lsysc_singlestep |
| 275 | tm __TI_flags+7(%r12),_TIF_SIGPENDING | 275 | tm __TI_flags+7(%r12),_TIF_SIGPENDING |
| 276 | jo sysc_sigpending | 276 | jo .Lsysc_sigpending |
| 277 | tm __TI_flags+7(%r12),_TIF_NOTIFY_RESUME | 277 | tm __TI_flags+7(%r12),_TIF_NOTIFY_RESUME |
| 278 | jo sysc_notify_resume | 278 | jo .Lsysc_notify_resume |
| 279 | tm __LC_CPU_FLAGS+7,_CIF_ASCE | 279 | tm __LC_CPU_FLAGS+7,_CIF_ASCE |
| 280 | jo sysc_uaccess | 280 | jo .Lsysc_uaccess |
| 281 | j sysc_return # beware of critical section cleanup | 281 | j .Lsysc_return # beware of critical section cleanup |
| 282 | 282 | ||
| 283 | # | 283 | # |
| 284 | # _TIF_NEED_RESCHED is set, call schedule | 284 | # _TIF_NEED_RESCHED is set, call schedule |
| 285 | # | 285 | # |
| 286 | sysc_reschedule: | 286 | .Lsysc_reschedule: |
| 287 | larl %r14,sysc_return | 287 | larl %r14,.Lsysc_return |
| 288 | jg schedule | 288 | jg schedule |
| 289 | 289 | ||
| 290 | # | 290 | # |
| 291 | # _CIF_MCCK_PENDING is set, call handler | 291 | # _CIF_MCCK_PENDING is set, call handler |
| 292 | # | 292 | # |
| 293 | sysc_mcck_pending: | 293 | .Lsysc_mcck_pending: |
| 294 | larl %r14,sysc_return | 294 | larl %r14,.Lsysc_return |
| 295 | jg s390_handle_mcck # TIF bit will be cleared by handler | 295 | jg s390_handle_mcck # TIF bit will be cleared by handler |
| 296 | 296 | ||
| 297 | # | 297 | # |
| 298 | # _CIF_ASCE is set, load user space asce | 298 | # _CIF_ASCE is set, load user space asce |
| 299 | # | 299 | # |
| 300 | sysc_uaccess: | 300 | .Lsysc_uaccess: |
| 301 | ni __LC_CPU_FLAGS+7,255-_CIF_ASCE | 301 | ni __LC_CPU_FLAGS+7,255-_CIF_ASCE |
| 302 | lctlg %c1,%c1,__LC_USER_ASCE # load primary asce | 302 | lctlg %c1,%c1,__LC_USER_ASCE # load primary asce |
| 303 | j sysc_return | 303 | j .Lsysc_return |
| 304 | 304 | ||
| 305 | # | 305 | # |
| 306 | # _TIF_SIGPENDING is set, call do_signal | 306 | # _TIF_SIGPENDING is set, call do_signal |
| 307 | # | 307 | # |
| 308 | sysc_sigpending: | 308 | .Lsysc_sigpending: |
| 309 | lgr %r2,%r11 # pass pointer to pt_regs | 309 | lgr %r2,%r11 # pass pointer to pt_regs |
| 310 | brasl %r14,do_signal | 310 | brasl %r14,do_signal |
| 311 | tm __PT_FLAGS+7(%r11),_PIF_SYSCALL | 311 | tm __PT_FLAGS+7(%r11),_PIF_SYSCALL |
| 312 | jno sysc_return | 312 | jno .Lsysc_return |
| 313 | lmg %r2,%r7,__PT_R2(%r11) # load svc arguments | 313 | lmg %r2,%r7,__PT_R2(%r11) # load svc arguments |
| 314 | lg %r10,__TI_sysc_table(%r12) # address of system call table | 314 | lg %r10,__TI_sysc_table(%r12) # address of system call table |
| 315 | lghi %r8,0 # svc 0 returns -ENOSYS | 315 | lghi %r8,0 # svc 0 returns -ENOSYS |
| 316 | llgh %r1,__PT_INT_CODE+2(%r11) # load new svc number | 316 | llgh %r1,__PT_INT_CODE+2(%r11) # load new svc number |
| 317 | cghi %r1,NR_syscalls | 317 | cghi %r1,NR_syscalls |
| 318 | jnl sysc_nr_ok # invalid svc number -> do svc 0 | 318 | jnl .Lsysc_nr_ok # invalid svc number -> do svc 0 |
| 319 | slag %r8,%r1,2 | 319 | slag %r8,%r1,2 |
| 320 | j sysc_nr_ok # restart svc | 320 | j .Lsysc_nr_ok # restart svc |
| 321 | 321 | ||
| 322 | # | 322 | # |
| 323 | # _TIF_NOTIFY_RESUME is set, call do_notify_resume | 323 | # _TIF_NOTIFY_RESUME is set, call do_notify_resume |
| 324 | # | 324 | # |
| 325 | sysc_notify_resume: | 325 | .Lsysc_notify_resume: |
| 326 | lgr %r2,%r11 # pass pointer to pt_regs | 326 | lgr %r2,%r11 # pass pointer to pt_regs |
| 327 | larl %r14,sysc_return | 327 | larl %r14,.Lsysc_return |
| 328 | jg do_notify_resume | 328 | jg do_notify_resume |
| 329 | 329 | ||
| 330 | # | 330 | # |
| 331 | # _TIF_UPROBE is set, call uprobe_notify_resume | 331 | # _TIF_UPROBE is set, call uprobe_notify_resume |
| 332 | # | 332 | # |
| 333 | #ifdef CONFIG_UPROBES | 333 | #ifdef CONFIG_UPROBES |
| 334 | sysc_uprobe_notify: | 334 | .Lsysc_uprobe_notify: |
| 335 | lgr %r2,%r11 # pass pointer to pt_regs | 335 | lgr %r2,%r11 # pass pointer to pt_regs |
| 336 | larl %r14,sysc_return | 336 | larl %r14,.Lsysc_return |
| 337 | jg uprobe_notify_resume | 337 | jg uprobe_notify_resume |
| 338 | #endif | 338 | #endif |
| 339 | 339 | ||
| 340 | # | 340 | # |
| 341 | # _PIF_PER_TRAP is set, call do_per_trap | 341 | # _PIF_PER_TRAP is set, call do_per_trap |
| 342 | # | 342 | # |
| 343 | sysc_singlestep: | 343 | .Lsysc_singlestep: |
| 344 | ni __PT_FLAGS+7(%r11),255-_PIF_PER_TRAP | 344 | ni __PT_FLAGS+7(%r11),255-_PIF_PER_TRAP |
| 345 | lgr %r2,%r11 # pass pointer to pt_regs | 345 | lgr %r2,%r11 # pass pointer to pt_regs |
| 346 | larl %r14,sysc_return | 346 | larl %r14,.Lsysc_return |
| 347 | jg do_per_trap | 347 | jg do_per_trap |
| 348 | 348 | ||
| 349 | # | 349 | # |
| 350 | # call tracehook_report_syscall_entry/tracehook_report_syscall_exit before | 350 | # call tracehook_report_syscall_entry/tracehook_report_syscall_exit before |
| 351 | # and after the system call | 351 | # and after the system call |
| 352 | # | 352 | # |
| 353 | sysc_tracesys: | 353 | .Lsysc_tracesys: |
| 354 | lgr %r2,%r11 # pass pointer to pt_regs | 354 | lgr %r2,%r11 # pass pointer to pt_regs |
| 355 | la %r3,0 | 355 | la %r3,0 |
| 356 | llgh %r0,__PT_INT_CODE+2(%r11) | 356 | llgh %r0,__PT_INT_CODE+2(%r11) |
| @@ -358,20 +358,20 @@ sysc_tracesys: | |||
| 358 | brasl %r14,do_syscall_trace_enter | 358 | brasl %r14,do_syscall_trace_enter |
| 359 | lghi %r0,NR_syscalls | 359 | lghi %r0,NR_syscalls |
| 360 | clgr %r0,%r2 | 360 | clgr %r0,%r2 |
| 361 | jnh sysc_tracenogo | 361 | jnh .Lsysc_tracenogo |
| 362 | sllg %r8,%r2,2 | 362 | sllg %r8,%r2,2 |
| 363 | lgf %r9,0(%r8,%r10) | 363 | lgf %r9,0(%r8,%r10) |
| 364 | sysc_tracego: | 364 | .Lsysc_tracego: |
| 365 | lmg %r3,%r7,__PT_R3(%r11) | 365 | lmg %r3,%r7,__PT_R3(%r11) |
| 366 | stg %r7,STACK_FRAME_OVERHEAD(%r15) | 366 | stg %r7,STACK_FRAME_OVERHEAD(%r15) |
| 367 | lg %r2,__PT_ORIG_GPR2(%r11) | 367 | lg %r2,__PT_ORIG_GPR2(%r11) |
| 368 | basr %r14,%r9 # call sys_xxx | 368 | basr %r14,%r9 # call sys_xxx |
| 369 | stg %r2,__PT_R2(%r11) # store return value | 369 | stg %r2,__PT_R2(%r11) # store return value |
| 370 | sysc_tracenogo: | 370 | .Lsysc_tracenogo: |
| 371 | tm __TI_flags+7(%r12),_TIF_TRACE | 371 | tm __TI_flags+7(%r12),_TIF_TRACE |
| 372 | jz sysc_return | 372 | jz .Lsysc_return |
| 373 | lgr %r2,%r11 # pass pointer to pt_regs | 373 | lgr %r2,%r11 # pass pointer to pt_regs |
| 374 | larl %r14,sysc_return | 374 | larl %r14,.Lsysc_return |
| 375 | jg do_syscall_trace_exit | 375 | jg do_syscall_trace_exit |
| 376 | 376 | ||
| 377 | # | 377 | # |
| @@ -384,13 +384,13 @@ ENTRY(ret_from_fork) | |||
| 384 | TRACE_IRQS_ON | 384 | TRACE_IRQS_ON |
| 385 | ssm __LC_SVC_NEW_PSW # reenable interrupts | 385 | ssm __LC_SVC_NEW_PSW # reenable interrupts |
| 386 | tm __PT_PSW+1(%r11),0x01 # forking a kernel thread ? | 386 | tm __PT_PSW+1(%r11),0x01 # forking a kernel thread ? |
| 387 | jne sysc_tracenogo | 387 | jne .Lsysc_tracenogo |
| 388 | # it's a kernel thread | 388 | # it's a kernel thread |
| 389 | lmg %r9,%r10,__PT_R9(%r11) # load gprs | 389 | lmg %r9,%r10,__PT_R9(%r11) # load gprs |
| 390 | ENTRY(kernel_thread_starter) | 390 | ENTRY(kernel_thread_starter) |
| 391 | la %r2,0(%r10) | 391 | la %r2,0(%r10) |
| 392 | basr %r14,%r9 | 392 | basr %r14,%r9 |
| 393 | j sysc_tracenogo | 393 | j .Lsysc_tracenogo |
| 394 | 394 | ||
| 395 | /* | 395 | /* |
| 396 | * Program check handler routine | 396 | * Program check handler routine |
| @@ -409,7 +409,7 @@ ENTRY(pgm_check_handler) | |||
| 409 | tmhh %r8,0x4000 # PER bit set in old PSW ? | 409 | tmhh %r8,0x4000 # PER bit set in old PSW ? |
| 410 | jnz 0f # -> enabled, can't be a double fault | 410 | jnz 0f # -> enabled, can't be a double fault |
| 411 | tm __LC_PGM_ILC+3,0x80 # check for per exception | 411 | tm __LC_PGM_ILC+3,0x80 # check for per exception |
| 412 | jnz pgm_svcper # -> single stepped svc | 412 | jnz .Lpgm_svcper # -> single stepped svc |
| 413 | 0: CHECK_STACK STACK_SIZE,__LC_SAVE_AREA_SYNC | 413 | 0: CHECK_STACK STACK_SIZE,__LC_SAVE_AREA_SYNC |
| 414 | aghi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE) | 414 | aghi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE) |
| 415 | j 2f | 415 | j 2f |
| @@ -432,7 +432,7 @@ ENTRY(pgm_check_handler) | |||
| 432 | tm __LC_PGM_ILC+3,0x80 # check for per exception | 432 | tm __LC_PGM_ILC+3,0x80 # check for per exception |
| 433 | jz 0f | 433 | jz 0f |
| 434 | tmhh %r8,0x0001 # kernel per event ? | 434 | tmhh %r8,0x0001 # kernel per event ? |
| 435 | jz pgm_kprobe | 435 | jz .Lpgm_kprobe |
| 436 | oi __PT_FLAGS+7(%r11),_PIF_PER_TRAP | 436 | oi __PT_FLAGS+7(%r11),_PIF_PER_TRAP |
| 437 | mvc __THREAD_per_address(8,%r14),__LC_PER_ADDRESS | 437 | mvc __THREAD_per_address(8,%r14),__LC_PER_ADDRESS |
| 438 | mvc __THREAD_per_cause(2,%r14),__LC_PER_CODE | 438 | mvc __THREAD_per_cause(2,%r14),__LC_PER_CODE |
| @@ -443,31 +443,31 @@ ENTRY(pgm_check_handler) | |||
| 443 | llgh %r10,__PT_INT_CODE+2(%r11) | 443 | llgh %r10,__PT_INT_CODE+2(%r11) |
| 444 | nill %r10,0x007f | 444 | nill %r10,0x007f |
| 445 | sll %r10,2 | 445 | sll %r10,2 |
| 446 | je sysc_return | 446 | je .Lsysc_return |
| 447 | lgf %r1,0(%r10,%r1) # load address of handler routine | 447 | lgf %r1,0(%r10,%r1) # load address of handler routine |
| 448 | lgr %r2,%r11 # pass pointer to pt_regs | 448 | lgr %r2,%r11 # pass pointer to pt_regs |
| 449 | basr %r14,%r1 # branch to interrupt-handler | 449 | basr %r14,%r1 # branch to interrupt-handler |
| 450 | j sysc_return | 450 | j .Lsysc_return |
| 451 | 451 | ||
| 452 | # | 452 | # |
| 453 | # PER event in supervisor state, must be kprobes | 453 | # PER event in supervisor state, must be kprobes |
| 454 | # | 454 | # |
| 455 | pgm_kprobe: | 455 | .Lpgm_kprobe: |
| 456 | REENABLE_IRQS | 456 | REENABLE_IRQS |
| 457 | xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) | 457 | xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) |
| 458 | lgr %r2,%r11 # pass pointer to pt_regs | 458 | lgr %r2,%r11 # pass pointer to pt_regs |
| 459 | brasl %r14,do_per_trap | 459 | brasl %r14,do_per_trap |
| 460 | j sysc_return | 460 | j .Lsysc_return |
| 461 | 461 | ||
| 462 | # | 462 | # |
| 463 | # single stepped system call | 463 | # single stepped system call |
| 464 | # | 464 | # |
| 465 | pgm_svcper: | 465 | .Lpgm_svcper: |
| 466 | mvc __LC_RETURN_PSW(8),__LC_SVC_NEW_PSW | 466 | mvc __LC_RETURN_PSW(8),__LC_SVC_NEW_PSW |
| 467 | larl %r14,sysc_per | 467 | larl %r14,.Lsysc_per |
| 468 | stg %r14,__LC_RETURN_PSW+8 | 468 | stg %r14,__LC_RETURN_PSW+8 |
| 469 | lghi %r14,_PIF_SYSCALL | _PIF_PER_TRAP | 469 | lghi %r14,_PIF_SYSCALL | _PIF_PER_TRAP |
| 470 | lpswe __LC_RETURN_PSW # branch to sysc_per and enable irqs | 470 | lpswe __LC_RETURN_PSW # branch to .Lsysc_per and enable irqs |
| 471 | 471 | ||
| 472 | /* | 472 | /* |
| 473 | * IO interrupt handler routine | 473 | * IO interrupt handler routine |
| @@ -483,10 +483,10 @@ ENTRY(io_int_handler) | |||
| 483 | HANDLE_SIE_INTERCEPT %r14,2 | 483 | HANDLE_SIE_INTERCEPT %r14,2 |
| 484 | SWITCH_ASYNC __LC_SAVE_AREA_ASYNC,__LC_ASYNC_STACK,STACK_SHIFT | 484 | SWITCH_ASYNC __LC_SAVE_AREA_ASYNC,__LC_ASYNC_STACK,STACK_SHIFT |
| 485 | tmhh %r8,0x0001 # interrupting from user? | 485 | tmhh %r8,0x0001 # interrupting from user? |
| 486 | jz io_skip | 486 | jz .Lio_skip |
| 487 | UPDATE_VTIME %r14,__LC_ASYNC_ENTER_TIMER | 487 | UPDATE_VTIME %r14,__LC_ASYNC_ENTER_TIMER |
| 488 | LAST_BREAK %r14 | 488 | LAST_BREAK %r14 |
| 489 | io_skip: | 489 | .Lio_skip: |
| 490 | stmg %r0,%r7,__PT_R0(%r11) | 490 | stmg %r0,%r7,__PT_R0(%r11) |
| 491 | mvc __PT_R8(64,%r11),__LC_SAVE_AREA_ASYNC | 491 | mvc __PT_R8(64,%r11),__LC_SAVE_AREA_ASYNC |
| 492 | stmg %r8,%r9,__PT_PSW(%r11) | 492 | stmg %r8,%r9,__PT_PSW(%r11) |
| @@ -494,29 +494,29 @@ io_skip: | |||
| 494 | xc __PT_FLAGS(8,%r11),__PT_FLAGS(%r11) | 494 | xc __PT_FLAGS(8,%r11),__PT_FLAGS(%r11) |
| 495 | TRACE_IRQS_OFF | 495 | TRACE_IRQS_OFF |
| 496 | xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) | 496 | xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) |
| 497 | io_loop: | 497 | .Lio_loop: |
| 498 | lgr %r2,%r11 # pass pointer to pt_regs | 498 | lgr %r2,%r11 # pass pointer to pt_regs |
| 499 | lghi %r3,IO_INTERRUPT | 499 | lghi %r3,IO_INTERRUPT |
| 500 | tm __PT_INT_CODE+8(%r11),0x80 # adapter interrupt ? | 500 | tm __PT_INT_CODE+8(%r11),0x80 # adapter interrupt ? |
| 501 | jz io_call | 501 | jz .Lio_call |
| 502 | lghi %r3,THIN_INTERRUPT | 502 | lghi %r3,THIN_INTERRUPT |
| 503 | io_call: | 503 | .Lio_call: |
| 504 | brasl %r14,do_IRQ | 504 | brasl %r14,do_IRQ |
| 505 | tm __LC_MACHINE_FLAGS+6,0x10 # MACHINE_FLAG_LPAR | 505 | tm __LC_MACHINE_FLAGS+6,0x10 # MACHINE_FLAG_LPAR |
| 506 | jz io_return | 506 | jz .Lio_return |
| 507 | tpi 0 | 507 | tpi 0 |
| 508 | jz io_return | 508 | jz .Lio_return |
| 509 | mvc __PT_INT_CODE(12,%r11),__LC_SUBCHANNEL_ID | 509 | mvc __PT_INT_CODE(12,%r11),__LC_SUBCHANNEL_ID |
| 510 | j io_loop | 510 | j .Lio_loop |
| 511 | io_return: | 511 | .Lio_return: |
| 512 | LOCKDEP_SYS_EXIT | 512 | LOCKDEP_SYS_EXIT |
| 513 | TRACE_IRQS_ON | 513 | TRACE_IRQS_ON |
| 514 | io_tif: | 514 | .Lio_tif: |
| 515 | tm __TI_flags+7(%r12),_TIF_WORK | 515 | tm __TI_flags+7(%r12),_TIF_WORK |
| 516 | jnz io_work # there is work to do (signals etc.) | 516 | jnz .Lio_work # there is work to do (signals etc.) |
| 517 | tm __LC_CPU_FLAGS+7,_CIF_WORK | 517 | tm __LC_CPU_FLAGS+7,_CIF_WORK |
| 518 | jnz io_work | 518 | jnz .Lio_work |
| 519 | io_restore: | 519 | .Lio_restore: |
| 520 | lg %r14,__LC_VDSO_PER_CPU | 520 | lg %r14,__LC_VDSO_PER_CPU |
| 521 | lmg %r0,%r10,__PT_R0(%r11) | 521 | lmg %r0,%r10,__PT_R0(%r11) |
| 522 | mvc __LC_RETURN_PSW(16),__PT_PSW(%r11) | 522 | mvc __LC_RETURN_PSW(16),__PT_PSW(%r11) |
| @@ -524,7 +524,7 @@ io_restore: | |||
| 524 | mvc __VDSO_ECTG_BASE(16,%r14),__LC_EXIT_TIMER | 524 | mvc __VDSO_ECTG_BASE(16,%r14),__LC_EXIT_TIMER |
| 525 | lmg %r11,%r15,__PT_R11(%r11) | 525 | lmg %r11,%r15,__PT_R11(%r11) |
| 526 | lpswe __LC_RETURN_PSW | 526 | lpswe __LC_RETURN_PSW |
| 527 | io_done: | 527 | .Lio_done: |
| 528 | 528 | ||
| 529 | # | 529 | # |
| 530 | # There is work todo, find out in which context we have been interrupted: | 530 | # There is work todo, find out in which context we have been interrupted: |
| @@ -535,15 +535,15 @@ io_done: | |||
| 535 | # the preemption counter and if it is zero call preempt_schedule_irq | 535 | # the preemption counter and if it is zero call preempt_schedule_irq |
| 536 | # Before any work can be done, a switch to the kernel stack is required. | 536 | # Before any work can be done, a switch to the kernel stack is required. |
| 537 | # | 537 | # |
| 538 | io_work: | 538 | .Lio_work: |
| 539 | tm __PT_PSW+1(%r11),0x01 # returning to user ? | 539 | tm __PT_PSW+1(%r11),0x01 # returning to user ? |
| 540 | jo io_work_user # yes -> do resched & signal | 540 | jo .Lio_work_user # yes -> do resched & signal |
| 541 | #ifdef CONFIG_PREEMPT | 541 | #ifdef CONFIG_PREEMPT |
| 542 | # check for preemptive scheduling | 542 | # check for preemptive scheduling |
| 543 | icm %r0,15,__TI_precount(%r12) | 543 | icm %r0,15,__TI_precount(%r12) |
| 544 | jnz io_restore # preemption is disabled | 544 | jnz .Lio_restore # preemption is disabled |
| 545 | tm __TI_flags+7(%r12),_TIF_NEED_RESCHED | 545 | tm __TI_flags+7(%r12),_TIF_NEED_RESCHED |
| 546 | jno io_restore | 546 | jno .Lio_restore |
| 547 | # switch to kernel stack | 547 | # switch to kernel stack |
| 548 | lg %r1,__PT_R15(%r11) | 548 | lg %r1,__PT_R15(%r11) |
| 549 | aghi %r1,-(STACK_FRAME_OVERHEAD + __PT_SIZE) | 549 | aghi %r1,-(STACK_FRAME_OVERHEAD + __PT_SIZE) |
| @@ -551,19 +551,19 @@ io_work: | |||
| 551 | xc __SF_BACKCHAIN(8,%r1),__SF_BACKCHAIN(%r1) | 551 | xc __SF_BACKCHAIN(8,%r1),__SF_BACKCHAIN(%r1) |
| 552 | la %r11,STACK_FRAME_OVERHEAD(%r1) | 552 | la %r11,STACK_FRAME_OVERHEAD(%r1) |
| 553 | lgr %r15,%r1 | 553 | lgr %r15,%r1 |
| 554 | # TRACE_IRQS_ON already done at io_return, call | 554 | # TRACE_IRQS_ON already done at .Lio_return, call |
| 555 | # TRACE_IRQS_OFF to keep things symmetrical | 555 | # TRACE_IRQS_OFF to keep things symmetrical |
| 556 | TRACE_IRQS_OFF | 556 | TRACE_IRQS_OFF |
| 557 | brasl %r14,preempt_schedule_irq | 557 | brasl %r14,preempt_schedule_irq |
| 558 | j io_return | 558 | j .Lio_return |
| 559 | #else | 559 | #else |
| 560 | j io_restore | 560 | j .Lio_restore |
| 561 | #endif | 561 | #endif |
| 562 | 562 | ||
| 563 | # | 563 | # |
| 564 | # Need to do work before returning to userspace, switch to kernel stack | 564 | # Need to do work before returning to userspace, switch to kernel stack |
| 565 | # | 565 | # |
| 566 | io_work_user: | 566 | .Lio_work_user: |
| 567 | lg %r1,__LC_KERNEL_STACK | 567 | lg %r1,__LC_KERNEL_STACK |
| 568 | mvc STACK_FRAME_OVERHEAD(__PT_SIZE,%r1),0(%r11) | 568 | mvc STACK_FRAME_OVERHEAD(__PT_SIZE,%r1),0(%r11) |
| 569 | xc __SF_BACKCHAIN(8,%r1),__SF_BACKCHAIN(%r1) | 569 | xc __SF_BACKCHAIN(8,%r1),__SF_BACKCHAIN(%r1) |
| @@ -573,70 +573,70 @@ io_work_user: | |||
| 573 | # | 573 | # |
| 574 | # One of the work bits is on. Find out which one. | 574 | # One of the work bits is on. Find out which one. |
| 575 | # | 575 | # |
| 576 | io_work_tif: | 576 | .Lio_work_tif: |
| 577 | tm __LC_CPU_FLAGS+7,_CIF_MCCK_PENDING | 577 | tm __LC_CPU_FLAGS+7,_CIF_MCCK_PENDING |
| 578 | jo io_mcck_pending | 578 | jo .Lio_mcck_pending |
| 579 | tm __TI_flags+7(%r12),_TIF_NEED_RESCHED | 579 | tm __TI_flags+7(%r12),_TIF_NEED_RESCHED |
| 580 | jo io_reschedule | 580 | jo .Lio_reschedule |
| 581 | tm __TI_flags+7(%r12),_TIF_SIGPENDING | 581 | tm __TI_flags+7(%r12),_TIF_SIGPENDING |
| 582 | jo io_sigpending | 582 | jo .Lio_sigpending |
| 583 | tm __TI_flags+7(%r12),_TIF_NOTIFY_RESUME | 583 | tm __TI_flags+7(%r12),_TIF_NOTIFY_RESUME |
| 584 | jo io_notify_resume | 584 | jo .Lio_notify_resume |
| 585 | tm __LC_CPU_FLAGS+7,_CIF_ASCE | 585 | tm __LC_CPU_FLAGS+7,_CIF_ASCE |
| 586 | jo io_uaccess | 586 | jo .Lio_uaccess |
| 587 | j io_return # beware of critical section cleanup | 587 | j .Lio_return # beware of critical section cleanup |
| 588 | 588 | ||
| 589 | # | 589 | # |
| 590 | # _CIF_MCCK_PENDING is set, call handler | 590 | # _CIF_MCCK_PENDING is set, call handler |
| 591 | # | 591 | # |
| 592 | io_mcck_pending: | 592 | .Lio_mcck_pending: |
| 593 | # TRACE_IRQS_ON already done at io_return | 593 | # TRACE_IRQS_ON already done at .Lio_return |
| 594 | brasl %r14,s390_handle_mcck # TIF bit will be cleared by handler | 594 | brasl %r14,s390_handle_mcck # TIF bit will be cleared by handler |
| 595 | TRACE_IRQS_OFF | 595 | TRACE_IRQS_OFF |
| 596 | j io_return | 596 | j .Lio_return |
| 597 | 597 | ||
| 598 | # | 598 | # |
| 599 | # _CIF_ASCE is set, load user space asce | 599 | # _CIF_ASCE is set, load user space asce |
| 600 | # | 600 | # |
| 601 | io_uaccess: | 601 | .Lio_uaccess: |
| 602 | ni __LC_CPU_FLAGS+7,255-_CIF_ASCE | 602 | ni __LC_CPU_FLAGS+7,255-_CIF_ASCE |
| 603 | lctlg %c1,%c1,__LC_USER_ASCE # load primary asce | 603 | lctlg %c1,%c1,__LC_USER_ASCE # load primary asce |
| 604 | j io_return | 604 | j .Lio_return |
| 605 | 605 | ||
| 606 | # | 606 | # |
| 607 | # _TIF_NEED_RESCHED is set, call schedule | 607 | # _TIF_NEED_RESCHED is set, call schedule |
| 608 | # | 608 | # |
| 609 | io_reschedule: | 609 | .Lio_reschedule: |
| 610 | # TRACE_IRQS_ON already done at io_return | 610 | # TRACE_IRQS_ON already done at .Lio_return |
| 611 | ssm __LC_SVC_NEW_PSW # reenable interrupts | 611 | ssm __LC_SVC_NEW_PSW # reenable interrupts |
| 612 | brasl %r14,schedule # call scheduler | 612 | brasl %r14,schedule # call scheduler |
| 613 | ssm __LC_PGM_NEW_PSW # disable I/O and ext. interrupts | 613 | ssm __LC_PGM_NEW_PSW # disable I/O and ext. interrupts |
| 614 | TRACE_IRQS_OFF | 614 | TRACE_IRQS_OFF |
| 615 | j io_return | 615 | j .Lio_return |
| 616 | 616 | ||
| 617 | # | 617 | # |
| 618 | # _TIF_SIGPENDING or is set, call do_signal | 618 | # _TIF_SIGPENDING or is set, call do_signal |
| 619 | # | 619 | # |
| 620 | io_sigpending: | 620 | .Lio_sigpending: |
| 621 | # TRACE_IRQS_ON already done at io_return | 621 | # TRACE_IRQS_ON already done at .Lio_return |
| 622 | ssm __LC_SVC_NEW_PSW # reenable interrupts | 622 | ssm __LC_SVC_NEW_PSW # reenable interrupts |
| 623 | lgr %r2,%r11 # pass pointer to pt_regs | 623 | lgr %r2,%r11 # pass pointer to pt_regs |
| 624 | brasl %r14,do_signal | 624 | brasl %r14,do_signal |
| 625 | ssm __LC_PGM_NEW_PSW # disable I/O and ext. interrupts | 625 | ssm __LC_PGM_NEW_PSW # disable I/O and ext. interrupts |
| 626 | TRACE_IRQS_OFF | 626 | TRACE_IRQS_OFF |
| 627 | j io_return | 627 | j .Lio_return |
| 628 | 628 | ||
| 629 | # | 629 | # |
| 630 | # _TIF_NOTIFY_RESUME or is set, call do_notify_resume | 630 | # _TIF_NOTIFY_RESUME or is set, call do_notify_resume |
| 631 | # | 631 | # |
| 632 | io_notify_resume: | 632 | .Lio_notify_resume: |
| 633 | # TRACE_IRQS_ON already done at io_return | 633 | # TRACE_IRQS_ON already done at .Lio_return |
| 634 | ssm __LC_SVC_NEW_PSW # reenable interrupts | 634 | ssm __LC_SVC_NEW_PSW # reenable interrupts |
| 635 | lgr %r2,%r11 # pass pointer to pt_regs | 635 | lgr %r2,%r11 # pass pointer to pt_regs |
| 636 | brasl %r14,do_notify_resume | 636 | brasl %r14,do_notify_resume |
| 637 | ssm __LC_PGM_NEW_PSW # disable I/O and ext. interrupts | 637 | ssm __LC_PGM_NEW_PSW # disable I/O and ext. interrupts |
| 638 | TRACE_IRQS_OFF | 638 | TRACE_IRQS_OFF |
| 639 | j io_return | 639 | j .Lio_return |
| 640 | 640 | ||
| 641 | /* | 641 | /* |
| 642 | * External interrupt handler routine | 642 | * External interrupt handler routine |
| @@ -652,10 +652,10 @@ ENTRY(ext_int_handler) | |||
| 652 | HANDLE_SIE_INTERCEPT %r14,3 | 652 | HANDLE_SIE_INTERCEPT %r14,3 |
| 653 | SWITCH_ASYNC __LC_SAVE_AREA_ASYNC,__LC_ASYNC_STACK,STACK_SHIFT | 653 | SWITCH_ASYNC __LC_SAVE_AREA_ASYNC,__LC_ASYNC_STACK,STACK_SHIFT |
| 654 | tmhh %r8,0x0001 # interrupting from user ? | 654 | tmhh %r8,0x0001 # interrupting from user ? |
| 655 | jz ext_skip | 655 | jz .Lext_skip |
| 656 | UPDATE_VTIME %r14,__LC_ASYNC_ENTER_TIMER | 656 | UPDATE_VTIME %r14,__LC_ASYNC_ENTER_TIMER |
| 657 | LAST_BREAK %r14 | 657 | LAST_BREAK %r14 |
| 658 | ext_skip: | 658 | .Lext_skip: |
| 659 | stmg %r0,%r7,__PT_R0(%r11) | 659 | stmg %r0,%r7,__PT_R0(%r11) |
| 660 | mvc __PT_R8(64,%r11),__LC_SAVE_AREA_ASYNC | 660 | mvc __PT_R8(64,%r11),__LC_SAVE_AREA_ASYNC |
| 661 | stmg %r8,%r9,__PT_PSW(%r11) | 661 | stmg %r8,%r9,__PT_PSW(%r11) |
| @@ -669,23 +669,23 @@ ext_skip: | |||
| 669 | lgr %r2,%r11 # pass pointer to pt_regs | 669 | lgr %r2,%r11 # pass pointer to pt_regs |
| 670 | lghi %r3,EXT_INTERRUPT | 670 | lghi %r3,EXT_INTERRUPT |
| 671 | brasl %r14,do_IRQ | 671 | brasl %r14,do_IRQ |
| 672 | j io_return | 672 | j .Lio_return |
| 673 | 673 | ||
| 674 | /* | 674 | /* |
| 675 | * Load idle PSW. The second "half" of this function is in cleanup_idle. | 675 | * Load idle PSW. The second "half" of this function is in .Lcleanup_idle. |
| 676 | */ | 676 | */ |
| 677 | ENTRY(psw_idle) | 677 | ENTRY(psw_idle) |
| 678 | stg %r3,__SF_EMPTY(%r15) | 678 | stg %r3,__SF_EMPTY(%r15) |
| 679 | larl %r1,psw_idle_lpsw+4 | 679 | larl %r1,.Lpsw_idle_lpsw+4 |
| 680 | stg %r1,__SF_EMPTY+8(%r15) | 680 | stg %r1,__SF_EMPTY+8(%r15) |
| 681 | STCK __CLOCK_IDLE_ENTER(%r2) | 681 | STCK __CLOCK_IDLE_ENTER(%r2) |
| 682 | stpt __TIMER_IDLE_ENTER(%r2) | 682 | stpt __TIMER_IDLE_ENTER(%r2) |
| 683 | psw_idle_lpsw: | 683 | .Lpsw_idle_lpsw: |
| 684 | lpswe __SF_EMPTY(%r15) | 684 | lpswe __SF_EMPTY(%r15) |
| 685 | br %r14 | 685 | br %r14 |
| 686 | psw_idle_end: | 686 | .Lpsw_idle_end: |
| 687 | 687 | ||
| 688 | __critical_end: | 688 | .L__critical_end: |
| 689 | 689 | ||
| 690 | /* | 690 | /* |
| 691 | * Machine check handler routines | 691 | * Machine check handler routines |
| @@ -701,7 +701,7 @@ ENTRY(mcck_int_handler) | |||
| 701 | lmg %r8,%r9,__LC_MCK_OLD_PSW | 701 | lmg %r8,%r9,__LC_MCK_OLD_PSW |
| 702 | HANDLE_SIE_INTERCEPT %r14,4 | 702 | HANDLE_SIE_INTERCEPT %r14,4 |
| 703 | tm __LC_MCCK_CODE,0x80 # system damage? | 703 | tm __LC_MCCK_CODE,0x80 # system damage? |
| 704 | jo mcck_panic # yes -> rest of mcck code invalid | 704 | jo .Lmcck_panic # yes -> rest of mcck code invalid |
| 705 | lghi %r14,__LC_CPU_TIMER_SAVE_AREA | 705 | lghi %r14,__LC_CPU_TIMER_SAVE_AREA |
| 706 | mvc __LC_MCCK_ENTER_TIMER(8),0(%r14) | 706 | mvc __LC_MCCK_ENTER_TIMER(8),0(%r14) |
| 707 | tm __LC_MCCK_CODE+5,0x02 # stored cpu timer value valid? | 707 | tm __LC_MCCK_CODE+5,0x02 # stored cpu timer value valid? |
| @@ -719,13 +719,13 @@ ENTRY(mcck_int_handler) | |||
| 719 | 2: spt 0(%r14) | 719 | 2: spt 0(%r14) |
| 720 | mvc __LC_MCCK_ENTER_TIMER(8),0(%r14) | 720 | mvc __LC_MCCK_ENTER_TIMER(8),0(%r14) |
| 721 | 3: tm __LC_MCCK_CODE+2,0x09 # mwp + ia of old psw valid? | 721 | 3: tm __LC_MCCK_CODE+2,0x09 # mwp + ia of old psw valid? |
| 722 | jno mcck_panic # no -> skip cleanup critical | 722 | jno .Lmcck_panic # no -> skip cleanup critical |
| 723 | SWITCH_ASYNC __LC_GPREGS_SAVE_AREA+64,__LC_PANIC_STACK,PAGE_SHIFT | 723 | SWITCH_ASYNC __LC_GPREGS_SAVE_AREA+64,__LC_PANIC_STACK,PAGE_SHIFT |
| 724 | tm %r8,0x0001 # interrupting from user ? | 724 | tm %r8,0x0001 # interrupting from user ? |
| 725 | jz mcck_skip | 725 | jz .Lmcck_skip |
| 726 | UPDATE_VTIME %r14,__LC_MCCK_ENTER_TIMER | 726 | UPDATE_VTIME %r14,__LC_MCCK_ENTER_TIMER |
| 727 | LAST_BREAK %r14 | 727 | LAST_BREAK %r14 |
| 728 | mcck_skip: | 728 | .Lmcck_skip: |
| 729 | lghi %r14,__LC_GPREGS_SAVE_AREA+64 | 729 | lghi %r14,__LC_GPREGS_SAVE_AREA+64 |
| 730 | stmg %r0,%r7,__PT_R0(%r11) | 730 | stmg %r0,%r7,__PT_R0(%r11) |
| 731 | mvc __PT_R8(64,%r11),0(%r14) | 731 | mvc __PT_R8(64,%r11),0(%r14) |
| @@ -735,7 +735,7 @@ mcck_skip: | |||
| 735 | lgr %r2,%r11 # pass pointer to pt_regs | 735 | lgr %r2,%r11 # pass pointer to pt_regs |
| 736 | brasl %r14,s390_do_machine_check | 736 | brasl %r14,s390_do_machine_check |
| 737 | tm __PT_PSW+1(%r11),0x01 # returning to user ? | 737 | tm __PT_PSW+1(%r11),0x01 # returning to user ? |
| 738 | jno mcck_return | 738 | jno .Lmcck_return |
| 739 | lg %r1,__LC_KERNEL_STACK # switch to kernel stack | 739 | lg %r1,__LC_KERNEL_STACK # switch to kernel stack |
| 740 | mvc STACK_FRAME_OVERHEAD(__PT_SIZE,%r1),0(%r11) | 740 | mvc STACK_FRAME_OVERHEAD(__PT_SIZE,%r1),0(%r11) |
| 741 | xc __SF_BACKCHAIN(8,%r1),__SF_BACKCHAIN(%r1) | 741 | xc __SF_BACKCHAIN(8,%r1),__SF_BACKCHAIN(%r1) |
| @@ -743,11 +743,11 @@ mcck_skip: | |||
| 743 | lgr %r15,%r1 | 743 | lgr %r15,%r1 |
| 744 | ssm __LC_PGM_NEW_PSW # turn dat on, keep irqs off | 744 | ssm __LC_PGM_NEW_PSW # turn dat on, keep irqs off |
| 745 | tm __LC_CPU_FLAGS+7,_CIF_MCCK_PENDING | 745 | tm __LC_CPU_FLAGS+7,_CIF_MCCK_PENDING |
| 746 | jno mcck_return | 746 | jno .Lmcck_return |
| 747 | TRACE_IRQS_OFF | 747 | TRACE_IRQS_OFF |
| 748 | brasl %r14,s390_handle_mcck | 748 | brasl %r14,s390_handle_mcck |
| 749 | TRACE_IRQS_ON | 749 | TRACE_IRQS_ON |
| 750 | mcck_return: | 750 | .Lmcck_return: |
| 751 | lg %r14,__LC_VDSO_PER_CPU | 751 | lg %r14,__LC_VDSO_PER_CPU |
| 752 | lmg %r0,%r10,__PT_R0(%r11) | 752 | lmg %r0,%r10,__PT_R0(%r11) |
| 753 | mvc __LC_RETURN_MCCK_PSW(16),__PT_PSW(%r11) # move return PSW | 753 | mvc __LC_RETURN_MCCK_PSW(16),__PT_PSW(%r11) # move return PSW |
| @@ -758,14 +758,14 @@ mcck_return: | |||
| 758 | 0: lmg %r11,%r15,__PT_R11(%r11) | 758 | 0: lmg %r11,%r15,__PT_R11(%r11) |
| 759 | lpswe __LC_RETURN_MCCK_PSW | 759 | lpswe __LC_RETURN_MCCK_PSW |
| 760 | 760 | ||
| 761 | mcck_panic: | 761 | .Lmcck_panic: |
| 762 | lg %r14,__LC_PANIC_STACK | 762 | lg %r14,__LC_PANIC_STACK |
| 763 | slgr %r14,%r15 | 763 | slgr %r14,%r15 |
| 764 | srag %r14,%r14,PAGE_SHIFT | 764 | srag %r14,%r14,PAGE_SHIFT |
| 765 | jz 0f | 765 | jz 0f |
| 766 | lg %r15,__LC_PANIC_STACK | 766 | lg %r15,__LC_PANIC_STACK |
| 767 | 0: aghi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE) | 767 | 0: aghi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE) |
| 768 | j mcck_skip | 768 | j .Lmcck_skip |
| 769 | 769 | ||
| 770 | # | 770 | # |
| 771 | # PSW restart interrupt handler | 771 | # PSW restart interrupt handler |
| @@ -815,69 +815,69 @@ stack_overflow: | |||
| 815 | #endif | 815 | #endif |
| 816 | 816 | ||
| 817 | .align 8 | 817 | .align 8 |
| 818 | cleanup_table: | 818 | .Lcleanup_table: |
| 819 | .quad system_call | 819 | .quad system_call |
| 820 | .quad sysc_do_svc | 820 | .quad .Lsysc_do_svc |
| 821 | .quad sysc_tif | 821 | .quad .Lsysc_tif |
| 822 | .quad sysc_restore | 822 | .quad .Lsysc_restore |
| 823 | .quad sysc_done | 823 | .quad .Lsysc_done |
| 824 | .quad io_tif | 824 | .quad .Lio_tif |
| 825 | .quad io_restore | 825 | .quad .Lio_restore |
| 826 | .quad io_done | 826 | .quad .Lio_done |
| 827 | .quad psw_idle | 827 | .quad psw_idle |
| 828 | .quad psw_idle_end | 828 | .quad .Lpsw_idle_end |
| 829 | 829 | ||
| 830 | cleanup_critical: | 830 | cleanup_critical: |
| 831 | clg %r9,BASED(cleanup_table) # system_call | 831 | clg %r9,BASED(.Lcleanup_table) # system_call |
| 832 | jl 0f | 832 | jl 0f |
| 833 | clg %r9,BASED(cleanup_table+8) # sysc_do_svc | 833 | clg %r9,BASED(.Lcleanup_table+8) # .Lsysc_do_svc |
| 834 | jl cleanup_system_call | 834 | jl .Lcleanup_system_call |
| 835 | clg %r9,BASED(cleanup_table+16) # sysc_tif | 835 | clg %r9,BASED(.Lcleanup_table+16) # .Lsysc_tif |
| 836 | jl 0f | 836 | jl 0f |
| 837 | clg %r9,BASED(cleanup_table+24) # sysc_restore | 837 | clg %r9,BASED(.Lcleanup_table+24) # .Lsysc_restore |
| 838 | jl cleanup_sysc_tif | 838 | jl .Lcleanup_sysc_tif |
| 839 | clg %r9,BASED(cleanup_table+32) # sysc_done | 839 | clg %r9,BASED(.Lcleanup_table+32) # .Lsysc_done |
| 840 | jl cleanup_sysc_restore | 840 | jl .Lcleanup_sysc_restore |
| 841 | clg %r9,BASED(cleanup_table+40) # io_tif | 841 | clg %r9,BASED(.Lcleanup_table+40) # .Lio_tif |
| 842 | jl 0f | 842 | jl 0f |
| 843 | clg %r9,BASED(cleanup_table+48) # io_restore | 843 | clg %r9,BASED(.Lcleanup_table+48) # .Lio_restore |
| 844 | jl cleanup_io_tif | 844 | jl .Lcleanup_io_tif |
| 845 | clg %r9,BASED(cleanup_table+56) # io_done | 845 | clg %r9,BASED(.Lcleanup_table+56) # .Lio_done |
| 846 | jl cleanup_io_restore | 846 | jl .Lcleanup_io_restore |
| 847 | clg %r9,BASED(cleanup_table+64) # psw_idle | 847 | clg %r9,BASED(.Lcleanup_table+64) # psw_idle |
| 848 | jl 0f | 848 | jl 0f |
| 849 | clg %r9,BASED(cleanup_table+72) # psw_idle_end | 849 | clg %r9,BASED(.Lcleanup_table+72) # .Lpsw_idle_end |
| 850 | jl cleanup_idle | 850 | jl .Lcleanup_idle |
| 851 | 0: br %r14 | 851 | 0: br %r14 |
| 852 | 852 | ||
| 853 | 853 | ||
| 854 | cleanup_system_call: | 854 | .Lcleanup_system_call: |
| 855 | # check if stpt has been executed | 855 | # check if stpt has been executed |
| 856 | clg %r9,BASED(cleanup_system_call_insn) | 856 | clg %r9,BASED(.Lcleanup_system_call_insn) |
| 857 | jh 0f | 857 | jh 0f |
| 858 | mvc __LC_SYNC_ENTER_TIMER(8),__LC_ASYNC_ENTER_TIMER | 858 | mvc __LC_SYNC_ENTER_TIMER(8),__LC_ASYNC_ENTER_TIMER |
| 859 | cghi %r11,__LC_SAVE_AREA_ASYNC | 859 | cghi %r11,__LC_SAVE_AREA_ASYNC |
| 860 | je 0f | 860 | je 0f |
| 861 | mvc __LC_SYNC_ENTER_TIMER(8),__LC_MCCK_ENTER_TIMER | 861 | mvc __LC_SYNC_ENTER_TIMER(8),__LC_MCCK_ENTER_TIMER |
| 862 | 0: # check if stmg has been executed | 862 | 0: # check if stmg has been executed |
| 863 | clg %r9,BASED(cleanup_system_call_insn+8) | 863 | clg %r9,BASED(.Lcleanup_system_call_insn+8) |
| 864 | jh 0f | 864 | jh 0f |
| 865 | mvc __LC_SAVE_AREA_SYNC(64),0(%r11) | 865 | mvc __LC_SAVE_AREA_SYNC(64),0(%r11) |
| 866 | 0: # check if base register setup + TIF bit load has been done | 866 | 0: # check if base register setup + TIF bit load has been done |
| 867 | clg %r9,BASED(cleanup_system_call_insn+16) | 867 | clg %r9,BASED(.Lcleanup_system_call_insn+16) |
| 868 | jhe 0f | 868 | jhe 0f |
| 869 | # set up saved registers r10 and r12 | 869 | # set up saved registers r10 and r12 |
| 870 | stg %r10,16(%r11) # r10 last break | 870 | stg %r10,16(%r11) # r10 last break |
| 871 | stg %r12,32(%r11) # r12 thread-info pointer | 871 | stg %r12,32(%r11) # r12 thread-info pointer |
| 872 | 0: # check if the user time update has been done | 872 | 0: # check if the user time update has been done |
| 873 | clg %r9,BASED(cleanup_system_call_insn+24) | 873 | clg %r9,BASED(.Lcleanup_system_call_insn+24) |
| 874 | jh 0f | 874 | jh 0f |
| 875 | lg %r15,__LC_EXIT_TIMER | 875 | lg %r15,__LC_EXIT_TIMER |
| 876 | slg %r15,__LC_SYNC_ENTER_TIMER | 876 | slg %r15,__LC_SYNC_ENTER_TIMER |
| 877 | alg %r15,__LC_USER_TIMER | 877 | alg %r15,__LC_USER_TIMER |
| 878 | stg %r15,__LC_USER_TIMER | 878 | stg %r15,__LC_USER_TIMER |
| 879 | 0: # check if the system time update has been done | 879 | 0: # check if the system time update has been done |
| 880 | clg %r9,BASED(cleanup_system_call_insn+32) | 880 | clg %r9,BASED(.Lcleanup_system_call_insn+32) |
| 881 | jh 0f | 881 | jh 0f |
| 882 | lg %r15,__LC_LAST_UPDATE_TIMER | 882 | lg %r15,__LC_LAST_UPDATE_TIMER |
| 883 | slg %r15,__LC_EXIT_TIMER | 883 | slg %r15,__LC_EXIT_TIMER |
| @@ -904,21 +904,21 @@ cleanup_system_call: | |||
| 904 | # setup saved register r15 | 904 | # setup saved register r15 |
| 905 | stg %r15,56(%r11) # r15 stack pointer | 905 | stg %r15,56(%r11) # r15 stack pointer |
| 906 | # set new psw address and exit | 906 | # set new psw address and exit |
| 907 | larl %r9,sysc_do_svc | 907 | larl %r9,.Lsysc_do_svc |
| 908 | br %r14 | 908 | br %r14 |
| 909 | cleanup_system_call_insn: | 909 | .Lcleanup_system_call_insn: |
| 910 | .quad system_call | 910 | .quad system_call |
| 911 | .quad sysc_stmg | 911 | .quad .Lsysc_stmg |
| 912 | .quad sysc_per | 912 | .quad .Lsysc_per |
| 913 | .quad sysc_vtime+18 | 913 | .quad .Lsysc_vtime+18 |
| 914 | .quad sysc_vtime+42 | 914 | .quad .Lsysc_vtime+42 |
| 915 | 915 | ||
| 916 | cleanup_sysc_tif: | 916 | .Lcleanup_sysc_tif: |
| 917 | larl %r9,sysc_tif | 917 | larl %r9,.Lsysc_tif |
| 918 | br %r14 | 918 | br %r14 |
| 919 | 919 | ||
| 920 | cleanup_sysc_restore: | 920 | .Lcleanup_sysc_restore: |
| 921 | clg %r9,BASED(cleanup_sysc_restore_insn) | 921 | clg %r9,BASED(.Lcleanup_sysc_restore_insn) |
| 922 | je 0f | 922 | je 0f |
| 923 | lg %r9,24(%r11) # get saved pointer to pt_regs | 923 | lg %r9,24(%r11) # get saved pointer to pt_regs |
| 924 | mvc __LC_RETURN_PSW(16),__PT_PSW(%r9) | 924 | mvc __LC_RETURN_PSW(16),__PT_PSW(%r9) |
| @@ -926,15 +926,15 @@ cleanup_sysc_restore: | |||
| 926 | lmg %r0,%r7,__PT_R0(%r9) | 926 | lmg %r0,%r7,__PT_R0(%r9) |
| 927 | 0: lmg %r8,%r9,__LC_RETURN_PSW | 927 | 0: lmg %r8,%r9,__LC_RETURN_PSW |
| 928 | br %r14 | 928 | br %r14 |
| 929 | cleanup_sysc_restore_insn: | 929 | .Lcleanup_sysc_restore_insn: |
| 930 | .quad sysc_done - 4 | 930 | .quad .Lsysc_done - 4 |
| 931 | 931 | ||
| 932 | cleanup_io_tif: | 932 | .Lcleanup_io_tif: |
| 933 | larl %r9,io_tif | 933 | larl %r9,.Lio_tif |
| 934 | br %r14 | 934 | br %r14 |
| 935 | 935 | ||
| 936 | cleanup_io_restore: | 936 | .Lcleanup_io_restore: |
| 937 | clg %r9,BASED(cleanup_io_restore_insn) | 937 | clg %r9,BASED(.Lcleanup_io_restore_insn) |
| 938 | je 0f | 938 | je 0f |
| 939 | lg %r9,24(%r11) # get saved r11 pointer to pt_regs | 939 | lg %r9,24(%r11) # get saved r11 pointer to pt_regs |
| 940 | mvc __LC_RETURN_PSW(16),__PT_PSW(%r9) | 940 | mvc __LC_RETURN_PSW(16),__PT_PSW(%r9) |
| @@ -942,10 +942,10 @@ cleanup_io_restore: | |||
| 942 | lmg %r0,%r7,__PT_R0(%r9) | 942 | lmg %r0,%r7,__PT_R0(%r9) |
| 943 | 0: lmg %r8,%r9,__LC_RETURN_PSW | 943 | 0: lmg %r8,%r9,__LC_RETURN_PSW |
| 944 | br %r14 | 944 | br %r14 |
| 945 | cleanup_io_restore_insn: | 945 | .Lcleanup_io_restore_insn: |
| 946 | .quad io_done - 4 | 946 | .quad .Lio_done - 4 |
| 947 | 947 | ||
| 948 | cleanup_idle: | 948 | .Lcleanup_idle: |
| 949 | # copy interrupt clock & cpu timer | 949 | # copy interrupt clock & cpu timer |
| 950 | mvc __CLOCK_IDLE_EXIT(8,%r2),__LC_INT_CLOCK | 950 | mvc __CLOCK_IDLE_EXIT(8,%r2),__LC_INT_CLOCK |
| 951 | mvc __TIMER_IDLE_EXIT(8,%r2),__LC_ASYNC_ENTER_TIMER | 951 | mvc __TIMER_IDLE_EXIT(8,%r2),__LC_ASYNC_ENTER_TIMER |
| @@ -954,7 +954,7 @@ cleanup_idle: | |||
| 954 | mvc __CLOCK_IDLE_EXIT(8,%r2),__LC_MCCK_CLOCK | 954 | mvc __CLOCK_IDLE_EXIT(8,%r2),__LC_MCCK_CLOCK |
| 955 | mvc __TIMER_IDLE_EXIT(8,%r2),__LC_MCCK_ENTER_TIMER | 955 | mvc __TIMER_IDLE_EXIT(8,%r2),__LC_MCCK_ENTER_TIMER |
| 956 | 0: # check if stck & stpt have been executed | 956 | 0: # check if stck & stpt have been executed |
| 957 | clg %r9,BASED(cleanup_idle_insn) | 957 | clg %r9,BASED(.Lcleanup_idle_insn) |
| 958 | jhe 1f | 958 | jhe 1f |
| 959 | mvc __CLOCK_IDLE_ENTER(8,%r2),__CLOCK_IDLE_EXIT(%r2) | 959 | mvc __CLOCK_IDLE_ENTER(8,%r2),__CLOCK_IDLE_EXIT(%r2) |
| 960 | mvc __TIMER_IDLE_ENTER(8,%r2),__TIMER_IDLE_EXIT(%r2) | 960 | mvc __TIMER_IDLE_ENTER(8,%r2),__TIMER_IDLE_EXIT(%r2) |
| @@ -973,17 +973,17 @@ cleanup_idle: | |||
| 973 | nihh %r8,0xfcfd # clear irq & wait state bits | 973 | nihh %r8,0xfcfd # clear irq & wait state bits |
| 974 | lg %r9,48(%r11) # return from psw_idle | 974 | lg %r9,48(%r11) # return from psw_idle |
| 975 | br %r14 | 975 | br %r14 |
| 976 | cleanup_idle_insn: | 976 | .Lcleanup_idle_insn: |
| 977 | .quad psw_idle_lpsw | 977 | .quad .Lpsw_idle_lpsw |
| 978 | 978 | ||
| 979 | /* | 979 | /* |
| 980 | * Integer constants | 980 | * Integer constants |
| 981 | */ | 981 | */ |
| 982 | .align 8 | 982 | .align 8 |
| 983 | .Lcritical_start: | 983 | .Lcritical_start: |
| 984 | .quad __critical_start | 984 | .quad .L__critical_start |
| 985 | .Lcritical_length: | 985 | .Lcritical_length: |
| 986 | .quad __critical_end - __critical_start | 986 | .quad .L__critical_end - .L__critical_start |
| 987 | 987 | ||
| 988 | 988 | ||
| 989 | #if IS_ENABLED(CONFIG_KVM) | 989 | #if IS_ENABLED(CONFIG_KVM) |
| @@ -1000,25 +1000,25 @@ ENTRY(sie64a) | |||
| 1000 | lmg %r0,%r13,0(%r3) # load guest gprs 0-13 | 1000 | lmg %r0,%r13,0(%r3) # load guest gprs 0-13 |
| 1001 | lg %r14,__LC_GMAP # get gmap pointer | 1001 | lg %r14,__LC_GMAP # get gmap pointer |
| 1002 | ltgr %r14,%r14 | 1002 | ltgr %r14,%r14 |
| 1003 | jz sie_gmap | 1003 | jz .Lsie_gmap |
| 1004 | lctlg %c1,%c1,__GMAP_ASCE(%r14) # load primary asce | 1004 | lctlg %c1,%c1,__GMAP_ASCE(%r14) # load primary asce |
| 1005 | sie_gmap: | 1005 | .Lsie_gmap: |
| 1006 | lg %r14,__SF_EMPTY(%r15) # get control block pointer | 1006 | lg %r14,__SF_EMPTY(%r15) # get control block pointer |
| 1007 | oi __SIE_PROG0C+3(%r14),1 # we are going into SIE now | 1007 | oi __SIE_PROG0C+3(%r14),1 # we are going into SIE now |
| 1008 | tm __SIE_PROG20+3(%r14),1 # last exit... | 1008 | tm __SIE_PROG20+3(%r14),1 # last exit... |
| 1009 | jnz sie_done | 1009 | jnz .Lsie_done |
| 1010 | LPP __SF_EMPTY(%r15) # set guest id | 1010 | LPP __SF_EMPTY(%r15) # set guest id |
| 1011 | sie 0(%r14) | 1011 | sie 0(%r14) |
| 1012 | sie_done: | 1012 | .Lsie_done: |
| 1013 | LPP __SF_EMPTY+16(%r15) # set host id | 1013 | LPP __SF_EMPTY+16(%r15) # set host id |
| 1014 | ni __SIE_PROG0C+3(%r14),0xfe # no longer in SIE | 1014 | ni __SIE_PROG0C+3(%r14),0xfe # no longer in SIE |
| 1015 | lctlg %c1,%c1,__LC_USER_ASCE # load primary asce | 1015 | lctlg %c1,%c1,__LC_USER_ASCE # load primary asce |
| 1016 | # some program checks are suppressing. C code (e.g. do_protection_exception) | 1016 | # some program checks are suppressing. C code (e.g. do_protection_exception) |
| 1017 | # will rewind the PSW by the ILC, which is 4 bytes in case of SIE. Other | 1017 | # will rewind the PSW by the ILC, which is 4 bytes in case of SIE. Other |
| 1018 | # instructions between sie64a and sie_done should not cause program | 1018 | # instructions between sie64a and .Lsie_done should not cause program |
| 1019 | # interrupts. So lets use a nop (47 00 00 00) as a landing pad. | 1019 | # interrupts. So lets use a nop (47 00 00 00) as a landing pad. |
| 1020 | # See also HANDLE_SIE_INTERCEPT | 1020 | # See also HANDLE_SIE_INTERCEPT |
| 1021 | rewind_pad: | 1021 | .Lrewind_pad: |
| 1022 | nop 0 | 1022 | nop 0 |
| 1023 | .globl sie_exit | 1023 | .globl sie_exit |
| 1024 | sie_exit: | 1024 | sie_exit: |
| @@ -1027,19 +1027,19 @@ sie_exit: | |||
| 1027 | lmg %r6,%r14,__SF_GPRS(%r15) # restore kernel registers | 1027 | lmg %r6,%r14,__SF_GPRS(%r15) # restore kernel registers |
| 1028 | lg %r2,__SF_EMPTY+24(%r15) # return exit reason code | 1028 | lg %r2,__SF_EMPTY+24(%r15) # return exit reason code |
| 1029 | br %r14 | 1029 | br %r14 |
| 1030 | sie_fault: | 1030 | .Lsie_fault: |
| 1031 | lghi %r14,-EFAULT | 1031 | lghi %r14,-EFAULT |
| 1032 | stg %r14,__SF_EMPTY+24(%r15) # set exit reason code | 1032 | stg %r14,__SF_EMPTY+24(%r15) # set exit reason code |
| 1033 | j sie_exit | 1033 | j sie_exit |
| 1034 | 1034 | ||
| 1035 | .align 8 | 1035 | .align 8 |
| 1036 | .Lsie_critical: | 1036 | .Lsie_critical: |
| 1037 | .quad sie_gmap | 1037 | .quad .Lsie_gmap |
| 1038 | .Lsie_critical_length: | 1038 | .Lsie_critical_length: |
| 1039 | .quad sie_done - sie_gmap | 1039 | .quad .Lsie_done - .Lsie_gmap |
| 1040 | 1040 | ||
| 1041 | EX_TABLE(rewind_pad,sie_fault) | 1041 | EX_TABLE(.Lrewind_pad,.Lsie_fault) |
| 1042 | EX_TABLE(sie_exit,sie_fault) | 1042 | EX_TABLE(sie_exit,.Lsie_fault) |
| 1043 | #endif | 1043 | #endif |
| 1044 | 1044 | ||
| 1045 | .section .rodata, "a" | 1045 | .section .rodata, "a" |
diff --git a/arch/s390/kernel/ftrace.c b/arch/s390/kernel/ftrace.c index ca1cabb3a96c..b86bb8823f15 100644 --- a/arch/s390/kernel/ftrace.c +++ b/arch/s390/kernel/ftrace.c | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | * Martin Schwidefsky <schwidefsky@de.ibm.com> | 7 | * Martin Schwidefsky <schwidefsky@de.ibm.com> |
| 8 | */ | 8 | */ |
| 9 | 9 | ||
| 10 | #include <linux/moduleloader.h> | ||
| 10 | #include <linux/hardirq.h> | 11 | #include <linux/hardirq.h> |
| 11 | #include <linux/uaccess.h> | 12 | #include <linux/uaccess.h> |
| 12 | #include <linux/ftrace.h> | 13 | #include <linux/ftrace.h> |
| @@ -15,60 +16,39 @@ | |||
| 15 | #include <linux/kprobes.h> | 16 | #include <linux/kprobes.h> |
| 16 | #include <trace/syscall.h> | 17 | #include <trace/syscall.h> |
| 17 | #include <asm/asm-offsets.h> | 18 | #include <asm/asm-offsets.h> |
| 19 | #include <asm/cacheflush.h> | ||
| 18 | #include "entry.h" | 20 | #include "entry.h" |
| 19 | 21 | ||
| 20 | void mcount_replace_code(void); | ||
| 21 | void ftrace_disable_code(void); | ||
| 22 | void ftrace_enable_insn(void); | ||
| 23 | |||
| 24 | /* | 22 | /* |
| 25 | * The mcount code looks like this: | 23 | * The mcount code looks like this: |
| 26 | * stg %r14,8(%r15) # offset 0 | 24 | * stg %r14,8(%r15) # offset 0 |
| 27 | * larl %r1,<&counter> # offset 6 | 25 | * larl %r1,<&counter> # offset 6 |
| 28 | * brasl %r14,_mcount # offset 12 | 26 | * brasl %r14,_mcount # offset 12 |
| 29 | * lg %r14,8(%r15) # offset 18 | 27 | * lg %r14,8(%r15) # offset 18 |
| 30 | * Total length is 24 bytes. The complete mcount block initially gets replaced | 28 | * Total length is 24 bytes. Only the first instruction will be patched |
| 31 | * by ftrace_make_nop. Subsequent calls to ftrace_make_call / ftrace_make_nop | 29 | * by ftrace_make_call / ftrace_make_nop. |
| 32 | * only patch the jg/lg instruction within the block. | ||
| 33 | * Note: we do not patch the first instruction to an unconditional branch, | ||
| 34 | * since that would break kprobes/jprobes. It is easier to leave the larl | ||
| 35 | * instruction in and only modify the second instruction. | ||
| 36 | * The enabled ftrace code block looks like this: | 30 | * The enabled ftrace code block looks like this: |
| 37 | * larl %r0,.+24 # offset 0 | 31 | * > brasl %r0,ftrace_caller # offset 0 |
| 38 | * > lg %r1,__LC_FTRACE_FUNC # offset 6 | 32 | * larl %r1,<&counter> # offset 6 |
| 39 | * br %r1 # offset 12 | 33 | * brasl %r14,_mcount # offset 12 |
| 40 | * brcl 0,0 # offset 14 | 34 | * lg %r14,8(%r15) # offset 18 |
| 41 | * brc 0,0 # offset 20 | ||
| 42 | * The ftrace function gets called with a non-standard C function call ABI | 35 | * The ftrace function gets called with a non-standard C function call ABI |
| 43 | * where r0 contains the return address. It is also expected that the called | 36 | * where r0 contains the return address. It is also expected that the called |
| 44 | * function only clobbers r0 and r1, but restores r2-r15. | 37 | * function only clobbers r0 and r1, but restores r2-r15. |
| 38 | * For module code we can't directly jump to ftrace caller, but need a | ||
| 39 | * trampoline (ftrace_plt), which clobbers also r1. | ||
| 45 | * The return point of the ftrace function has offset 24, so execution | 40 | * The return point of the ftrace function has offset 24, so execution |
| 46 | * continues behind the mcount block. | 41 | * continues behind the mcount block. |
| 47 | * larl %r0,.+24 # offset 0 | 42 | * The disabled ftrace code block looks like this: |
| 48 | * > jg .+18 # offset 6 | 43 | * > jg .+24 # offset 0 |
| 49 | * br %r1 # offset 12 | 44 | * larl %r1,<&counter> # offset 6 |
| 50 | * brcl 0,0 # offset 14 | 45 | * brasl %r14,_mcount # offset 12 |
| 51 | * brc 0,0 # offset 20 | 46 | * lg %r14,8(%r15) # offset 18 |
| 52 | * The jg instruction branches to offset 24 to skip as many instructions | 47 | * The jg instruction branches to offset 24 to skip as many instructions |
| 53 | * as possible. | 48 | * as possible. |
| 54 | */ | 49 | */ |
| 55 | asm( | 50 | |
| 56 | " .align 4\n" | 51 | unsigned long ftrace_plt; |
| 57 | "mcount_replace_code:\n" | ||
| 58 | " larl %r0,0f\n" | ||
| 59 | "ftrace_disable_code:\n" | ||
| 60 | " jg 0f\n" | ||
| 61 | " br %r1\n" | ||
| 62 | " brcl 0,0\n" | ||
| 63 | " brc 0,0\n" | ||
| 64 | "0:\n" | ||
| 65 | " .align 4\n" | ||
| 66 | "ftrace_enable_insn:\n" | ||
| 67 | " lg %r1,"__stringify(__LC_FTRACE_FUNC)"\n"); | ||
| 68 | |||
| 69 | #define MCOUNT_BLOCK_SIZE 24 | ||
| 70 | #define MCOUNT_INSN_OFFSET 6 | ||
| 71 | #define FTRACE_INSN_SIZE 6 | ||
| 72 | 52 | ||
| 73 | int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr, | 53 | int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr, |
| 74 | unsigned long addr) | 54 | unsigned long addr) |
| @@ -79,24 +59,62 @@ int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr, | |||
| 79 | int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec, | 59 | int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec, |
| 80 | unsigned long addr) | 60 | unsigned long addr) |
| 81 | { | 61 | { |
| 82 | /* Initial replacement of the whole mcount block */ | 62 | struct ftrace_insn insn; |
| 83 | if (addr == MCOUNT_ADDR) { | 63 | unsigned short op; |
| 84 | if (probe_kernel_write((void *) rec->ip - MCOUNT_INSN_OFFSET, | 64 | void *from, *to; |
| 85 | mcount_replace_code, | 65 | size_t size; |
| 86 | MCOUNT_BLOCK_SIZE)) | 66 | |
| 87 | return -EPERM; | 67 | ftrace_generate_nop_insn(&insn); |
| 88 | return 0; | 68 | size = sizeof(insn); |
| 69 | from = &insn; | ||
| 70 | to = (void *) rec->ip; | ||
| 71 | if (probe_kernel_read(&op, (void *) rec->ip, sizeof(op))) | ||
| 72 | return -EFAULT; | ||
| 73 | /* | ||
| 74 | * If we find a breakpoint instruction, a kprobe has been placed | ||
| 75 | * at the beginning of the function. We write the constant | ||
| 76 | * KPROBE_ON_FTRACE_NOP into the remaining four bytes of the original | ||
| 77 | * instruction so that the kprobes handler can execute a nop, if it | ||
| 78 | * reaches this breakpoint. | ||
| 79 | */ | ||
| 80 | if (op == BREAKPOINT_INSTRUCTION) { | ||
| 81 | size -= 2; | ||
| 82 | from += 2; | ||
| 83 | to += 2; | ||
| 84 | insn.disp = KPROBE_ON_FTRACE_NOP; | ||
| 89 | } | 85 | } |
| 90 | if (probe_kernel_write((void *) rec->ip, ftrace_disable_code, | 86 | if (probe_kernel_write(to, from, size)) |
| 91 | MCOUNT_INSN_SIZE)) | ||
| 92 | return -EPERM; | 87 | return -EPERM; |
| 93 | return 0; | 88 | return 0; |
| 94 | } | 89 | } |
| 95 | 90 | ||
| 96 | int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) | 91 | int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) |
| 97 | { | 92 | { |
| 98 | if (probe_kernel_write((void *) rec->ip, ftrace_enable_insn, | 93 | struct ftrace_insn insn; |
| 99 | FTRACE_INSN_SIZE)) | 94 | unsigned short op; |
| 95 | void *from, *to; | ||
| 96 | size_t size; | ||
| 97 | |||
| 98 | ftrace_generate_call_insn(&insn, rec->ip); | ||
| 99 | size = sizeof(insn); | ||
| 100 | from = &insn; | ||
| 101 | to = (void *) rec->ip; | ||
| 102 | if (probe_kernel_read(&op, (void *) rec->ip, sizeof(op))) | ||
| 103 | return -EFAULT; | ||
| 104 | /* | ||
| 105 | * If we find a breakpoint instruction, a kprobe has been placed | ||
| 106 | * at the beginning of the function. We write the constant | ||
| 107 | * KPROBE_ON_FTRACE_CALL into the remaining four bytes of the original | ||
| 108 | * instruction so that the kprobes handler can execute a brasl if it | ||
| 109 | * reaches this breakpoint. | ||
| 110 | */ | ||
| 111 | if (op == BREAKPOINT_INSTRUCTION) { | ||
| 112 | size -= 2; | ||
| 113 | from += 2; | ||
| 114 | to += 2; | ||
| 115 | insn.disp = KPROBE_ON_FTRACE_CALL; | ||
| 116 | } | ||
| 117 | if (probe_kernel_write(to, from, size)) | ||
| 100 | return -EPERM; | 118 | return -EPERM; |
| 101 | return 0; | 119 | return 0; |
| 102 | } | 120 | } |
| @@ -111,13 +129,30 @@ int __init ftrace_dyn_arch_init(void) | |||
| 111 | return 0; | 129 | return 0; |
| 112 | } | 130 | } |
| 113 | 131 | ||
| 132 | static int __init ftrace_plt_init(void) | ||
| 133 | { | ||
| 134 | unsigned int *ip; | ||
| 135 | |||
| 136 | ftrace_plt = (unsigned long) module_alloc(PAGE_SIZE); | ||
| 137 | if (!ftrace_plt) | ||
| 138 | panic("cannot allocate ftrace plt\n"); | ||
| 139 | ip = (unsigned int *) ftrace_plt; | ||
| 140 | ip[0] = 0x0d10e310; /* basr 1,0; lg 1,10(1); br 1 */ | ||
| 141 | ip[1] = 0x100a0004; | ||
| 142 | ip[2] = 0x07f10000; | ||
| 143 | ip[3] = FTRACE_ADDR >> 32; | ||
| 144 | ip[4] = FTRACE_ADDR & 0xffffffff; | ||
| 145 | set_memory_ro(ftrace_plt, 1); | ||
| 146 | return 0; | ||
| 147 | } | ||
| 148 | device_initcall(ftrace_plt_init); | ||
| 149 | |||
| 114 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | 150 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER |
| 115 | /* | 151 | /* |
| 116 | * Hook the return address and push it in the stack of return addresses | 152 | * Hook the return address and push it in the stack of return addresses |
| 117 | * in current thread info. | 153 | * in current thread info. |
| 118 | */ | 154 | */ |
| 119 | unsigned long __kprobes prepare_ftrace_return(unsigned long parent, | 155 | unsigned long prepare_ftrace_return(unsigned long parent, unsigned long ip) |
| 120 | unsigned long ip) | ||
| 121 | { | 156 | { |
| 122 | struct ftrace_graph_ent trace; | 157 | struct ftrace_graph_ent trace; |
| 123 | 158 | ||
| @@ -137,6 +172,7 @@ unsigned long __kprobes prepare_ftrace_return(unsigned long parent, | |||
| 137 | out: | 172 | out: |
| 138 | return parent; | 173 | return parent; |
| 139 | } | 174 | } |
| 175 | NOKPROBE_SYMBOL(prepare_ftrace_return); | ||
| 140 | 176 | ||
| 141 | /* | 177 | /* |
| 142 | * Patch the kernel code at ftrace_graph_caller location. The instruction | 178 | * Patch the kernel code at ftrace_graph_caller location. The instruction |
diff --git a/arch/s390/kernel/idle.c b/arch/s390/kernel/idle.c index 7559f1beab29..7a55c29b0b33 100644 --- a/arch/s390/kernel/idle.c +++ b/arch/s390/kernel/idle.c | |||
| @@ -19,7 +19,7 @@ | |||
| 19 | 19 | ||
| 20 | static DEFINE_PER_CPU(struct s390_idle_data, s390_idle); | 20 | static DEFINE_PER_CPU(struct s390_idle_data, s390_idle); |
| 21 | 21 | ||
| 22 | void __kprobes enabled_wait(void) | 22 | void enabled_wait(void) |
| 23 | { | 23 | { |
| 24 | struct s390_idle_data *idle = this_cpu_ptr(&s390_idle); | 24 | struct s390_idle_data *idle = this_cpu_ptr(&s390_idle); |
| 25 | unsigned long long idle_time; | 25 | unsigned long long idle_time; |
| @@ -35,31 +35,32 @@ void __kprobes enabled_wait(void) | |||
| 35 | /* Call the assembler magic in entry.S */ | 35 | /* Call the assembler magic in entry.S */ |
| 36 | psw_idle(idle, psw_mask); | 36 | psw_idle(idle, psw_mask); |
| 37 | 37 | ||
| 38 | trace_hardirqs_off(); | ||
| 39 | |||
| 38 | /* Account time spent with enabled wait psw loaded as idle time. */ | 40 | /* Account time spent with enabled wait psw loaded as idle time. */ |
| 39 | idle->sequence++; | 41 | write_seqcount_begin(&idle->seqcount); |
| 40 | smp_wmb(); | ||
| 41 | idle_time = idle->clock_idle_exit - idle->clock_idle_enter; | 42 | idle_time = idle->clock_idle_exit - idle->clock_idle_enter; |
| 42 | idle->clock_idle_enter = idle->clock_idle_exit = 0ULL; | 43 | idle->clock_idle_enter = idle->clock_idle_exit = 0ULL; |
| 43 | idle->idle_time += idle_time; | 44 | idle->idle_time += idle_time; |
| 44 | idle->idle_count++; | 45 | idle->idle_count++; |
| 45 | account_idle_time(idle_time); | 46 | account_idle_time(idle_time); |
| 46 | smp_wmb(); | 47 | write_seqcount_end(&idle->seqcount); |
| 47 | idle->sequence++; | ||
| 48 | } | 48 | } |
| 49 | NOKPROBE_SYMBOL(enabled_wait); | ||
| 49 | 50 | ||
| 50 | static ssize_t show_idle_count(struct device *dev, | 51 | static ssize_t show_idle_count(struct device *dev, |
| 51 | struct device_attribute *attr, char *buf) | 52 | struct device_attribute *attr, char *buf) |
| 52 | { | 53 | { |
| 53 | struct s390_idle_data *idle = &per_cpu(s390_idle, dev->id); | 54 | struct s390_idle_data *idle = &per_cpu(s390_idle, dev->id); |
| 54 | unsigned long long idle_count; | 55 | unsigned long long idle_count; |
| 55 | unsigned int sequence; | 56 | unsigned int seq; |
| 56 | 57 | ||
| 57 | do { | 58 | do { |
| 58 | sequence = ACCESS_ONCE(idle->sequence); | 59 | seq = read_seqcount_begin(&idle->seqcount); |
| 59 | idle_count = ACCESS_ONCE(idle->idle_count); | 60 | idle_count = ACCESS_ONCE(idle->idle_count); |
| 60 | if (ACCESS_ONCE(idle->clock_idle_enter)) | 61 | if (ACCESS_ONCE(idle->clock_idle_enter)) |
| 61 | idle_count++; | 62 | idle_count++; |
| 62 | } while ((sequence & 1) || (ACCESS_ONCE(idle->sequence) != sequence)); | 63 | } while (read_seqcount_retry(&idle->seqcount, seq)); |
| 63 | return sprintf(buf, "%llu\n", idle_count); | 64 | return sprintf(buf, "%llu\n", idle_count); |
| 64 | } | 65 | } |
| 65 | DEVICE_ATTR(idle_count, 0444, show_idle_count, NULL); | 66 | DEVICE_ATTR(idle_count, 0444, show_idle_count, NULL); |
| @@ -69,15 +70,15 @@ static ssize_t show_idle_time(struct device *dev, | |||
| 69 | { | 70 | { |
| 70 | struct s390_idle_data *idle = &per_cpu(s390_idle, dev->id); | 71 | struct s390_idle_data *idle = &per_cpu(s390_idle, dev->id); |
| 71 | unsigned long long now, idle_time, idle_enter, idle_exit; | 72 | unsigned long long now, idle_time, idle_enter, idle_exit; |
| 72 | unsigned int sequence; | 73 | unsigned int seq; |
| 73 | 74 | ||
| 74 | do { | 75 | do { |
| 75 | now = get_tod_clock(); | 76 | now = get_tod_clock(); |
| 76 | sequence = ACCESS_ONCE(idle->sequence); | 77 | seq = read_seqcount_begin(&idle->seqcount); |
| 77 | idle_time = ACCESS_ONCE(idle->idle_time); | 78 | idle_time = ACCESS_ONCE(idle->idle_time); |
| 78 | idle_enter = ACCESS_ONCE(idle->clock_idle_enter); | 79 | idle_enter = ACCESS_ONCE(idle->clock_idle_enter); |
| 79 | idle_exit = ACCESS_ONCE(idle->clock_idle_exit); | 80 | idle_exit = ACCESS_ONCE(idle->clock_idle_exit); |
| 80 | } while ((sequence & 1) || (ACCESS_ONCE(idle->sequence) != sequence)); | 81 | } while (read_seqcount_retry(&idle->seqcount, seq)); |
| 81 | idle_time += idle_enter ? ((idle_exit ? : now) - idle_enter) : 0; | 82 | idle_time += idle_enter ? ((idle_exit ? : now) - idle_enter) : 0; |
| 82 | return sprintf(buf, "%llu\n", idle_time >> 12); | 83 | return sprintf(buf, "%llu\n", idle_time >> 12); |
| 83 | } | 84 | } |
| @@ -87,14 +88,14 @@ cputime64_t arch_cpu_idle_time(int cpu) | |||
| 87 | { | 88 | { |
| 88 | struct s390_idle_data *idle = &per_cpu(s390_idle, cpu); | 89 | struct s390_idle_data *idle = &per_cpu(s390_idle, cpu); |
| 89 | unsigned long long now, idle_enter, idle_exit; | 90 | unsigned long long now, idle_enter, idle_exit; |
| 90 | unsigned int sequence; | 91 | unsigned int seq; |
| 91 | 92 | ||
| 92 | do { | 93 | do { |
| 93 | now = get_tod_clock(); | 94 | now = get_tod_clock(); |
| 94 | sequence = ACCESS_ONCE(idle->sequence); | 95 | seq = read_seqcount_begin(&idle->seqcount); |
| 95 | idle_enter = ACCESS_ONCE(idle->clock_idle_enter); | 96 | idle_enter = ACCESS_ONCE(idle->clock_idle_enter); |
| 96 | idle_exit = ACCESS_ONCE(idle->clock_idle_exit); | 97 | idle_exit = ACCESS_ONCE(idle->clock_idle_exit); |
| 97 | } while ((sequence & 1) || (ACCESS_ONCE(idle->sequence) != sequence)); | 98 | } while (read_seqcount_retry(&idle->seqcount, seq)); |
| 98 | return idle_enter ? ((idle_exit ?: now) - idle_enter) : 0; | 99 | return idle_enter ? ((idle_exit ?: now) - idle_enter) : 0; |
| 99 | } | 100 | } |
| 100 | 101 | ||
diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c index 1b8a38ab7861..f238720690f3 100644 --- a/arch/s390/kernel/irq.c +++ b/arch/s390/kernel/irq.c | |||
| @@ -127,13 +127,10 @@ int show_interrupts(struct seq_file *p, void *v) | |||
| 127 | for_each_online_cpu(cpu) | 127 | for_each_online_cpu(cpu) |
| 128 | seq_printf(p, "CPU%d ", cpu); | 128 | seq_printf(p, "CPU%d ", cpu); |
| 129 | seq_putc(p, '\n'); | 129 | seq_putc(p, '\n'); |
| 130 | goto out; | ||
| 131 | } | 130 | } |
| 132 | if (index < NR_IRQS) { | 131 | if (index < NR_IRQS) { |
| 133 | if (index >= NR_IRQS_BASE) | 132 | if (index >= NR_IRQS_BASE) |
| 134 | goto out; | 133 | goto out; |
| 135 | /* Adjust index to process irqclass_main_desc array entries */ | ||
| 136 | index--; | ||
| 137 | seq_printf(p, "%s: ", irqclass_main_desc[index].name); | 134 | seq_printf(p, "%s: ", irqclass_main_desc[index].name); |
| 138 | irq = irqclass_main_desc[index].irq; | 135 | irq = irqclass_main_desc[index].irq; |
| 139 | for_each_online_cpu(cpu) | 136 | for_each_online_cpu(cpu) |
| @@ -158,7 +155,7 @@ out: | |||
| 158 | 155 | ||
| 159 | unsigned int arch_dynirq_lower_bound(unsigned int from) | 156 | unsigned int arch_dynirq_lower_bound(unsigned int from) |
| 160 | { | 157 | { |
| 161 | return from < THIN_INTERRUPT ? THIN_INTERRUPT : from; | 158 | return from < NR_IRQS_BASE ? NR_IRQS_BASE : from; |
| 162 | } | 159 | } |
| 163 | 160 | ||
| 164 | /* | 161 | /* |
diff --git a/arch/s390/kernel/kprobes.c b/arch/s390/kernel/kprobes.c index 014d4729b134..1e4c710dfb92 100644 --- a/arch/s390/kernel/kprobes.c +++ b/arch/s390/kernel/kprobes.c | |||
| @@ -29,6 +29,7 @@ | |||
| 29 | #include <linux/module.h> | 29 | #include <linux/module.h> |
| 30 | #include <linux/slab.h> | 30 | #include <linux/slab.h> |
| 31 | #include <linux/hardirq.h> | 31 | #include <linux/hardirq.h> |
| 32 | #include <linux/ftrace.h> | ||
| 32 | #include <asm/cacheflush.h> | 33 | #include <asm/cacheflush.h> |
| 33 | #include <asm/sections.h> | 34 | #include <asm/sections.h> |
| 34 | #include <asm/dis.h> | 35 | #include <asm/dis.h> |
| @@ -58,12 +59,23 @@ struct kprobe_insn_cache kprobe_dmainsn_slots = { | |||
| 58 | .insn_size = MAX_INSN_SIZE, | 59 | .insn_size = MAX_INSN_SIZE, |
| 59 | }; | 60 | }; |
| 60 | 61 | ||
| 61 | static void __kprobes copy_instruction(struct kprobe *p) | 62 | static void copy_instruction(struct kprobe *p) |
| 62 | { | 63 | { |
| 64 | unsigned long ip = (unsigned long) p->addr; | ||
| 63 | s64 disp, new_disp; | 65 | s64 disp, new_disp; |
| 64 | u64 addr, new_addr; | 66 | u64 addr, new_addr; |
| 65 | 67 | ||
| 66 | memcpy(p->ainsn.insn, p->addr, insn_length(p->opcode >> 8)); | 68 | if (ftrace_location(ip) == ip) { |
| 69 | /* | ||
| 70 | * If kprobes patches the instruction that is morphed by | ||
| 71 | * ftrace make sure that kprobes always sees the branch | ||
| 72 | * "jg .+24" that skips the mcount block | ||
| 73 | */ | ||
| 74 | ftrace_generate_nop_insn((struct ftrace_insn *)p->ainsn.insn); | ||
| 75 | p->ainsn.is_ftrace_insn = 1; | ||
| 76 | } else | ||
| 77 | memcpy(p->ainsn.insn, p->addr, insn_length(*p->addr >> 8)); | ||
| 78 | p->opcode = p->ainsn.insn[0]; | ||
| 67 | if (!probe_is_insn_relative_long(p->ainsn.insn)) | 79 | if (!probe_is_insn_relative_long(p->ainsn.insn)) |
| 68 | return; | 80 | return; |
| 69 | /* | 81 | /* |
| @@ -79,25 +91,14 @@ static void __kprobes copy_instruction(struct kprobe *p) | |||
| 79 | new_disp = ((addr + (disp * 2)) - new_addr) / 2; | 91 | new_disp = ((addr + (disp * 2)) - new_addr) / 2; |
| 80 | *(s32 *)&p->ainsn.insn[1] = new_disp; | 92 | *(s32 *)&p->ainsn.insn[1] = new_disp; |
| 81 | } | 93 | } |
| 94 | NOKPROBE_SYMBOL(copy_instruction); | ||
| 82 | 95 | ||
| 83 | static inline int is_kernel_addr(void *addr) | 96 | static inline int is_kernel_addr(void *addr) |
| 84 | { | 97 | { |
| 85 | return addr < (void *)_end; | 98 | return addr < (void *)_end; |
| 86 | } | 99 | } |
| 87 | 100 | ||
| 88 | static inline int is_module_addr(void *addr) | 101 | static int s390_get_insn_slot(struct kprobe *p) |
| 89 | { | ||
| 90 | #ifdef CONFIG_64BIT | ||
| 91 | BUILD_BUG_ON(MODULES_LEN > (1UL << 31)); | ||
| 92 | if (addr < (void *)MODULES_VADDR) | ||
| 93 | return 0; | ||
| 94 | if (addr > (void *)MODULES_END) | ||
| 95 | return 0; | ||
| 96 | #endif | ||
| 97 | return 1; | ||
| 98 | } | ||
| 99 | |||
| 100 | static int __kprobes s390_get_insn_slot(struct kprobe *p) | ||
| 101 | { | 102 | { |
| 102 | /* | 103 | /* |
| 103 | * Get an insn slot that is within the same 2GB area like the original | 104 | * Get an insn slot that is within the same 2GB area like the original |
| @@ -111,8 +112,9 @@ static int __kprobes s390_get_insn_slot(struct kprobe *p) | |||
| 111 | p->ainsn.insn = get_insn_slot(); | 112 | p->ainsn.insn = get_insn_slot(); |
| 112 | return p->ainsn.insn ? 0 : -ENOMEM; | 113 | return p->ainsn.insn ? 0 : -ENOMEM; |
| 113 | } | 114 | } |
| 115 | NOKPROBE_SYMBOL(s390_get_insn_slot); | ||
| 114 | 116 | ||
| 115 | static void __kprobes s390_free_insn_slot(struct kprobe *p) | 117 | static void s390_free_insn_slot(struct kprobe *p) |
| 116 | { | 118 | { |
| 117 | if (!p->ainsn.insn) | 119 | if (!p->ainsn.insn) |
| 118 | return; | 120 | return; |
| @@ -122,8 +124,9 @@ static void __kprobes s390_free_insn_slot(struct kprobe *p) | |||
| 122 | free_insn_slot(p->ainsn.insn, 0); | 124 | free_insn_slot(p->ainsn.insn, 0); |
| 123 | p->ainsn.insn = NULL; | 125 | p->ainsn.insn = NULL; |
| 124 | } | 126 | } |
| 127 | NOKPROBE_SYMBOL(s390_free_insn_slot); | ||
| 125 | 128 | ||
| 126 | int __kprobes arch_prepare_kprobe(struct kprobe *p) | 129 | int arch_prepare_kprobe(struct kprobe *p) |
| 127 | { | 130 | { |
| 128 | if ((unsigned long) p->addr & 0x01) | 131 | if ((unsigned long) p->addr & 0x01) |
| 129 | return -EINVAL; | 132 | return -EINVAL; |
| @@ -132,54 +135,79 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) | |||
| 132 | return -EINVAL; | 135 | return -EINVAL; |
| 133 | if (s390_get_insn_slot(p)) | 136 | if (s390_get_insn_slot(p)) |
| 134 | return -ENOMEM; | 137 | return -ENOMEM; |
| 135 | p->opcode = *p->addr; | ||
| 136 | copy_instruction(p); | 138 | copy_instruction(p); |
| 137 | return 0; | 139 | return 0; |
| 138 | } | 140 | } |
| 141 | NOKPROBE_SYMBOL(arch_prepare_kprobe); | ||
| 139 | 142 | ||
| 140 | struct ins_replace_args { | 143 | int arch_check_ftrace_location(struct kprobe *p) |
| 141 | kprobe_opcode_t *ptr; | 144 | { |
| 142 | kprobe_opcode_t opcode; | 145 | return 0; |
| 146 | } | ||
| 147 | |||
| 148 | struct swap_insn_args { | ||
| 149 | struct kprobe *p; | ||
| 150 | unsigned int arm_kprobe : 1; | ||
| 143 | }; | 151 | }; |
| 144 | 152 | ||
| 145 | static int __kprobes swap_instruction(void *aref) | 153 | static int swap_instruction(void *data) |
| 146 | { | 154 | { |
| 147 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); | 155 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); |
| 148 | unsigned long status = kcb->kprobe_status; | 156 | unsigned long status = kcb->kprobe_status; |
| 149 | struct ins_replace_args *args = aref; | 157 | struct swap_insn_args *args = data; |
| 150 | 158 | struct ftrace_insn new_insn, *insn; | |
| 159 | struct kprobe *p = args->p; | ||
| 160 | size_t len; | ||
| 161 | |||
| 162 | new_insn.opc = args->arm_kprobe ? BREAKPOINT_INSTRUCTION : p->opcode; | ||
| 163 | len = sizeof(new_insn.opc); | ||
| 164 | if (!p->ainsn.is_ftrace_insn) | ||
| 165 | goto skip_ftrace; | ||
| 166 | len = sizeof(new_insn); | ||
| 167 | insn = (struct ftrace_insn *) p->addr; | ||
| 168 | if (args->arm_kprobe) { | ||
| 169 | if (is_ftrace_nop(insn)) | ||
| 170 | new_insn.disp = KPROBE_ON_FTRACE_NOP; | ||
| 171 | else | ||
| 172 | new_insn.disp = KPROBE_ON_FTRACE_CALL; | ||
| 173 | } else { | ||
| 174 | ftrace_generate_call_insn(&new_insn, (unsigned long)p->addr); | ||
| 175 | if (insn->disp == KPROBE_ON_FTRACE_NOP) | ||
| 176 | ftrace_generate_nop_insn(&new_insn); | ||
| 177 | } | ||
| 178 | skip_ftrace: | ||
| 151 | kcb->kprobe_status = KPROBE_SWAP_INST; | 179 | kcb->kprobe_status = KPROBE_SWAP_INST; |
| 152 | probe_kernel_write(args->ptr, &args->opcode, sizeof(args->opcode)); | 180 | probe_kernel_write(p->addr, &new_insn, len); |
| 153 | kcb->kprobe_status = status; | 181 | kcb->kprobe_status = status; |
| 154 | return 0; | 182 | return 0; |
| 155 | } | 183 | } |
| 184 | NOKPROBE_SYMBOL(swap_instruction); | ||
| 156 | 185 | ||
| 157 | void __kprobes arch_arm_kprobe(struct kprobe *p) | 186 | void arch_arm_kprobe(struct kprobe *p) |
| 158 | { | 187 | { |
| 159 | struct ins_replace_args args; | 188 | struct swap_insn_args args = {.p = p, .arm_kprobe = 1}; |
| 160 | 189 | ||
| 161 | args.ptr = p->addr; | ||
| 162 | args.opcode = BREAKPOINT_INSTRUCTION; | ||
| 163 | stop_machine(swap_instruction, &args, NULL); | 190 | stop_machine(swap_instruction, &args, NULL); |
| 164 | } | 191 | } |
| 192 | NOKPROBE_SYMBOL(arch_arm_kprobe); | ||
| 165 | 193 | ||
| 166 | void __kprobes arch_disarm_kprobe(struct kprobe *p) | 194 | void arch_disarm_kprobe(struct kprobe *p) |
| 167 | { | 195 | { |
| 168 | struct ins_replace_args args; | 196 | struct swap_insn_args args = {.p = p, .arm_kprobe = 0}; |
| 169 | 197 | ||
| 170 | args.ptr = p->addr; | ||
| 171 | args.opcode = p->opcode; | ||
| 172 | stop_machine(swap_instruction, &args, NULL); | 198 | stop_machine(swap_instruction, &args, NULL); |
| 173 | } | 199 | } |
| 200 | NOKPROBE_SYMBOL(arch_disarm_kprobe); | ||
| 174 | 201 | ||
| 175 | void __kprobes arch_remove_kprobe(struct kprobe *p) | 202 | void arch_remove_kprobe(struct kprobe *p) |
| 176 | { | 203 | { |
| 177 | s390_free_insn_slot(p); | 204 | s390_free_insn_slot(p); |
| 178 | } | 205 | } |
| 206 | NOKPROBE_SYMBOL(arch_remove_kprobe); | ||
| 179 | 207 | ||
| 180 | static void __kprobes enable_singlestep(struct kprobe_ctlblk *kcb, | 208 | static void enable_singlestep(struct kprobe_ctlblk *kcb, |
| 181 | struct pt_regs *regs, | 209 | struct pt_regs *regs, |
| 182 | unsigned long ip) | 210 | unsigned long ip) |
| 183 | { | 211 | { |
| 184 | struct per_regs per_kprobe; | 212 | struct per_regs per_kprobe; |
| 185 | 213 | ||
| @@ -199,10 +227,11 @@ static void __kprobes enable_singlestep(struct kprobe_ctlblk *kcb, | |||
| 199 | regs->psw.mask &= ~(PSW_MASK_IO | PSW_MASK_EXT); | 227 | regs->psw.mask &= ~(PSW_MASK_IO | PSW_MASK_EXT); |
| 200 | regs->psw.addr = ip | PSW_ADDR_AMODE; | 228 | regs->psw.addr = ip | PSW_ADDR_AMODE; |
| 201 | } | 229 | } |
| 230 | NOKPROBE_SYMBOL(enable_singlestep); | ||
| 202 | 231 | ||
| 203 | static void __kprobes disable_singlestep(struct kprobe_ctlblk *kcb, | 232 | static void disable_singlestep(struct kprobe_ctlblk *kcb, |
| 204 | struct pt_regs *regs, | 233 | struct pt_regs *regs, |
| 205 | unsigned long ip) | 234 | unsigned long ip) |
| 206 | { | 235 | { |
| 207 | /* Restore control regs and psw mask, set new psw address */ | 236 | /* Restore control regs and psw mask, set new psw address */ |
| 208 | __ctl_load(kcb->kprobe_saved_ctl, 9, 11); | 237 | __ctl_load(kcb->kprobe_saved_ctl, 9, 11); |
| @@ -210,41 +239,43 @@ static void __kprobes disable_singlestep(struct kprobe_ctlblk *kcb, | |||
| 210 | regs->psw.mask |= kcb->kprobe_saved_imask; | 239 | regs->psw.mask |= kcb->kprobe_saved_imask; |
| 211 | regs->psw.addr = ip | PSW_ADDR_AMODE; | 240 | regs->psw.addr = ip | PSW_ADDR_AMODE; |
| 212 | } | 241 | } |
| 242 | NOKPROBE_SYMBOL(disable_singlestep); | ||
| 213 | 243 | ||
| 214 | /* | 244 | /* |
| 215 | * Activate a kprobe by storing its pointer to current_kprobe. The | 245 | * Activate a kprobe by storing its pointer to current_kprobe. The |
| 216 | * previous kprobe is stored in kcb->prev_kprobe. A stack of up to | 246 | * previous kprobe is stored in kcb->prev_kprobe. A stack of up to |
| 217 | * two kprobes can be active, see KPROBE_REENTER. | 247 | * two kprobes can be active, see KPROBE_REENTER. |
| 218 | */ | 248 | */ |
| 219 | static void __kprobes push_kprobe(struct kprobe_ctlblk *kcb, struct kprobe *p) | 249 | static void push_kprobe(struct kprobe_ctlblk *kcb, struct kprobe *p) |
| 220 | { | 250 | { |
| 221 | kcb->prev_kprobe.kp = __this_cpu_read(current_kprobe); | 251 | kcb->prev_kprobe.kp = __this_cpu_read(current_kprobe); |
| 222 | kcb->prev_kprobe.status = kcb->kprobe_status; | 252 | kcb->prev_kprobe.status = kcb->kprobe_status; |
| 223 | __this_cpu_write(current_kprobe, p); | 253 | __this_cpu_write(current_kprobe, p); |
| 224 | } | 254 | } |
| 255 | NOKPROBE_SYMBOL(push_kprobe); | ||
| 225 | 256 | ||
| 226 | /* | 257 | /* |
| 227 | * Deactivate a kprobe by backing up to the previous state. If the | 258 | * Deactivate a kprobe by backing up to the previous state. If the |
| 228 | * current state is KPROBE_REENTER prev_kprobe.kp will be non-NULL, | 259 | * current state is KPROBE_REENTER prev_kprobe.kp will be non-NULL, |
| 229 | * for any other state prev_kprobe.kp will be NULL. | 260 | * for any other state prev_kprobe.kp will be NULL. |
| 230 | */ | 261 | */ |
| 231 | static void __kprobes pop_kprobe(struct kprobe_ctlblk *kcb) | 262 | static void pop_kprobe(struct kprobe_ctlblk *kcb) |
| 232 | { | 263 | { |
| 233 | __this_cpu_write(current_kprobe, kcb->prev_kprobe.kp); | 264 | __this_cpu_write(current_kprobe, kcb->prev_kprobe.kp); |
| 234 | kcb->kprobe_status = kcb->prev_kprobe.status; | 265 | kcb->kprobe_status = kcb->prev_kprobe.status; |
| 235 | } | 266 | } |
| 267 | NOKPROBE_SYMBOL(pop_kprobe); | ||
| 236 | 268 | ||
| 237 | void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri, | 269 | void arch_prepare_kretprobe(struct kretprobe_instance *ri, struct pt_regs *regs) |
| 238 | struct pt_regs *regs) | ||
| 239 | { | 270 | { |
| 240 | ri->ret_addr = (kprobe_opcode_t *) regs->gprs[14]; | 271 | ri->ret_addr = (kprobe_opcode_t *) regs->gprs[14]; |
| 241 | 272 | ||
| 242 | /* Replace the return addr with trampoline addr */ | 273 | /* Replace the return addr with trampoline addr */ |
| 243 | regs->gprs[14] = (unsigned long) &kretprobe_trampoline; | 274 | regs->gprs[14] = (unsigned long) &kretprobe_trampoline; |
| 244 | } | 275 | } |
| 276 | NOKPROBE_SYMBOL(arch_prepare_kretprobe); | ||
| 245 | 277 | ||
| 246 | static void __kprobes kprobe_reenter_check(struct kprobe_ctlblk *kcb, | 278 | static void kprobe_reenter_check(struct kprobe_ctlblk *kcb, struct kprobe *p) |
| 247 | struct kprobe *p) | ||
| 248 | { | 279 | { |
| 249 | switch (kcb->kprobe_status) { | 280 | switch (kcb->kprobe_status) { |
| 250 | case KPROBE_HIT_SSDONE: | 281 | case KPROBE_HIT_SSDONE: |
| @@ -264,8 +295,9 @@ static void __kprobes kprobe_reenter_check(struct kprobe_ctlblk *kcb, | |||
| 264 | BUG(); | 295 | BUG(); |
| 265 | } | 296 | } |
| 266 | } | 297 | } |
| 298 | NOKPROBE_SYMBOL(kprobe_reenter_check); | ||
| 267 | 299 | ||
| 268 | static int __kprobes kprobe_handler(struct pt_regs *regs) | 300 | static int kprobe_handler(struct pt_regs *regs) |
| 269 | { | 301 | { |
| 270 | struct kprobe_ctlblk *kcb; | 302 | struct kprobe_ctlblk *kcb; |
| 271 | struct kprobe *p; | 303 | struct kprobe *p; |
| @@ -339,6 +371,7 @@ static int __kprobes kprobe_handler(struct pt_regs *regs) | |||
| 339 | preempt_enable_no_resched(); | 371 | preempt_enable_no_resched(); |
| 340 | return 0; | 372 | return 0; |
| 341 | } | 373 | } |
| 374 | NOKPROBE_SYMBOL(kprobe_handler); | ||
| 342 | 375 | ||
| 343 | /* | 376 | /* |
| 344 | * Function return probe trampoline: | 377 | * Function return probe trampoline: |
| @@ -355,8 +388,7 @@ static void __used kretprobe_trampoline_holder(void) | |||
| 355 | /* | 388 | /* |
| 356 | * Called when the probe at kretprobe trampoline is hit | 389 | * Called when the probe at kretprobe trampoline is hit |
| 357 | */ | 390 | */ |
| 358 | static int __kprobes trampoline_probe_handler(struct kprobe *p, | 391 | static int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) |
| 359 | struct pt_regs *regs) | ||
| 360 | { | 392 | { |
| 361 | struct kretprobe_instance *ri; | 393 | struct kretprobe_instance *ri; |
| 362 | struct hlist_head *head, empty_rp; | 394 | struct hlist_head *head, empty_rp; |
| @@ -444,6 +476,7 @@ static int __kprobes trampoline_probe_handler(struct kprobe *p, | |||
| 444 | */ | 476 | */ |
| 445 | return 1; | 477 | return 1; |
| 446 | } | 478 | } |
| 479 | NOKPROBE_SYMBOL(trampoline_probe_handler); | ||
| 447 | 480 | ||
| 448 | /* | 481 | /* |
| 449 | * Called after single-stepping. p->addr is the address of the | 482 | * Called after single-stepping. p->addr is the address of the |
| @@ -453,12 +486,30 @@ static int __kprobes trampoline_probe_handler(struct kprobe *p, | |||
| 453 | * single-stepped a copy of the instruction. The address of this | 486 | * single-stepped a copy of the instruction. The address of this |
| 454 | * copy is p->ainsn.insn. | 487 | * copy is p->ainsn.insn. |
| 455 | */ | 488 | */ |
| 456 | static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs) | 489 | static void resume_execution(struct kprobe *p, struct pt_regs *regs) |
| 457 | { | 490 | { |
| 458 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); | 491 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); |
| 459 | unsigned long ip = regs->psw.addr & PSW_ADDR_INSN; | 492 | unsigned long ip = regs->psw.addr & PSW_ADDR_INSN; |
| 460 | int fixup = probe_get_fixup_type(p->ainsn.insn); | 493 | int fixup = probe_get_fixup_type(p->ainsn.insn); |
| 461 | 494 | ||
| 495 | /* Check if the kprobes location is an enabled ftrace caller */ | ||
| 496 | if (p->ainsn.is_ftrace_insn) { | ||
| 497 | struct ftrace_insn *insn = (struct ftrace_insn *) p->addr; | ||
| 498 | struct ftrace_insn call_insn; | ||
| 499 | |||
| 500 | ftrace_generate_call_insn(&call_insn, (unsigned long) p->addr); | ||
| 501 | /* | ||
| 502 | * A kprobe on an enabled ftrace call site actually single | ||
| 503 | * stepped an unconditional branch (ftrace nop equivalent). | ||
| 504 | * Now we need to fixup things and pretend that a brasl r0,... | ||
| 505 | * was executed instead. | ||
| 506 | */ | ||
| 507 | if (insn->disp == KPROBE_ON_FTRACE_CALL) { | ||
| 508 | ip += call_insn.disp * 2 - MCOUNT_INSN_SIZE; | ||
| 509 | regs->gprs[0] = (unsigned long)p->addr + sizeof(*insn); | ||
| 510 | } | ||
| 511 | } | ||
| 512 | |||
| 462 | if (fixup & FIXUP_PSW_NORMAL) | 513 | if (fixup & FIXUP_PSW_NORMAL) |
| 463 | ip += (unsigned long) p->addr - (unsigned long) p->ainsn.insn; | 514 | ip += (unsigned long) p->addr - (unsigned long) p->ainsn.insn; |
| 464 | 515 | ||
| @@ -476,8 +527,9 @@ static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs) | |||
| 476 | 527 | ||
| 477 | disable_singlestep(kcb, regs, ip); | 528 | disable_singlestep(kcb, regs, ip); |
| 478 | } | 529 | } |
| 530 | NOKPROBE_SYMBOL(resume_execution); | ||
| 479 | 531 | ||
| 480 | static int __kprobes post_kprobe_handler(struct pt_regs *regs) | 532 | static int post_kprobe_handler(struct pt_regs *regs) |
| 481 | { | 533 | { |
| 482 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); | 534 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); |
| 483 | struct kprobe *p = kprobe_running(); | 535 | struct kprobe *p = kprobe_running(); |
| @@ -504,8 +556,9 @@ static int __kprobes post_kprobe_handler(struct pt_regs *regs) | |||
| 504 | 556 | ||
| 505 | return 1; | 557 | return 1; |
| 506 | } | 558 | } |
| 559 | NOKPROBE_SYMBOL(post_kprobe_handler); | ||
| 507 | 560 | ||
| 508 | static int __kprobes kprobe_trap_handler(struct pt_regs *regs, int trapnr) | 561 | static int kprobe_trap_handler(struct pt_regs *regs, int trapnr) |
| 509 | { | 562 | { |
| 510 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); | 563 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); |
| 511 | struct kprobe *p = kprobe_running(); | 564 | struct kprobe *p = kprobe_running(); |
| @@ -567,8 +620,9 @@ static int __kprobes kprobe_trap_handler(struct pt_regs *regs, int trapnr) | |||
| 567 | } | 620 | } |
| 568 | return 0; | 621 | return 0; |
| 569 | } | 622 | } |
| 623 | NOKPROBE_SYMBOL(kprobe_trap_handler); | ||
| 570 | 624 | ||
| 571 | int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr) | 625 | int kprobe_fault_handler(struct pt_regs *regs, int trapnr) |
| 572 | { | 626 | { |
| 573 | int ret; | 627 | int ret; |
| 574 | 628 | ||
| @@ -579,12 +633,13 @@ int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr) | |||
| 579 | local_irq_restore(regs->psw.mask & ~PSW_MASK_PER); | 633 | local_irq_restore(regs->psw.mask & ~PSW_MASK_PER); |
| 580 | return ret; | 634 | return ret; |
| 581 | } | 635 | } |
| 636 | NOKPROBE_SYMBOL(kprobe_fault_handler); | ||
| 582 | 637 | ||
| 583 | /* | 638 | /* |
| 584 | * Wrapper routine to for handling exceptions. | 639 | * Wrapper routine to for handling exceptions. |
| 585 | */ | 640 | */ |
| 586 | int __kprobes kprobe_exceptions_notify(struct notifier_block *self, | 641 | int kprobe_exceptions_notify(struct notifier_block *self, |
| 587 | unsigned long val, void *data) | 642 | unsigned long val, void *data) |
| 588 | { | 643 | { |
| 589 | struct die_args *args = (struct die_args *) data; | 644 | struct die_args *args = (struct die_args *) data; |
| 590 | struct pt_regs *regs = args->regs; | 645 | struct pt_regs *regs = args->regs; |
| @@ -616,8 +671,9 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self, | |||
| 616 | 671 | ||
| 617 | return ret; | 672 | return ret; |
| 618 | } | 673 | } |
| 674 | NOKPROBE_SYMBOL(kprobe_exceptions_notify); | ||
| 619 | 675 | ||
| 620 | int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) | 676 | int setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) |
| 621 | { | 677 | { |
| 622 | struct jprobe *jp = container_of(p, struct jprobe, kp); | 678 | struct jprobe *jp = container_of(p, struct jprobe, kp); |
| 623 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); | 679 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); |
| @@ -635,13 +691,15 @@ int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) | |||
| 635 | memcpy(kcb->jprobes_stack, (void *) stack, MIN_STACK_SIZE(stack)); | 691 | memcpy(kcb->jprobes_stack, (void *) stack, MIN_STACK_SIZE(stack)); |
| 636 | return 1; | 692 | return 1; |
| 637 | } | 693 | } |
| 694 | NOKPROBE_SYMBOL(setjmp_pre_handler); | ||
| 638 | 695 | ||
| 639 | void __kprobes jprobe_return(void) | 696 | void jprobe_return(void) |
| 640 | { | 697 | { |
| 641 | asm volatile(".word 0x0002"); | 698 | asm volatile(".word 0x0002"); |
| 642 | } | 699 | } |
| 700 | NOKPROBE_SYMBOL(jprobe_return); | ||
| 643 | 701 | ||
| 644 | int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) | 702 | int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) |
| 645 | { | 703 | { |
| 646 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); | 704 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); |
| 647 | unsigned long stack; | 705 | unsigned long stack; |
| @@ -655,6 +713,7 @@ int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) | |||
| 655 | preempt_enable_no_resched(); | 713 | preempt_enable_no_resched(); |
| 656 | return 1; | 714 | return 1; |
| 657 | } | 715 | } |
| 716 | NOKPROBE_SYMBOL(longjmp_break_handler); | ||
| 658 | 717 | ||
| 659 | static struct kprobe trampoline = { | 718 | static struct kprobe trampoline = { |
| 660 | .addr = (kprobe_opcode_t *) &kretprobe_trampoline, | 719 | .addr = (kprobe_opcode_t *) &kretprobe_trampoline, |
| @@ -666,7 +725,8 @@ int __init arch_init_kprobes(void) | |||
| 666 | return register_kprobe(&trampoline); | 725 | return register_kprobe(&trampoline); |
| 667 | } | 726 | } |
| 668 | 727 | ||
| 669 | int __kprobes arch_trampoline_kprobe(struct kprobe *p) | 728 | int arch_trampoline_kprobe(struct kprobe *p) |
| 670 | { | 729 | { |
| 671 | return p->addr == (kprobe_opcode_t *) &kretprobe_trampoline; | 730 | return p->addr == (kprobe_opcode_t *) &kretprobe_trampoline; |
| 672 | } | 731 | } |
| 732 | NOKPROBE_SYMBOL(arch_trampoline_kprobe); | ||
diff --git a/arch/s390/kernel/mcount.S b/arch/s390/kernel/mcount.S index 4300ea374826..b6dfc5bfcb89 100644 --- a/arch/s390/kernel/mcount.S +++ b/arch/s390/kernel/mcount.S | |||
| @@ -27,6 +27,7 @@ ENTRY(ftrace_caller) | |||
| 27 | .globl ftrace_regs_caller | 27 | .globl ftrace_regs_caller |
| 28 | .set ftrace_regs_caller,ftrace_caller | 28 | .set ftrace_regs_caller,ftrace_caller |
| 29 | lgr %r1,%r15 | 29 | lgr %r1,%r15 |
| 30 | aghi %r0,MCOUNT_RETURN_FIXUP | ||
| 30 | aghi %r15,-STACK_FRAME_SIZE | 31 | aghi %r15,-STACK_FRAME_SIZE |
| 31 | stg %r1,__SF_BACKCHAIN(%r15) | 32 | stg %r1,__SF_BACKCHAIN(%r15) |
| 32 | stg %r1,(STACK_PTREGS_GPRS+15*8)(%r15) | 33 | stg %r1,(STACK_PTREGS_GPRS+15*8)(%r15) |
diff --git a/arch/s390/kernel/perf_cpum_sf.c b/arch/s390/kernel/perf_cpum_sf.c index b878f12a9597..c3f8d157cb0d 100644 --- a/arch/s390/kernel/perf_cpum_sf.c +++ b/arch/s390/kernel/perf_cpum_sf.c | |||
| @@ -1383,7 +1383,6 @@ static int cpumsf_pmu_add(struct perf_event *event, int flags) | |||
| 1383 | cpuhw->lsctl.ed = 1; | 1383 | cpuhw->lsctl.ed = 1; |
| 1384 | 1384 | ||
| 1385 | /* Set in_use flag and store event */ | 1385 | /* Set in_use flag and store event */ |
| 1386 | event->hw.idx = 0; /* only one sampling event per CPU supported */ | ||
| 1387 | cpuhw->event = event; | 1386 | cpuhw->event = event; |
| 1388 | cpuhw->flags |= PMU_F_IN_USE; | 1387 | cpuhw->flags |= PMU_F_IN_USE; |
| 1389 | 1388 | ||
diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c index ed84cc224899..aa7a83948c7b 100644 --- a/arch/s390/kernel/process.c +++ b/arch/s390/kernel/process.c | |||
| @@ -61,7 +61,7 @@ unsigned long thread_saved_pc(struct task_struct *tsk) | |||
| 61 | return sf->gprs[8]; | 61 | return sf->gprs[8]; |
| 62 | } | 62 | } |
| 63 | 63 | ||
| 64 | extern void __kprobes kernel_thread_starter(void); | 64 | extern void kernel_thread_starter(void); |
| 65 | 65 | ||
| 66 | /* | 66 | /* |
| 67 | * Free current thread data structures etc.. | 67 | * Free current thread data structures etc.. |
| @@ -153,6 +153,7 @@ int copy_thread(unsigned long clone_flags, unsigned long new_stackp, | |||
| 153 | save_fp_ctl(&p->thread.fp_regs.fpc); | 153 | save_fp_ctl(&p->thread.fp_regs.fpc); |
| 154 | save_fp_regs(p->thread.fp_regs.fprs); | 154 | save_fp_regs(p->thread.fp_regs.fprs); |
| 155 | p->thread.fp_regs.pad = 0; | 155 | p->thread.fp_regs.pad = 0; |
| 156 | p->thread.vxrs = NULL; | ||
| 156 | /* Set a new TLS ? */ | 157 | /* Set a new TLS ? */ |
| 157 | if (clone_flags & CLONE_SETTLS) { | 158 | if (clone_flags & CLONE_SETTLS) { |
| 158 | unsigned long tls = frame->childregs.gprs[6]; | 159 | unsigned long tls = frame->childregs.gprs[6]; |
diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c index 99a567b70d16..eabfb4594517 100644 --- a/arch/s390/kernel/ptrace.c +++ b/arch/s390/kernel/ptrace.c | |||
| @@ -248,14 +248,27 @@ static unsigned long __peek_user(struct task_struct *child, addr_t addr) | |||
| 248 | */ | 248 | */ |
| 249 | tmp = 0; | 249 | tmp = 0; |
| 250 | 250 | ||
| 251 | } else if (addr == (addr_t) &dummy->regs.fp_regs.fpc) { | ||
| 252 | /* | ||
| 253 | * floating point control reg. is in the thread structure | ||
| 254 | */ | ||
| 255 | tmp = child->thread.fp_regs.fpc; | ||
| 256 | tmp <<= BITS_PER_LONG - 32; | ||
| 257 | |||
| 251 | } else if (addr < (addr_t) (&dummy->regs.fp_regs + 1)) { | 258 | } else if (addr < (addr_t) (&dummy->regs.fp_regs + 1)) { |
| 252 | /* | 259 | /* |
| 253 | * floating point regs. are stored in the thread structure | 260 | * floating point regs. are either in child->thread.fp_regs |
| 261 | * or the child->thread.vxrs array | ||
| 254 | */ | 262 | */ |
| 255 | offset = addr - (addr_t) &dummy->regs.fp_regs; | 263 | offset = addr - (addr_t) &dummy->regs.fp_regs.fprs; |
| 256 | tmp = *(addr_t *)((addr_t) &child->thread.fp_regs + offset); | 264 | #ifdef CONFIG_64BIT |
| 257 | if (addr == (addr_t) &dummy->regs.fp_regs.fpc) | 265 | if (child->thread.vxrs) |
| 258 | tmp <<= BITS_PER_LONG - 32; | 266 | tmp = *(addr_t *) |
| 267 | ((addr_t) child->thread.vxrs + 2*offset); | ||
| 268 | else | ||
| 269 | #endif | ||
| 270 | tmp = *(addr_t *) | ||
| 271 | ((addr_t) &child->thread.fp_regs.fprs + offset); | ||
| 259 | 272 | ||
| 260 | } else if (addr < (addr_t) (&dummy->regs.per_info + 1)) { | 273 | } else if (addr < (addr_t) (&dummy->regs.per_info + 1)) { |
| 261 | /* | 274 | /* |
| @@ -383,16 +396,29 @@ static int __poke_user(struct task_struct *child, addr_t addr, addr_t data) | |||
| 383 | */ | 396 | */ |
| 384 | return 0; | 397 | return 0; |
| 385 | 398 | ||
| 399 | } else if (addr == (addr_t) &dummy->regs.fp_regs.fpc) { | ||
| 400 | /* | ||
| 401 | * floating point control reg. is in the thread structure | ||
| 402 | */ | ||
| 403 | if ((unsigned int) data != 0 || | ||
| 404 | test_fp_ctl(data >> (BITS_PER_LONG - 32))) | ||
| 405 | return -EINVAL; | ||
| 406 | child->thread.fp_regs.fpc = data >> (BITS_PER_LONG - 32); | ||
| 407 | |||
| 386 | } else if (addr < (addr_t) (&dummy->regs.fp_regs + 1)) { | 408 | } else if (addr < (addr_t) (&dummy->regs.fp_regs + 1)) { |
| 387 | /* | 409 | /* |
| 388 | * floating point regs. are stored in the thread structure | 410 | * floating point regs. are either in child->thread.fp_regs |
| 411 | * or the child->thread.vxrs array | ||
| 389 | */ | 412 | */ |
| 390 | if (addr == (addr_t) &dummy->regs.fp_regs.fpc) | 413 | offset = addr - (addr_t) &dummy->regs.fp_regs.fprs; |
| 391 | if ((unsigned int) data != 0 || | 414 | #ifdef CONFIG_64BIT |
| 392 | test_fp_ctl(data >> (BITS_PER_LONG - 32))) | 415 | if (child->thread.vxrs) |
| 393 | return -EINVAL; | 416 | *(addr_t *)((addr_t) |
| 394 | offset = addr - (addr_t) &dummy->regs.fp_regs; | 417 | child->thread.vxrs + 2*offset) = data; |
| 395 | *(addr_t *)((addr_t) &child->thread.fp_regs + offset) = data; | 418 | else |
| 419 | #endif | ||
| 420 | *(addr_t *)((addr_t) | ||
| 421 | &child->thread.fp_regs.fprs + offset) = data; | ||
| 396 | 422 | ||
| 397 | } else if (addr < (addr_t) (&dummy->regs.per_info + 1)) { | 423 | } else if (addr < (addr_t) (&dummy->regs.per_info + 1)) { |
| 398 | /* | 424 | /* |
| @@ -611,12 +637,26 @@ static u32 __peek_user_compat(struct task_struct *child, addr_t addr) | |||
| 611 | */ | 637 | */ |
| 612 | tmp = 0; | 638 | tmp = 0; |
| 613 | 639 | ||
| 640 | } else if (addr == (addr_t) &dummy32->regs.fp_regs.fpc) { | ||
| 641 | /* | ||
| 642 | * floating point control reg. is in the thread structure | ||
| 643 | */ | ||
| 644 | tmp = child->thread.fp_regs.fpc; | ||
| 645 | |||
| 614 | } else if (addr < (addr_t) (&dummy32->regs.fp_regs + 1)) { | 646 | } else if (addr < (addr_t) (&dummy32->regs.fp_regs + 1)) { |
| 615 | /* | 647 | /* |
| 616 | * floating point regs. are stored in the thread structure | 648 | * floating point regs. are either in child->thread.fp_regs |
| 649 | * or the child->thread.vxrs array | ||
| 617 | */ | 650 | */ |
| 618 | offset = addr - (addr_t) &dummy32->regs.fp_regs; | 651 | offset = addr - (addr_t) &dummy32->regs.fp_regs.fprs; |
| 619 | tmp = *(__u32 *)((addr_t) &child->thread.fp_regs + offset); | 652 | #ifdef CONFIG_64BIT |
| 653 | if (child->thread.vxrs) | ||
| 654 | tmp = *(__u32 *) | ||
| 655 | ((addr_t) child->thread.vxrs + 2*offset); | ||
| 656 | else | ||
| 657 | #endif | ||
| 658 | tmp = *(__u32 *) | ||
| 659 | ((addr_t) &child->thread.fp_regs.fprs + offset); | ||
| 620 | 660 | ||
| 621 | } else if (addr < (addr_t) (&dummy32->regs.per_info + 1)) { | 661 | } else if (addr < (addr_t) (&dummy32->regs.per_info + 1)) { |
| 622 | /* | 662 | /* |
| @@ -722,15 +762,28 @@ static int __poke_user_compat(struct task_struct *child, | |||
| 722 | */ | 762 | */ |
| 723 | return 0; | 763 | return 0; |
| 724 | 764 | ||
| 725 | } else if (addr < (addr_t) (&dummy32->regs.fp_regs + 1)) { | 765 | } else if (addr == (addr_t) &dummy32->regs.fp_regs.fpc) { |
| 726 | /* | 766 | /* |
| 727 | * floating point regs. are stored in the thread structure | 767 | * floating point control reg. is in the thread structure |
| 728 | */ | 768 | */ |
| 729 | if (addr == (addr_t) &dummy32->regs.fp_regs.fpc && | 769 | if (test_fp_ctl(tmp)) |
| 730 | test_fp_ctl(tmp)) | ||
| 731 | return -EINVAL; | 770 | return -EINVAL; |
| 732 | offset = addr - (addr_t) &dummy32->regs.fp_regs; | 771 | child->thread.fp_regs.fpc = data; |
| 733 | *(__u32 *)((addr_t) &child->thread.fp_regs + offset) = tmp; | 772 | |
| 773 | } else if (addr < (addr_t) (&dummy32->regs.fp_regs + 1)) { | ||
| 774 | /* | ||
| 775 | * floating point regs. are either in child->thread.fp_regs | ||
| 776 | * or the child->thread.vxrs array | ||
| 777 | */ | ||
| 778 | offset = addr - (addr_t) &dummy32->regs.fp_regs.fprs; | ||
| 779 | #ifdef CONFIG_64BIT | ||
| 780 | if (child->thread.vxrs) | ||
| 781 | *(__u32 *)((addr_t) | ||
| 782 | child->thread.vxrs + 2*offset) = tmp; | ||
| 783 | else | ||
| 784 | #endif | ||
| 785 | *(__u32 *)((addr_t) | ||
| 786 | &child->thread.fp_regs.fprs + offset) = tmp; | ||
| 734 | 787 | ||
| 735 | } else if (addr < (addr_t) (&dummy32->regs.per_info + 1)) { | 788 | } else if (addr < (addr_t) (&dummy32->regs.per_info + 1)) { |
| 736 | /* | 789 | /* |
| @@ -1038,12 +1091,6 @@ static int s390_tdb_set(struct task_struct *target, | |||
| 1038 | return 0; | 1091 | return 0; |
| 1039 | } | 1092 | } |
| 1040 | 1093 | ||
| 1041 | static int s390_vxrs_active(struct task_struct *target, | ||
| 1042 | const struct user_regset *regset) | ||
| 1043 | { | ||
| 1044 | return !!target->thread.vxrs; | ||
| 1045 | } | ||
| 1046 | |||
| 1047 | static int s390_vxrs_low_get(struct task_struct *target, | 1094 | static int s390_vxrs_low_get(struct task_struct *target, |
| 1048 | const struct user_regset *regset, | 1095 | const struct user_regset *regset, |
| 1049 | unsigned int pos, unsigned int count, | 1096 | unsigned int pos, unsigned int count, |
| @@ -1052,6 +1099,8 @@ static int s390_vxrs_low_get(struct task_struct *target, | |||
| 1052 | __u64 vxrs[__NUM_VXRS_LOW]; | 1099 | __u64 vxrs[__NUM_VXRS_LOW]; |
| 1053 | int i; | 1100 | int i; |
| 1054 | 1101 | ||
| 1102 | if (!MACHINE_HAS_VX) | ||
| 1103 | return -ENODEV; | ||
| 1055 | if (target->thread.vxrs) { | 1104 | if (target->thread.vxrs) { |
| 1056 | if (target == current) | 1105 | if (target == current) |
| 1057 | save_vx_regs(target->thread.vxrs); | 1106 | save_vx_regs(target->thread.vxrs); |
| @@ -1070,6 +1119,8 @@ static int s390_vxrs_low_set(struct task_struct *target, | |||
| 1070 | __u64 vxrs[__NUM_VXRS_LOW]; | 1119 | __u64 vxrs[__NUM_VXRS_LOW]; |
| 1071 | int i, rc; | 1120 | int i, rc; |
| 1072 | 1121 | ||
| 1122 | if (!MACHINE_HAS_VX) | ||
| 1123 | return -ENODEV; | ||
| 1073 | if (!target->thread.vxrs) { | 1124 | if (!target->thread.vxrs) { |
| 1074 | rc = alloc_vector_registers(target); | 1125 | rc = alloc_vector_registers(target); |
| 1075 | if (rc) | 1126 | if (rc) |
| @@ -1095,6 +1146,8 @@ static int s390_vxrs_high_get(struct task_struct *target, | |||
| 1095 | { | 1146 | { |
| 1096 | __vector128 vxrs[__NUM_VXRS_HIGH]; | 1147 | __vector128 vxrs[__NUM_VXRS_HIGH]; |
| 1097 | 1148 | ||
| 1149 | if (!MACHINE_HAS_VX) | ||
| 1150 | return -ENODEV; | ||
| 1098 | if (target->thread.vxrs) { | 1151 | if (target->thread.vxrs) { |
| 1099 | if (target == current) | 1152 | if (target == current) |
| 1100 | save_vx_regs(target->thread.vxrs); | 1153 | save_vx_regs(target->thread.vxrs); |
| @@ -1112,6 +1165,8 @@ static int s390_vxrs_high_set(struct task_struct *target, | |||
| 1112 | { | 1165 | { |
| 1113 | int rc; | 1166 | int rc; |
| 1114 | 1167 | ||
| 1168 | if (!MACHINE_HAS_VX) | ||
| 1169 | return -ENODEV; | ||
| 1115 | if (!target->thread.vxrs) { | 1170 | if (!target->thread.vxrs) { |
| 1116 | rc = alloc_vector_registers(target); | 1171 | rc = alloc_vector_registers(target); |
| 1117 | if (rc) | 1172 | if (rc) |
| @@ -1196,7 +1251,6 @@ static const struct user_regset s390_regsets[] = { | |||
| 1196 | .n = __NUM_VXRS_LOW, | 1251 | .n = __NUM_VXRS_LOW, |
| 1197 | .size = sizeof(__u64), | 1252 | .size = sizeof(__u64), |
| 1198 | .align = sizeof(__u64), | 1253 | .align = sizeof(__u64), |
| 1199 | .active = s390_vxrs_active, | ||
| 1200 | .get = s390_vxrs_low_get, | 1254 | .get = s390_vxrs_low_get, |
| 1201 | .set = s390_vxrs_low_set, | 1255 | .set = s390_vxrs_low_set, |
| 1202 | }, | 1256 | }, |
| @@ -1205,7 +1259,6 @@ static const struct user_regset s390_regsets[] = { | |||
| 1205 | .n = __NUM_VXRS_HIGH, | 1259 | .n = __NUM_VXRS_HIGH, |
| 1206 | .size = sizeof(__vector128), | 1260 | .size = sizeof(__vector128), |
| 1207 | .align = sizeof(__vector128), | 1261 | .align = sizeof(__vector128), |
| 1208 | .active = s390_vxrs_active, | ||
| 1209 | .get = s390_vxrs_high_get, | 1262 | .get = s390_vxrs_high_get, |
| 1210 | .set = s390_vxrs_high_set, | 1263 | .set = s390_vxrs_high_set, |
| 1211 | }, | 1264 | }, |
| @@ -1419,7 +1472,6 @@ static const struct user_regset s390_compat_regsets[] = { | |||
| 1419 | .n = __NUM_VXRS_LOW, | 1472 | .n = __NUM_VXRS_LOW, |
| 1420 | .size = sizeof(__u64), | 1473 | .size = sizeof(__u64), |
| 1421 | .align = sizeof(__u64), | 1474 | .align = sizeof(__u64), |
| 1422 | .active = s390_vxrs_active, | ||
| 1423 | .get = s390_vxrs_low_get, | 1475 | .get = s390_vxrs_low_get, |
| 1424 | .set = s390_vxrs_low_set, | 1476 | .set = s390_vxrs_low_set, |
| 1425 | }, | 1477 | }, |
| @@ -1428,7 +1480,6 @@ static const struct user_regset s390_compat_regsets[] = { | |||
| 1428 | .n = __NUM_VXRS_HIGH, | 1480 | .n = __NUM_VXRS_HIGH, |
| 1429 | .size = sizeof(__vector128), | 1481 | .size = sizeof(__vector128), |
| 1430 | .align = sizeof(__vector128), | 1482 | .align = sizeof(__vector128), |
| 1431 | .active = s390_vxrs_active, | ||
| 1432 | .get = s390_vxrs_high_get, | 1483 | .get = s390_vxrs_high_get, |
| 1433 | .set = s390_vxrs_high_set, | 1484 | .set = s390_vxrs_high_set, |
| 1434 | }, | 1485 | }, |
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index e80d9ff9a56d..4e532c67832f 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c | |||
| @@ -41,7 +41,6 @@ | |||
| 41 | #include <linux/ctype.h> | 41 | #include <linux/ctype.h> |
| 42 | #include <linux/reboot.h> | 42 | #include <linux/reboot.h> |
| 43 | #include <linux/topology.h> | 43 | #include <linux/topology.h> |
| 44 | #include <linux/ftrace.h> | ||
| 45 | #include <linux/kexec.h> | 44 | #include <linux/kexec.h> |
| 46 | #include <linux/crash_dump.h> | 45 | #include <linux/crash_dump.h> |
| 47 | #include <linux/memory.h> | 46 | #include <linux/memory.h> |
| @@ -356,7 +355,6 @@ static void __init setup_lowcore(void) | |||
| 356 | lc->steal_timer = S390_lowcore.steal_timer; | 355 | lc->steal_timer = S390_lowcore.steal_timer; |
| 357 | lc->last_update_timer = S390_lowcore.last_update_timer; | 356 | lc->last_update_timer = S390_lowcore.last_update_timer; |
| 358 | lc->last_update_clock = S390_lowcore.last_update_clock; | 357 | lc->last_update_clock = S390_lowcore.last_update_clock; |
| 359 | lc->ftrace_func = S390_lowcore.ftrace_func; | ||
| 360 | 358 | ||
| 361 | restart_stack = __alloc_bootmem(ASYNC_SIZE, ASYNC_SIZE, 0); | 359 | restart_stack = __alloc_bootmem(ASYNC_SIZE, ASYNC_SIZE, 0); |
| 362 | restart_stack += ASYNC_SIZE; | 360 | restart_stack += ASYNC_SIZE; |
diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c index 0c1a0ff0a558..6a2ac257d98f 100644 --- a/arch/s390/kernel/signal.c +++ b/arch/s390/kernel/signal.c | |||
| @@ -371,7 +371,7 @@ static int setup_frame(int sig, struct k_sigaction *ka, | |||
| 371 | restorer = (unsigned long) ka->sa.sa_restorer | PSW_ADDR_AMODE; | 371 | restorer = (unsigned long) ka->sa.sa_restorer | PSW_ADDR_AMODE; |
| 372 | } else { | 372 | } else { |
| 373 | /* Signal frame without vector registers are short ! */ | 373 | /* Signal frame without vector registers are short ! */ |
| 374 | __u16 __user *svc = (void *) frame + frame_size - 2; | 374 | __u16 __user *svc = (void __user *) frame + frame_size - 2; |
| 375 | if (__put_user(S390_SYSCALL_OPCODE | __NR_sigreturn, svc)) | 375 | if (__put_user(S390_SYSCALL_OPCODE | __NR_sigreturn, svc)) |
| 376 | return -EFAULT; | 376 | return -EFAULT; |
| 377 | restorer = (unsigned long) svc | PSW_ADDR_AMODE; | 377 | restorer = (unsigned long) svc | PSW_ADDR_AMODE; |
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 6fd9e60101f1..0b499f5cbe19 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c | |||
| @@ -236,7 +236,6 @@ static void pcpu_prepare_secondary(struct pcpu *pcpu, int cpu) | |||
| 236 | lc->percpu_offset = __per_cpu_offset[cpu]; | 236 | lc->percpu_offset = __per_cpu_offset[cpu]; |
| 237 | lc->kernel_asce = S390_lowcore.kernel_asce; | 237 | lc->kernel_asce = S390_lowcore.kernel_asce; |
| 238 | lc->machine_flags = S390_lowcore.machine_flags; | 238 | lc->machine_flags = S390_lowcore.machine_flags; |
| 239 | lc->ftrace_func = S390_lowcore.ftrace_func; | ||
| 240 | lc->user_timer = lc->system_timer = lc->steal_timer = 0; | 239 | lc->user_timer = lc->system_timer = lc->steal_timer = 0; |
| 241 | __ctl_store(lc->cregs_save_area, 0, 15); | 240 | __ctl_store(lc->cregs_save_area, 0, 15); |
| 242 | save_access_regs((unsigned int *) lc->access_regs_save_area); | 241 | save_access_regs((unsigned int *) lc->access_regs_save_area); |
diff --git a/arch/s390/kernel/syscalls.S b/arch/s390/kernel/syscalls.S index 9f7087fd58de..a2987243bc76 100644 --- a/arch/s390/kernel/syscalls.S +++ b/arch/s390/kernel/syscalls.S | |||
| @@ -360,3 +360,5 @@ SYSCALL(sys_seccomp,sys_seccomp,compat_sys_seccomp) | |||
| 360 | SYSCALL(sys_getrandom,sys_getrandom,compat_sys_getrandom) | 360 | SYSCALL(sys_getrandom,sys_getrandom,compat_sys_getrandom) |
| 361 | SYSCALL(sys_memfd_create,sys_memfd_create,compat_sys_memfd_create) /* 350 */ | 361 | SYSCALL(sys_memfd_create,sys_memfd_create,compat_sys_memfd_create) /* 350 */ |
| 362 | SYSCALL(sys_bpf,sys_bpf,compat_sys_bpf) | 362 | SYSCALL(sys_bpf,sys_bpf,compat_sys_bpf) |
| 363 | SYSCALL(sys_ni_syscall,sys_s390_pci_mmio_write,compat_sys_s390_pci_mmio_write) | ||
| 364 | SYSCALL(sys_ni_syscall,sys_s390_pci_mmio_read,compat_sys_s390_pci_mmio_read) | ||
diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c index 005d665fe4a5..20660dddb2d6 100644 --- a/arch/s390/kernel/time.c +++ b/arch/s390/kernel/time.c | |||
| @@ -61,10 +61,11 @@ static DEFINE_PER_CPU(struct clock_event_device, comparators); | |||
| 61 | /* | 61 | /* |
| 62 | * Scheduler clock - returns current time in nanosec units. | 62 | * Scheduler clock - returns current time in nanosec units. |
| 63 | */ | 63 | */ |
| 64 | unsigned long long notrace __kprobes sched_clock(void) | 64 | unsigned long long notrace sched_clock(void) |
| 65 | { | 65 | { |
| 66 | return tod_to_ns(get_tod_clock_monotonic()); | 66 | return tod_to_ns(get_tod_clock_monotonic()); |
| 67 | } | 67 | } |
| 68 | NOKPROBE_SYMBOL(sched_clock); | ||
| 68 | 69 | ||
| 69 | /* | 70 | /* |
| 70 | * Monotonic_clock - returns # of nanoseconds passed since time_init() | 71 | * Monotonic_clock - returns # of nanoseconds passed since time_init() |
diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c index 9ff5ecba26ab..f081cf1157c3 100644 --- a/arch/s390/kernel/traps.c +++ b/arch/s390/kernel/traps.c | |||
| @@ -49,7 +49,8 @@ static inline void report_user_fault(struct pt_regs *regs, int signr) | |||
| 49 | return; | 49 | return; |
| 50 | if (!printk_ratelimit()) | 50 | if (!printk_ratelimit()) |
| 51 | return; | 51 | return; |
| 52 | printk("User process fault: interruption code 0x%X ", regs->int_code); | 52 | printk("User process fault: interruption code %04x ilc:%d ", |
| 53 | regs->int_code & 0xffff, regs->int_code >> 17); | ||
| 53 | print_vma_addr("in ", regs->psw.addr & PSW_ADDR_INSN); | 54 | print_vma_addr("in ", regs->psw.addr & PSW_ADDR_INSN); |
| 54 | printk("\n"); | 55 | printk("\n"); |
| 55 | show_regs(regs); | 56 | show_regs(regs); |
| @@ -87,16 +88,16 @@ void do_report_trap(struct pt_regs *regs, int si_signo, int si_code, char *str) | |||
| 87 | } | 88 | } |
| 88 | } | 89 | } |
| 89 | 90 | ||
| 90 | static void __kprobes do_trap(struct pt_regs *regs, int si_signo, int si_code, | 91 | static void do_trap(struct pt_regs *regs, int si_signo, int si_code, char *str) |
| 91 | char *str) | ||
| 92 | { | 92 | { |
| 93 | if (notify_die(DIE_TRAP, str, regs, 0, | 93 | if (notify_die(DIE_TRAP, str, regs, 0, |
| 94 | regs->int_code, si_signo) == NOTIFY_STOP) | 94 | regs->int_code, si_signo) == NOTIFY_STOP) |
| 95 | return; | 95 | return; |
| 96 | do_report_trap(regs, si_signo, si_code, str); | 96 | do_report_trap(regs, si_signo, si_code, str); |
| 97 | } | 97 | } |
| 98 | NOKPROBE_SYMBOL(do_trap); | ||
| 98 | 99 | ||
| 99 | void __kprobes do_per_trap(struct pt_regs *regs) | 100 | void do_per_trap(struct pt_regs *regs) |
| 100 | { | 101 | { |
| 101 | siginfo_t info; | 102 | siginfo_t info; |
| 102 | 103 | ||
| @@ -111,6 +112,7 @@ void __kprobes do_per_trap(struct pt_regs *regs) | |||
| 111 | (void __force __user *) current->thread.per_event.address; | 112 | (void __force __user *) current->thread.per_event.address; |
| 112 | force_sig_info(SIGTRAP, &info, current); | 113 | force_sig_info(SIGTRAP, &info, current); |
| 113 | } | 114 | } |
| 115 | NOKPROBE_SYMBOL(do_per_trap); | ||
| 114 | 116 | ||
| 115 | void default_trap_handler(struct pt_regs *regs) | 117 | void default_trap_handler(struct pt_regs *regs) |
| 116 | { | 118 | { |
| @@ -151,8 +153,6 @@ DO_ERROR_INFO(privileged_op, SIGILL, ILL_PRVOPC, | |||
| 151 | "privileged operation") | 153 | "privileged operation") |
| 152 | DO_ERROR_INFO(special_op_exception, SIGILL, ILL_ILLOPN, | 154 | DO_ERROR_INFO(special_op_exception, SIGILL, ILL_ILLOPN, |
| 153 | "special operation exception") | 155 | "special operation exception") |
| 154 | DO_ERROR_INFO(translation_exception, SIGILL, ILL_ILLOPN, | ||
| 155 | "translation exception") | ||
| 156 | 156 | ||
| 157 | #ifdef CONFIG_64BIT | 157 | #ifdef CONFIG_64BIT |
| 158 | DO_ERROR_INFO(transaction_exception, SIGILL, ILL_ILLOPN, | 158 | DO_ERROR_INFO(transaction_exception, SIGILL, ILL_ILLOPN, |
| @@ -179,7 +179,13 @@ static inline void do_fp_trap(struct pt_regs *regs, int fpc) | |||
| 179 | do_trap(regs, SIGFPE, si_code, "floating point exception"); | 179 | do_trap(regs, SIGFPE, si_code, "floating point exception"); |
| 180 | } | 180 | } |
| 181 | 181 | ||
| 182 | void __kprobes illegal_op(struct pt_regs *regs) | 182 | void translation_exception(struct pt_regs *regs) |
| 183 | { | ||
| 184 | /* May never happen. */ | ||
| 185 | die(regs, "Translation exception"); | ||
| 186 | } | ||
| 187 | |||
| 188 | void illegal_op(struct pt_regs *regs) | ||
| 183 | { | 189 | { |
| 184 | siginfo_t info; | 190 | siginfo_t info; |
| 185 | __u8 opcode[6]; | 191 | __u8 opcode[6]; |
| @@ -252,7 +258,7 @@ void __kprobes illegal_op(struct pt_regs *regs) | |||
| 252 | if (signal) | 258 | if (signal) |
| 253 | do_trap(regs, signal, ILL_ILLOPC, "illegal operation"); | 259 | do_trap(regs, signal, ILL_ILLOPC, "illegal operation"); |
| 254 | } | 260 | } |
| 255 | 261 | NOKPROBE_SYMBOL(illegal_op); | |
| 256 | 262 | ||
| 257 | #ifdef CONFIG_MATHEMU | 263 | #ifdef CONFIG_MATHEMU |
| 258 | void specification_exception(struct pt_regs *regs) | 264 | void specification_exception(struct pt_regs *regs) |
| @@ -469,7 +475,7 @@ void space_switch_exception(struct pt_regs *regs) | |||
| 469 | do_trap(regs, SIGILL, ILL_PRVOPC, "space switch event"); | 475 | do_trap(regs, SIGILL, ILL_PRVOPC, "space switch event"); |
| 470 | } | 476 | } |
| 471 | 477 | ||
| 472 | void __kprobes kernel_stack_overflow(struct pt_regs * regs) | 478 | void kernel_stack_overflow(struct pt_regs *regs) |
| 473 | { | 479 | { |
| 474 | bust_spinlocks(1); | 480 | bust_spinlocks(1); |
| 475 | printk("Kernel stack overflow.\n"); | 481 | printk("Kernel stack overflow.\n"); |
| @@ -477,6 +483,7 @@ void __kprobes kernel_stack_overflow(struct pt_regs * regs) | |||
| 477 | bust_spinlocks(0); | 483 | bust_spinlocks(0); |
| 478 | panic("Corrupt kernel stack, can't continue."); | 484 | panic("Corrupt kernel stack, can't continue."); |
| 479 | } | 485 | } |
| 486 | NOKPROBE_SYMBOL(kernel_stack_overflow); | ||
| 480 | 487 | ||
| 481 | void __init trap_init(void) | 488 | void __init trap_init(void) |
| 482 | { | 489 | { |
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 55aade49b6d1..6b049ee75a56 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c | |||
| @@ -271,7 +271,7 @@ static int kvm_s390_mem_control(struct kvm *kvm, struct kvm_device_attr *attr) | |||
| 271 | case KVM_S390_VM_MEM_CLR_CMMA: | 271 | case KVM_S390_VM_MEM_CLR_CMMA: |
| 272 | mutex_lock(&kvm->lock); | 272 | mutex_lock(&kvm->lock); |
| 273 | idx = srcu_read_lock(&kvm->srcu); | 273 | idx = srcu_read_lock(&kvm->srcu); |
| 274 | page_table_reset_pgste(kvm->arch.gmap->mm, 0, TASK_SIZE, false); | 274 | s390_reset_cmma(kvm->arch.gmap->mm); |
| 275 | srcu_read_unlock(&kvm->srcu, idx); | 275 | srcu_read_unlock(&kvm->srcu, idx); |
| 276 | mutex_unlock(&kvm->lock); | 276 | mutex_unlock(&kvm->lock); |
| 277 | ret = 0; | 277 | ret = 0; |
diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c index 72bb2dd8b9cd..f47cb0c6d906 100644 --- a/arch/s390/kvm/priv.c +++ b/arch/s390/kvm/priv.c | |||
| @@ -156,21 +156,25 @@ static int handle_store_cpu_address(struct kvm_vcpu *vcpu) | |||
| 156 | return 0; | 156 | return 0; |
| 157 | } | 157 | } |
| 158 | 158 | ||
| 159 | static void __skey_check_enable(struct kvm_vcpu *vcpu) | 159 | static int __skey_check_enable(struct kvm_vcpu *vcpu) |
| 160 | { | 160 | { |
| 161 | int rc = 0; | ||
| 161 | if (!(vcpu->arch.sie_block->ictl & (ICTL_ISKE | ICTL_SSKE | ICTL_RRBE))) | 162 | if (!(vcpu->arch.sie_block->ictl & (ICTL_ISKE | ICTL_SSKE | ICTL_RRBE))) |
| 162 | return; | 163 | return rc; |
| 163 | 164 | ||
| 164 | s390_enable_skey(); | 165 | rc = s390_enable_skey(); |
| 165 | trace_kvm_s390_skey_related_inst(vcpu); | 166 | trace_kvm_s390_skey_related_inst(vcpu); |
| 166 | vcpu->arch.sie_block->ictl &= ~(ICTL_ISKE | ICTL_SSKE | ICTL_RRBE); | 167 | vcpu->arch.sie_block->ictl &= ~(ICTL_ISKE | ICTL_SSKE | ICTL_RRBE); |
| 168 | return rc; | ||
| 167 | } | 169 | } |
| 168 | 170 | ||
| 169 | 171 | ||
| 170 | static int handle_skey(struct kvm_vcpu *vcpu) | 172 | static int handle_skey(struct kvm_vcpu *vcpu) |
| 171 | { | 173 | { |
| 172 | __skey_check_enable(vcpu); | 174 | int rc = __skey_check_enable(vcpu); |
| 173 | 175 | ||
| 176 | if (rc) | ||
| 177 | return rc; | ||
| 174 | vcpu->stat.instruction_storage_key++; | 178 | vcpu->stat.instruction_storage_key++; |
| 175 | 179 | ||
| 176 | if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) | 180 | if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) |
| @@ -683,7 +687,10 @@ static int handle_pfmf(struct kvm_vcpu *vcpu) | |||
| 683 | } | 687 | } |
| 684 | 688 | ||
| 685 | if (vcpu->run->s.regs.gprs[reg1] & PFMF_SK) { | 689 | if (vcpu->run->s.regs.gprs[reg1] & PFMF_SK) { |
| 686 | __skey_check_enable(vcpu); | 690 | int rc = __skey_check_enable(vcpu); |
| 691 | |||
| 692 | if (rc) | ||
| 693 | return rc; | ||
| 687 | if (set_guest_storage_key(current->mm, useraddr, | 694 | if (set_guest_storage_key(current->mm, useraddr, |
| 688 | vcpu->run->s.regs.gprs[reg1] & PFMF_KEY, | 695 | vcpu->run->s.regs.gprs[reg1] & PFMF_KEY, |
| 689 | vcpu->run->s.regs.gprs[reg1] & PFMF_NQ)) | 696 | vcpu->run->s.regs.gprs[reg1] & PFMF_NQ)) |
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index a2b81d6ce8a5..811937bb90be 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c | |||
| @@ -261,8 +261,8 @@ static inline void report_user_fault(struct pt_regs *regs, long signr) | |||
| 261 | return; | 261 | return; |
| 262 | if (!printk_ratelimit()) | 262 | if (!printk_ratelimit()) |
| 263 | return; | 263 | return; |
| 264 | printk(KERN_ALERT "User process fault: interruption code 0x%X ", | 264 | printk(KERN_ALERT "User process fault: interruption code %04x ilc:%d", |
| 265 | regs->int_code); | 265 | regs->int_code & 0xffff, regs->int_code >> 17); |
| 266 | print_vma_addr(KERN_CONT "in ", regs->psw.addr & PSW_ADDR_INSN); | 266 | print_vma_addr(KERN_CONT "in ", regs->psw.addr & PSW_ADDR_INSN); |
| 267 | printk(KERN_CONT "\n"); | 267 | printk(KERN_CONT "\n"); |
| 268 | printk(KERN_ALERT "failing address: %016lx TEID: %016lx\n", | 268 | printk(KERN_ALERT "failing address: %016lx TEID: %016lx\n", |
| @@ -548,7 +548,7 @@ out: | |||
| 548 | return fault; | 548 | return fault; |
| 549 | } | 549 | } |
| 550 | 550 | ||
| 551 | void __kprobes do_protection_exception(struct pt_regs *regs) | 551 | void do_protection_exception(struct pt_regs *regs) |
| 552 | { | 552 | { |
| 553 | unsigned long trans_exc_code; | 553 | unsigned long trans_exc_code; |
| 554 | int fault; | 554 | int fault; |
| @@ -574,8 +574,9 @@ void __kprobes do_protection_exception(struct pt_regs *regs) | |||
| 574 | if (unlikely(fault)) | 574 | if (unlikely(fault)) |
| 575 | do_fault_error(regs, fault); | 575 | do_fault_error(regs, fault); |
| 576 | } | 576 | } |
| 577 | NOKPROBE_SYMBOL(do_protection_exception); | ||
| 577 | 578 | ||
| 578 | void __kprobes do_dat_exception(struct pt_regs *regs) | 579 | void do_dat_exception(struct pt_regs *regs) |
| 579 | { | 580 | { |
| 580 | int access, fault; | 581 | int access, fault; |
| 581 | 582 | ||
| @@ -584,6 +585,7 @@ void __kprobes do_dat_exception(struct pt_regs *regs) | |||
| 584 | if (unlikely(fault)) | 585 | if (unlikely(fault)) |
| 585 | do_fault_error(regs, fault); | 586 | do_fault_error(regs, fault); |
| 586 | } | 587 | } |
| 588 | NOKPROBE_SYMBOL(do_dat_exception); | ||
| 587 | 589 | ||
| 588 | #ifdef CONFIG_PFAULT | 590 | #ifdef CONFIG_PFAULT |
| 589 | /* | 591 | /* |
diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c index 1b79ca67392f..71c7eff2c89f 100644 --- a/arch/s390/mm/pgtable.c +++ b/arch/s390/mm/pgtable.c | |||
| @@ -18,6 +18,8 @@ | |||
| 18 | #include <linux/rcupdate.h> | 18 | #include <linux/rcupdate.h> |
| 19 | #include <linux/slab.h> | 19 | #include <linux/slab.h> |
| 20 | #include <linux/swapops.h> | 20 | #include <linux/swapops.h> |
| 21 | #include <linux/ksm.h> | ||
| 22 | #include <linux/mman.h> | ||
| 21 | 23 | ||
| 22 | #include <asm/pgtable.h> | 24 | #include <asm/pgtable.h> |
| 23 | #include <asm/pgalloc.h> | 25 | #include <asm/pgalloc.h> |
| @@ -750,8 +752,7 @@ int gmap_ipte_notify(struct gmap *gmap, unsigned long gaddr, unsigned long len) | |||
| 750 | break; | 752 | break; |
| 751 | /* Walk the process page table, lock and get pte pointer */ | 753 | /* Walk the process page table, lock and get pte pointer */ |
| 752 | ptep = get_locked_pte(gmap->mm, addr, &ptl); | 754 | ptep = get_locked_pte(gmap->mm, addr, &ptl); |
| 753 | if (unlikely(!ptep)) | 755 | VM_BUG_ON(!ptep); |
| 754 | continue; | ||
| 755 | /* Set notification bit in the pgste of the pte */ | 756 | /* Set notification bit in the pgste of the pte */ |
| 756 | entry = *ptep; | 757 | entry = *ptep; |
| 757 | if ((pte_val(entry) & (_PAGE_INVALID | _PAGE_PROTECT)) == 0) { | 758 | if ((pte_val(entry) & (_PAGE_INVALID | _PAGE_PROTECT)) == 0) { |
| @@ -761,7 +762,7 @@ int gmap_ipte_notify(struct gmap *gmap, unsigned long gaddr, unsigned long len) | |||
| 761 | gaddr += PAGE_SIZE; | 762 | gaddr += PAGE_SIZE; |
| 762 | len -= PAGE_SIZE; | 763 | len -= PAGE_SIZE; |
| 763 | } | 764 | } |
| 764 | spin_unlock(ptl); | 765 | pte_unmap_unlock(ptep, ptl); |
| 765 | } | 766 | } |
| 766 | up_read(&gmap->mm->mmap_sem); | 767 | up_read(&gmap->mm->mmap_sem); |
| 767 | return rc; | 768 | return rc; |
| @@ -834,99 +835,6 @@ static inline void page_table_free_pgste(unsigned long *table) | |||
| 834 | __free_page(page); | 835 | __free_page(page); |
| 835 | } | 836 | } |
| 836 | 837 | ||
| 837 | static inline unsigned long page_table_reset_pte(struct mm_struct *mm, pmd_t *pmd, | ||
| 838 | unsigned long addr, unsigned long end, bool init_skey) | ||
| 839 | { | ||
| 840 | pte_t *start_pte, *pte; | ||
| 841 | spinlock_t *ptl; | ||
| 842 | pgste_t pgste; | ||
| 843 | |||
| 844 | start_pte = pte_offset_map_lock(mm, pmd, addr, &ptl); | ||
| 845 | pte = start_pte; | ||
| 846 | do { | ||
| 847 | pgste = pgste_get_lock(pte); | ||
| 848 | pgste_val(pgste) &= ~_PGSTE_GPS_USAGE_MASK; | ||
| 849 | if (init_skey) { | ||
| 850 | unsigned long address; | ||
| 851 | |||
| 852 | pgste_val(pgste) &= ~(PGSTE_ACC_BITS | PGSTE_FP_BIT | | ||
| 853 | PGSTE_GR_BIT | PGSTE_GC_BIT); | ||
| 854 | |||
| 855 | /* skip invalid and not writable pages */ | ||
| 856 | if (pte_val(*pte) & _PAGE_INVALID || | ||
| 857 | !(pte_val(*pte) & _PAGE_WRITE)) { | ||
| 858 | pgste_set_unlock(pte, pgste); | ||
| 859 | continue; | ||
| 860 | } | ||
| 861 | |||
| 862 | address = pte_val(*pte) & PAGE_MASK; | ||
| 863 | page_set_storage_key(address, PAGE_DEFAULT_KEY, 1); | ||
| 864 | } | ||
| 865 | pgste_set_unlock(pte, pgste); | ||
| 866 | } while (pte++, addr += PAGE_SIZE, addr != end); | ||
| 867 | pte_unmap_unlock(start_pte, ptl); | ||
| 868 | |||
| 869 | return addr; | ||
| 870 | } | ||
| 871 | |||
| 872 | static inline unsigned long page_table_reset_pmd(struct mm_struct *mm, pud_t *pud, | ||
| 873 | unsigned long addr, unsigned long end, bool init_skey) | ||
| 874 | { | ||
| 875 | unsigned long next; | ||
| 876 | pmd_t *pmd; | ||
| 877 | |||
| 878 | pmd = pmd_offset(pud, addr); | ||
| 879 | do { | ||
| 880 | next = pmd_addr_end(addr, end); | ||
| 881 | if (pmd_none_or_clear_bad(pmd)) | ||
| 882 | continue; | ||
| 883 | next = page_table_reset_pte(mm, pmd, addr, next, init_skey); | ||
| 884 | } while (pmd++, addr = next, addr != end); | ||
| 885 | |||
| 886 | return addr; | ||
| 887 | } | ||
| 888 | |||
| 889 | static inline unsigned long page_table_reset_pud(struct mm_struct *mm, pgd_t *pgd, | ||
| 890 | unsigned long addr, unsigned long end, bool init_skey) | ||
| 891 | { | ||
| 892 | unsigned long next; | ||
| 893 | pud_t *pud; | ||
| 894 | |||
| 895 | pud = pud_offset(pgd, addr); | ||
| 896 | do { | ||
| 897 | next = pud_addr_end(addr, end); | ||
| 898 | if (pud_none_or_clear_bad(pud)) | ||
| 899 | continue; | ||
| 900 | next = page_table_reset_pmd(mm, pud, addr, next, init_skey); | ||
| 901 | } while (pud++, addr = next, addr != end); | ||
| 902 | |||
| 903 | return addr; | ||
| 904 | } | ||
| 905 | |||
| 906 | void page_table_reset_pgste(struct mm_struct *mm, unsigned long start, | ||
| 907 | unsigned long end, bool init_skey) | ||
| 908 | { | ||
| 909 | unsigned long addr, next; | ||
| 910 | pgd_t *pgd; | ||
| 911 | |||
| 912 | down_write(&mm->mmap_sem); | ||
| 913 | if (init_skey && mm_use_skey(mm)) | ||
| 914 | goto out_up; | ||
| 915 | addr = start; | ||
| 916 | pgd = pgd_offset(mm, addr); | ||
| 917 | do { | ||
| 918 | next = pgd_addr_end(addr, end); | ||
| 919 | if (pgd_none_or_clear_bad(pgd)) | ||
| 920 | continue; | ||
| 921 | next = page_table_reset_pud(mm, pgd, addr, next, init_skey); | ||
| 922 | } while (pgd++, addr = next, addr != end); | ||
| 923 | if (init_skey) | ||
| 924 | current->mm->context.use_skey = 1; | ||
| 925 | out_up: | ||
| 926 | up_write(&mm->mmap_sem); | ||
| 927 | } | ||
| 928 | EXPORT_SYMBOL(page_table_reset_pgste); | ||
| 929 | |||
| 930 | int set_guest_storage_key(struct mm_struct *mm, unsigned long addr, | 838 | int set_guest_storage_key(struct mm_struct *mm, unsigned long addr, |
| 931 | unsigned long key, bool nq) | 839 | unsigned long key, bool nq) |
| 932 | { | 840 | { |
| @@ -992,11 +900,6 @@ static inline unsigned long *page_table_alloc_pgste(struct mm_struct *mm) | |||
| 992 | return NULL; | 900 | return NULL; |
| 993 | } | 901 | } |
| 994 | 902 | ||
| 995 | void page_table_reset_pgste(struct mm_struct *mm, unsigned long start, | ||
| 996 | unsigned long end, bool init_skey) | ||
| 997 | { | ||
| 998 | } | ||
| 999 | |||
| 1000 | static inline void page_table_free_pgste(unsigned long *table) | 903 | static inline void page_table_free_pgste(unsigned long *table) |
| 1001 | { | 904 | { |
| 1002 | } | 905 | } |
| @@ -1347,13 +1250,89 @@ EXPORT_SYMBOL_GPL(s390_enable_sie); | |||
| 1347 | * Enable storage key handling from now on and initialize the storage | 1250 | * Enable storage key handling from now on and initialize the storage |
| 1348 | * keys with the default key. | 1251 | * keys with the default key. |
| 1349 | */ | 1252 | */ |
| 1350 | void s390_enable_skey(void) | 1253 | static int __s390_enable_skey(pte_t *pte, unsigned long addr, |
| 1254 | unsigned long next, struct mm_walk *walk) | ||
| 1351 | { | 1255 | { |
| 1352 | page_table_reset_pgste(current->mm, 0, TASK_SIZE, true); | 1256 | unsigned long ptev; |
| 1257 | pgste_t pgste; | ||
| 1258 | |||
| 1259 | pgste = pgste_get_lock(pte); | ||
| 1260 | /* | ||
| 1261 | * Remove all zero page mappings, | ||
| 1262 | * after establishing a policy to forbid zero page mappings | ||
| 1263 | * following faults for that page will get fresh anonymous pages | ||
| 1264 | */ | ||
| 1265 | if (is_zero_pfn(pte_pfn(*pte))) { | ||
| 1266 | ptep_flush_direct(walk->mm, addr, pte); | ||
| 1267 | pte_val(*pte) = _PAGE_INVALID; | ||
| 1268 | } | ||
| 1269 | /* Clear storage key */ | ||
| 1270 | pgste_val(pgste) &= ~(PGSTE_ACC_BITS | PGSTE_FP_BIT | | ||
| 1271 | PGSTE_GR_BIT | PGSTE_GC_BIT); | ||
| 1272 | ptev = pte_val(*pte); | ||
| 1273 | if (!(ptev & _PAGE_INVALID) && (ptev & _PAGE_WRITE)) | ||
| 1274 | page_set_storage_key(ptev & PAGE_MASK, PAGE_DEFAULT_KEY, 1); | ||
| 1275 | pgste_set_unlock(pte, pgste); | ||
| 1276 | return 0; | ||
| 1277 | } | ||
| 1278 | |||
| 1279 | int s390_enable_skey(void) | ||
| 1280 | { | ||
| 1281 | struct mm_walk walk = { .pte_entry = __s390_enable_skey }; | ||
| 1282 | struct mm_struct *mm = current->mm; | ||
| 1283 | struct vm_area_struct *vma; | ||
| 1284 | int rc = 0; | ||
| 1285 | |||
| 1286 | down_write(&mm->mmap_sem); | ||
| 1287 | if (mm_use_skey(mm)) | ||
| 1288 | goto out_up; | ||
| 1289 | |||
| 1290 | mm->context.use_skey = 1; | ||
| 1291 | for (vma = mm->mmap; vma; vma = vma->vm_next) { | ||
| 1292 | if (ksm_madvise(vma, vma->vm_start, vma->vm_end, | ||
| 1293 | MADV_UNMERGEABLE, &vma->vm_flags)) { | ||
| 1294 | mm->context.use_skey = 0; | ||
| 1295 | rc = -ENOMEM; | ||
| 1296 | goto out_up; | ||
| 1297 | } | ||
| 1298 | } | ||
| 1299 | mm->def_flags &= ~VM_MERGEABLE; | ||
| 1300 | |||
| 1301 | walk.mm = mm; | ||
| 1302 | walk_page_range(0, TASK_SIZE, &walk); | ||
| 1303 | |||
| 1304 | out_up: | ||
| 1305 | up_write(&mm->mmap_sem); | ||
| 1306 | return rc; | ||
| 1353 | } | 1307 | } |
| 1354 | EXPORT_SYMBOL_GPL(s390_enable_skey); | 1308 | EXPORT_SYMBOL_GPL(s390_enable_skey); |
| 1355 | 1309 | ||
| 1356 | /* | 1310 | /* |
| 1311 | * Reset CMMA state, make all pages stable again. | ||
| 1312 | */ | ||
| 1313 | static int __s390_reset_cmma(pte_t *pte, unsigned long addr, | ||
| 1314 | unsigned long next, struct mm_walk *walk) | ||
| 1315 | { | ||
| 1316 | pgste_t pgste; | ||
| 1317 | |||
| 1318 | pgste = pgste_get_lock(pte); | ||
| 1319 | pgste_val(pgste) &= ~_PGSTE_GPS_USAGE_MASK; | ||
| 1320 | pgste_set_unlock(pte, pgste); | ||
| 1321 | return 0; | ||
| 1322 | } | ||
| 1323 | |||
| 1324 | void s390_reset_cmma(struct mm_struct *mm) | ||
| 1325 | { | ||
| 1326 | struct mm_walk walk = { .pte_entry = __s390_reset_cmma }; | ||
| 1327 | |||
| 1328 | down_write(&mm->mmap_sem); | ||
| 1329 | walk.mm = mm; | ||
| 1330 | walk_page_range(0, TASK_SIZE, &walk); | ||
| 1331 | up_write(&mm->mmap_sem); | ||
| 1332 | } | ||
| 1333 | EXPORT_SYMBOL_GPL(s390_reset_cmma); | ||
| 1334 | |||
| 1335 | /* | ||
| 1357 | * Test and reset if a guest page is dirty | 1336 | * Test and reset if a guest page is dirty |
| 1358 | */ | 1337 | */ |
| 1359 | bool gmap_test_and_clear_dirty(unsigned long address, struct gmap *gmap) | 1338 | bool gmap_test_and_clear_dirty(unsigned long address, struct gmap *gmap) |
diff --git a/arch/s390/pci/Makefile b/arch/s390/pci/Makefile index a9e1dc4ae442..805d8b29193a 100644 --- a/arch/s390/pci/Makefile +++ b/arch/s390/pci/Makefile | |||
| @@ -3,4 +3,4 @@ | |||
| 3 | # | 3 | # |
| 4 | 4 | ||
| 5 | obj-$(CONFIG_PCI) += pci.o pci_dma.o pci_clp.o pci_sysfs.o \ | 5 | obj-$(CONFIG_PCI) += pci.o pci_dma.o pci_clp.o pci_sysfs.o \ |
| 6 | pci_event.o pci_debug.o pci_insn.o | 6 | pci_event.o pci_debug.o pci_insn.o pci_mmio.o |
diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c index d59c82569750..3290f11ae1d9 100644 --- a/arch/s390/pci/pci.c +++ b/arch/s390/pci/pci.c | |||
| @@ -369,8 +369,7 @@ int arch_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) | |||
| 369 | 369 | ||
| 370 | if (type == PCI_CAP_ID_MSI && nvec > 1) | 370 | if (type == PCI_CAP_ID_MSI && nvec > 1) |
| 371 | return 1; | 371 | return 1; |
| 372 | msi_vecs = min(nvec, ZPCI_MSI_VEC_MAX); | 372 | msi_vecs = min_t(unsigned int, nvec, zdev->max_msi); |
| 373 | msi_vecs = min_t(unsigned int, msi_vecs, CONFIG_PCI_NR_MSI); | ||
| 374 | 373 | ||
| 375 | /* Allocate adapter summary indicator bit */ | 374 | /* Allocate adapter summary indicator bit */ |
| 376 | rc = -EIO; | 375 | rc = -EIO; |
| @@ -474,7 +473,8 @@ static void zpci_map_resources(struct zpci_dev *zdev) | |||
| 474 | len = pci_resource_len(pdev, i); | 473 | len = pci_resource_len(pdev, i); |
| 475 | if (!len) | 474 | if (!len) |
| 476 | continue; | 475 | continue; |
| 477 | pdev->resource[i].start = (resource_size_t) pci_iomap(pdev, i, 0); | 476 | pdev->resource[i].start = |
| 477 | (resource_size_t __force) pci_iomap(pdev, i, 0); | ||
| 478 | pdev->resource[i].end = pdev->resource[i].start + len - 1; | 478 | pdev->resource[i].end = pdev->resource[i].start + len - 1; |
| 479 | } | 479 | } |
| 480 | } | 480 | } |
| @@ -489,7 +489,8 @@ static void zpci_unmap_resources(struct zpci_dev *zdev) | |||
| 489 | len = pci_resource_len(pdev, i); | 489 | len = pci_resource_len(pdev, i); |
| 490 | if (!len) | 490 | if (!len) |
| 491 | continue; | 491 | continue; |
| 492 | pci_iounmap(pdev, (void *) pdev->resource[i].start); | 492 | pci_iounmap(pdev, (void __iomem __force *) |
| 493 | pdev->resource[i].start); | ||
| 493 | } | 494 | } |
| 494 | } | 495 | } |
| 495 | 496 | ||
diff --git a/arch/s390/pci/pci_clp.c b/arch/s390/pci/pci_clp.c index 6e22a247de9b..d6e411ed8b1f 100644 --- a/arch/s390/pci/pci_clp.c +++ b/arch/s390/pci/pci_clp.c | |||
| @@ -62,6 +62,7 @@ static void clp_store_query_pci_fngrp(struct zpci_dev *zdev, | |||
| 62 | zdev->tlb_refresh = response->refresh; | 62 | zdev->tlb_refresh = response->refresh; |
| 63 | zdev->dma_mask = response->dasm; | 63 | zdev->dma_mask = response->dasm; |
| 64 | zdev->msi_addr = response->msia; | 64 | zdev->msi_addr = response->msia; |
| 65 | zdev->max_msi = response->noi; | ||
| 65 | zdev->fmb_update = response->mui; | 66 | zdev->fmb_update = response->mui; |
| 66 | 67 | ||
| 67 | switch (response->version) { | 68 | switch (response->version) { |
diff --git a/arch/s390/pci/pci_debug.c b/arch/s390/pci/pci_debug.c index eec598c5939f..3229a2e570df 100644 --- a/arch/s390/pci/pci_debug.c +++ b/arch/s390/pci/pci_debug.c | |||
| @@ -158,10 +158,7 @@ int __init zpci_debug_init(void) | |||
| 158 | 158 | ||
| 159 | void zpci_debug_exit(void) | 159 | void zpci_debug_exit(void) |
| 160 | { | 160 | { |
| 161 | if (pci_debug_msg_id) | 161 | debug_unregister(pci_debug_msg_id); |
| 162 | debug_unregister(pci_debug_msg_id); | 162 | debug_unregister(pci_debug_err_id); |
| 163 | if (pci_debug_err_id) | ||
| 164 | debug_unregister(pci_debug_err_id); | ||
| 165 | |||
| 166 | debugfs_remove(debugfs_root); | 163 | debugfs_remove(debugfs_root); |
| 167 | } | 164 | } |
diff --git a/arch/s390/pci/pci_mmio.c b/arch/s390/pci/pci_mmio.c new file mode 100644 index 000000000000..62c5ea6d8682 --- /dev/null +++ b/arch/s390/pci/pci_mmio.c | |||
| @@ -0,0 +1,115 @@ | |||
| 1 | /* | ||
| 2 | * Access to PCI I/O memory from user space programs. | ||
| 3 | * | ||
| 4 | * Copyright IBM Corp. 2014 | ||
| 5 | * Author(s): Alexey Ishchuk <aishchuk@linux.vnet.ibm.com> | ||
| 6 | */ | ||
| 7 | #include <linux/kernel.h> | ||
| 8 | #include <linux/syscalls.h> | ||
| 9 | #include <linux/init.h> | ||
| 10 | #include <linux/mm.h> | ||
| 11 | #include <linux/errno.h> | ||
| 12 | #include <linux/pci.h> | ||
| 13 | |||
| 14 | static long get_pfn(unsigned long user_addr, unsigned long access, | ||
| 15 | unsigned long *pfn) | ||
| 16 | { | ||
| 17 | struct vm_area_struct *vma; | ||
| 18 | long ret; | ||
| 19 | |||
| 20 | down_read(¤t->mm->mmap_sem); | ||
| 21 | ret = -EINVAL; | ||
| 22 | vma = find_vma(current->mm, user_addr); | ||
| 23 | if (!vma) | ||
| 24 | goto out; | ||
| 25 | ret = -EACCES; | ||
| 26 | if (!(vma->vm_flags & access)) | ||
| 27 | goto out; | ||
| 28 | ret = follow_pfn(vma, user_addr, pfn); | ||
| 29 | out: | ||
| 30 | up_read(¤t->mm->mmap_sem); | ||
| 31 | return ret; | ||
| 32 | } | ||
| 33 | |||
| 34 | SYSCALL_DEFINE3(s390_pci_mmio_write, unsigned long, mmio_addr, | ||
| 35 | const void __user *, user_buffer, size_t, length) | ||
| 36 | { | ||
| 37 | u8 local_buf[64]; | ||
| 38 | void __iomem *io_addr; | ||
| 39 | void *buf; | ||
| 40 | unsigned long pfn; | ||
| 41 | long ret; | ||
| 42 | |||
| 43 | if (!zpci_is_enabled()) | ||
| 44 | return -ENODEV; | ||
| 45 | |||
| 46 | if (length <= 0 || PAGE_SIZE - (mmio_addr & ~PAGE_MASK) < length) | ||
| 47 | return -EINVAL; | ||
| 48 | if (length > 64) { | ||
| 49 | buf = kmalloc(length, GFP_KERNEL); | ||
| 50 | if (!buf) | ||
| 51 | return -ENOMEM; | ||
| 52 | } else | ||
| 53 | buf = local_buf; | ||
| 54 | |||
| 55 | ret = get_pfn(mmio_addr, VM_WRITE, &pfn); | ||
| 56 | if (ret) | ||
| 57 | goto out; | ||
| 58 | io_addr = (void *)((pfn << PAGE_SHIFT) | (mmio_addr & ~PAGE_MASK)); | ||
| 59 | |||
| 60 | ret = -EFAULT; | ||
| 61 | if ((unsigned long) io_addr < ZPCI_IOMAP_ADDR_BASE) | ||
| 62 | goto out; | ||
| 63 | |||
| 64 | if (copy_from_user(buf, user_buffer, length)) | ||
| 65 | goto out; | ||
| 66 | |||
| 67 | memcpy_toio(io_addr, buf, length); | ||
| 68 | ret = 0; | ||
| 69 | out: | ||
| 70 | if (buf != local_buf) | ||
| 71 | kfree(buf); | ||
| 72 | return ret; | ||
| 73 | } | ||
| 74 | |||
| 75 | SYSCALL_DEFINE3(s390_pci_mmio_read, unsigned long, mmio_addr, | ||
| 76 | void __user *, user_buffer, size_t, length) | ||
| 77 | { | ||
| 78 | u8 local_buf[64]; | ||
| 79 | void __iomem *io_addr; | ||
| 80 | void *buf; | ||
| 81 | unsigned long pfn; | ||
| 82 | long ret; | ||
| 83 | |||
| 84 | if (!zpci_is_enabled()) | ||
| 85 | return -ENODEV; | ||
| 86 | |||
| 87 | if (length <= 0 || PAGE_SIZE - (mmio_addr & ~PAGE_MASK) < length) | ||
| 88 | return -EINVAL; | ||
| 89 | if (length > 64) { | ||
| 90 | buf = kmalloc(length, GFP_KERNEL); | ||
| 91 | if (!buf) | ||
| 92 | return -ENOMEM; | ||
| 93 | } else | ||
| 94 | buf = local_buf; | ||
| 95 | |||
| 96 | ret = get_pfn(mmio_addr, VM_READ, &pfn); | ||
| 97 | if (ret) | ||
| 98 | goto out; | ||
| 99 | io_addr = (void *)((pfn << PAGE_SHIFT) | (mmio_addr & ~PAGE_MASK)); | ||
| 100 | |||
| 101 | ret = -EFAULT; | ||
| 102 | if ((unsigned long) io_addr < ZPCI_IOMAP_ADDR_BASE) | ||
| 103 | goto out; | ||
| 104 | |||
| 105 | memcpy_fromio(buf, io_addr, length); | ||
| 106 | |||
| 107 | if (copy_to_user(user_buffer, buf, length)) | ||
| 108 | goto out; | ||
| 109 | |||
| 110 | ret = 0; | ||
| 111 | out: | ||
| 112 | if (buf != local_buf) | ||
| 113 | kfree(buf); | ||
| 114 | return ret; | ||
| 115 | } | ||
