diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-01-14 16:50:29 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-01-14 16:50:29 -0500 |
commit | 6fb400d36de0926309c8059ad81b0091593c2931 (patch) | |
tree | 05f3a9cbe10e4142e45c705bd4ff736e4c3f4890 | |
parent | fb005c47f7b72edac50342b6af490af09854381b (diff) | |
parent | 8d1a2427d8fc0cb26ee72dfad7ad1033420089a1 (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux
Pull s390 fixes from Martin Schwidefsky:
"Two small performance tweaks, the plumbing for the execveat system
call and a couple of bug fixes"
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux:
s390/uprobes: fix user space PER events
s390/bpf: Fix JMP_JGE_X (A > X) and JMP_JGT_X (A >= X)
s390/bpf: Fix ALU_NEG (A = -A)
s390/mm: avoid using pmd_to_page for !USE_SPLIT_PMD_PTLOCKS
s390/timex: fix get_tod_clock_ext() inline assembly
s390: wire up execveat syscall
s390/kernel: use stnsm 255 instead of stosm 0
s390/vtime: Get rid of redundant WARN_ON
s390/zcrypt: kernel oops at insmod of the z90crypt device driver
-rw-r--r-- | arch/s390/hypfs/hypfs_vm.c | 2 | ||||
-rw-r--r-- | arch/s390/include/asm/irqflags.h | 2 | ||||
-rw-r--r-- | arch/s390/include/asm/timex.h | 10 | ||||
-rw-r--r-- | arch/s390/include/uapi/asm/unistd.h | 3 | ||||
-rw-r--r-- | arch/s390/kernel/syscalls.S | 1 | ||||
-rw-r--r-- | arch/s390/kernel/uprobes.c | 69 | ||||
-rw-r--r-- | arch/s390/kernel/vtime.c | 2 | ||||
-rw-r--r-- | arch/s390/mm/pgtable.c | 5 | ||||
-rw-r--r-- | arch/s390/net/bpf_jit_comp.c | 8 | ||||
-rw-r--r-- | drivers/s390/crypto/ap_bus.c | 10 |
10 files changed, 85 insertions, 27 deletions
diff --git a/arch/s390/hypfs/hypfs_vm.c b/arch/s390/hypfs/hypfs_vm.c index 32040ace00ea..afbe07907c10 100644 --- a/arch/s390/hypfs/hypfs_vm.c +++ b/arch/s390/hypfs/hypfs_vm.c | |||
@@ -231,7 +231,7 @@ failed: | |||
231 | struct dbfs_d2fc_hdr { | 231 | struct dbfs_d2fc_hdr { |
232 | u64 len; /* Length of d2fc buffer without header */ | 232 | u64 len; /* Length of d2fc buffer without header */ |
233 | u16 version; /* Version of header */ | 233 | u16 version; /* Version of header */ |
234 | char tod_ext[16]; /* TOD clock for d2fc */ | 234 | char tod_ext[STORE_CLOCK_EXT_SIZE]; /* TOD clock for d2fc */ |
235 | u64 count; /* Number of VM guests in d2fc buffer */ | 235 | u64 count; /* Number of VM guests in d2fc buffer */ |
236 | char reserved[30]; | 236 | char reserved[30]; |
237 | } __attribute__ ((packed)); | 237 | } __attribute__ ((packed)); |
diff --git a/arch/s390/include/asm/irqflags.h b/arch/s390/include/asm/irqflags.h index 37b9091ab8c0..16aa0c779e07 100644 --- a/arch/s390/include/asm/irqflags.h +++ b/arch/s390/include/asm/irqflags.h | |||
@@ -36,7 +36,7 @@ static inline notrace void __arch_local_irq_ssm(unsigned long flags) | |||
36 | 36 | ||
37 | static inline notrace unsigned long arch_local_save_flags(void) | 37 | static inline notrace unsigned long arch_local_save_flags(void) |
38 | { | 38 | { |
39 | return __arch_local_irq_stosm(0x00); | 39 | return __arch_local_irq_stnsm(0xff); |
40 | } | 40 | } |
41 | 41 | ||
42 | static inline notrace unsigned long arch_local_irq_save(void) | 42 | static inline notrace unsigned long arch_local_irq_save(void) |
diff --git a/arch/s390/include/asm/timex.h b/arch/s390/include/asm/timex.h index 8beee1cceba4..98eb2a579223 100644 --- a/arch/s390/include/asm/timex.h +++ b/arch/s390/include/asm/timex.h | |||
@@ -67,20 +67,22 @@ static inline void local_tick_enable(unsigned long long comp) | |||
67 | set_clock_comparator(S390_lowcore.clock_comparator); | 67 | set_clock_comparator(S390_lowcore.clock_comparator); |
68 | } | 68 | } |
69 | 69 | ||
70 | #define CLOCK_TICK_RATE 1193180 /* Underlying HZ */ | 70 | #define CLOCK_TICK_RATE 1193180 /* Underlying HZ */ |
71 | #define STORE_CLOCK_EXT_SIZE 16 /* stcke writes 16 bytes */ | ||
71 | 72 | ||
72 | typedef unsigned long long cycles_t; | 73 | typedef unsigned long long cycles_t; |
73 | 74 | ||
74 | static inline void get_tod_clock_ext(char clk[16]) | 75 | static inline void get_tod_clock_ext(char *clk) |
75 | { | 76 | { |
76 | typedef struct { char _[sizeof(clk)]; } addrtype; | 77 | typedef struct { char _[STORE_CLOCK_EXT_SIZE]; } addrtype; |
77 | 78 | ||
78 | asm volatile("stcke %0" : "=Q" (*(addrtype *) clk) : : "cc"); | 79 | asm volatile("stcke %0" : "=Q" (*(addrtype *) clk) : : "cc"); |
79 | } | 80 | } |
80 | 81 | ||
81 | static inline unsigned long long get_tod_clock(void) | 82 | static inline unsigned long long get_tod_clock(void) |
82 | { | 83 | { |
83 | unsigned char clk[16]; | 84 | unsigned char clk[STORE_CLOCK_EXT_SIZE]; |
85 | |||
84 | get_tod_clock_ext(clk); | 86 | get_tod_clock_ext(clk); |
85 | return *((unsigned long long *)&clk[1]); | 87 | return *((unsigned long long *)&clk[1]); |
86 | } | 88 | } |
diff --git a/arch/s390/include/uapi/asm/unistd.h b/arch/s390/include/uapi/asm/unistd.h index 2b446cf0cc65..67878af257a0 100644 --- a/arch/s390/include/uapi/asm/unistd.h +++ b/arch/s390/include/uapi/asm/unistd.h | |||
@@ -289,7 +289,8 @@ | |||
289 | #define __NR_bpf 351 | 289 | #define __NR_bpf 351 |
290 | #define __NR_s390_pci_mmio_write 352 | 290 | #define __NR_s390_pci_mmio_write 352 |
291 | #define __NR_s390_pci_mmio_read 353 | 291 | #define __NR_s390_pci_mmio_read 353 |
292 | #define NR_syscalls 354 | 292 | #define __NR_execveat 354 |
293 | #define NR_syscalls 355 | ||
293 | 294 | ||
294 | /* | 295 | /* |
295 | * There are some system calls that are not present on 64 bit, some | 296 | * There are some system calls that are not present on 64 bit, some |
diff --git a/arch/s390/kernel/syscalls.S b/arch/s390/kernel/syscalls.S index a2987243bc76..939ec474b1dd 100644 --- a/arch/s390/kernel/syscalls.S +++ b/arch/s390/kernel/syscalls.S | |||
@@ -362,3 +362,4 @@ 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) | 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) | 364 | SYSCALL(sys_ni_syscall,sys_s390_pci_mmio_read,compat_sys_s390_pci_mmio_read) |
365 | SYSCALL(sys_execveat,sys_execveat,compat_sys_execveat) | ||
diff --git a/arch/s390/kernel/uprobes.c b/arch/s390/kernel/uprobes.c index f6b3cd056ec2..cc7328080b60 100644 --- a/arch/s390/kernel/uprobes.c +++ b/arch/s390/kernel/uprobes.c | |||
@@ -48,6 +48,30 @@ bool arch_uprobe_xol_was_trapped(struct task_struct *tsk) | |||
48 | return false; | 48 | return false; |
49 | } | 49 | } |
50 | 50 | ||
51 | static int check_per_event(unsigned short cause, unsigned long control, | ||
52 | struct pt_regs *regs) | ||
53 | { | ||
54 | if (!(regs->psw.mask & PSW_MASK_PER)) | ||
55 | return 0; | ||
56 | /* user space single step */ | ||
57 | if (control == 0) | ||
58 | return 1; | ||
59 | /* over indication for storage alteration */ | ||
60 | if ((control & 0x20200000) && (cause & 0x2000)) | ||
61 | return 1; | ||
62 | if (cause & 0x8000) { | ||
63 | /* all branches */ | ||
64 | if ((control & 0x80800000) == 0x80000000) | ||
65 | return 1; | ||
66 | /* branch into selected range */ | ||
67 | if (((control & 0x80800000) == 0x80800000) && | ||
68 | regs->psw.addr >= current->thread.per_user.start && | ||
69 | regs->psw.addr <= current->thread.per_user.end) | ||
70 | return 1; | ||
71 | } | ||
72 | return 0; | ||
73 | } | ||
74 | |||
51 | int arch_uprobe_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) | 75 | int arch_uprobe_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) |
52 | { | 76 | { |
53 | int fixup = probe_get_fixup_type(auprobe->insn); | 77 | int fixup = probe_get_fixup_type(auprobe->insn); |
@@ -71,9 +95,13 @@ int arch_uprobe_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) | |||
71 | if (regs->psw.addr - utask->xol_vaddr == ilen) | 95 | if (regs->psw.addr - utask->xol_vaddr == ilen) |
72 | regs->psw.addr = utask->vaddr + ilen; | 96 | regs->psw.addr = utask->vaddr + ilen; |
73 | } | 97 | } |
74 | /* If per tracing was active generate trap */ | 98 | if (check_per_event(current->thread.per_event.cause, |
75 | if (regs->psw.mask & PSW_MASK_PER) | 99 | current->thread.per_user.control, regs)) { |
76 | do_per_trap(regs); | 100 | /* fix per address */ |
101 | current->thread.per_event.address = utask->vaddr; | ||
102 | /* trigger per event */ | ||
103 | set_pt_regs_flag(regs, PIF_PER_TRAP); | ||
104 | } | ||
77 | return 0; | 105 | return 0; |
78 | } | 106 | } |
79 | 107 | ||
@@ -106,6 +134,7 @@ void arch_uprobe_abort_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) | |||
106 | clear_thread_flag(TIF_UPROBE_SINGLESTEP); | 134 | clear_thread_flag(TIF_UPROBE_SINGLESTEP); |
107 | regs->int_code = auprobe->saved_int_code; | 135 | regs->int_code = auprobe->saved_int_code; |
108 | regs->psw.addr = current->utask->vaddr; | 136 | regs->psw.addr = current->utask->vaddr; |
137 | current->thread.per_event.address = current->utask->vaddr; | ||
109 | } | 138 | } |
110 | 139 | ||
111 | unsigned long arch_uretprobe_hijack_return_addr(unsigned long trampoline, | 140 | unsigned long arch_uretprobe_hijack_return_addr(unsigned long trampoline, |
@@ -146,17 +175,20 @@ static void adjust_psw_addr(psw_t *psw, unsigned long len) | |||
146 | __rc; \ | 175 | __rc; \ |
147 | }) | 176 | }) |
148 | 177 | ||
149 | #define emu_store_ril(ptr, input) \ | 178 | #define emu_store_ril(regs, ptr, input) \ |
150 | ({ \ | 179 | ({ \ |
151 | unsigned int mask = sizeof(*(ptr)) - 1; \ | 180 | unsigned int mask = sizeof(*(ptr)) - 1; \ |
181 | __typeof__(ptr) __ptr = (ptr); \ | ||
152 | int __rc = 0; \ | 182 | int __rc = 0; \ |
153 | \ | 183 | \ |
154 | if (!test_facility(34)) \ | 184 | if (!test_facility(34)) \ |
155 | __rc = EMU_ILLEGAL_OP; \ | 185 | __rc = EMU_ILLEGAL_OP; \ |
156 | else if ((u64 __force)ptr & mask) \ | 186 | else if ((u64 __force)__ptr & mask) \ |
157 | __rc = EMU_SPECIFICATION; \ | 187 | __rc = EMU_SPECIFICATION; \ |
158 | else if (put_user(*(input), ptr)) \ | 188 | else if (put_user(*(input), __ptr)) \ |
159 | __rc = EMU_ADDRESSING; \ | 189 | __rc = EMU_ADDRESSING; \ |
190 | if (__rc == 0) \ | ||
191 | sim_stor_event(regs, __ptr, mask + 1); \ | ||
160 | __rc; \ | 192 | __rc; \ |
161 | }) | 193 | }) |
162 | 194 | ||
@@ -198,6 +230,25 @@ union split_register { | |||
198 | }; | 230 | }; |
199 | 231 | ||
200 | /* | 232 | /* |
233 | * If user per registers are setup to trace storage alterations and an | ||
234 | * emulated store took place on a fitting address a user trap is generated. | ||
235 | */ | ||
236 | static void sim_stor_event(struct pt_regs *regs, void *addr, int len) | ||
237 | { | ||
238 | if (!(regs->psw.mask & PSW_MASK_PER)) | ||
239 | return; | ||
240 | if (!(current->thread.per_user.control & PER_EVENT_STORE)) | ||
241 | return; | ||
242 | if ((void *)current->thread.per_user.start > (addr + len)) | ||
243 | return; | ||
244 | if ((void *)current->thread.per_user.end < addr) | ||
245 | return; | ||
246 | current->thread.per_event.address = regs->psw.addr; | ||
247 | current->thread.per_event.cause = PER_EVENT_STORE >> 16; | ||
248 | set_pt_regs_flag(regs, PIF_PER_TRAP); | ||
249 | } | ||
250 | |||
251 | /* | ||
201 | * pc relative instructions are emulated, since parameters may not be | 252 | * pc relative instructions are emulated, since parameters may not be |
202 | * accessible from the xol area due to range limitations. | 253 | * accessible from the xol area due to range limitations. |
203 | */ | 254 | */ |
@@ -249,13 +300,13 @@ static void handle_insn_ril(struct arch_uprobe *auprobe, struct pt_regs *regs) | |||
249 | rc = emu_load_ril((u32 __user *)uptr, &rx->u64); | 300 | rc = emu_load_ril((u32 __user *)uptr, &rx->u64); |
250 | break; | 301 | break; |
251 | case 0x07: /* sthrl */ | 302 | case 0x07: /* sthrl */ |
252 | rc = emu_store_ril((u16 __user *)uptr, &rx->u16[3]); | 303 | rc = emu_store_ril(regs, (u16 __user *)uptr, &rx->u16[3]); |
253 | break; | 304 | break; |
254 | case 0x0b: /* stgrl */ | 305 | case 0x0b: /* stgrl */ |
255 | rc = emu_store_ril((u64 __user *)uptr, &rx->u64); | 306 | rc = emu_store_ril(regs, (u64 __user *)uptr, &rx->u64); |
256 | break; | 307 | break; |
257 | case 0x0f: /* strl */ | 308 | case 0x0f: /* strl */ |
258 | rc = emu_store_ril((u32 __user *)uptr, &rx->u32[1]); | 309 | rc = emu_store_ril(regs, (u32 __user *)uptr, &rx->u32[1]); |
259 | break; | 310 | break; |
260 | } | 311 | } |
261 | break; | 312 | break; |
diff --git a/arch/s390/kernel/vtime.c b/arch/s390/kernel/vtime.c index 7f0089d9a4aa..e34122e539a1 100644 --- a/arch/s390/kernel/vtime.c +++ b/arch/s390/kernel/vtime.c | |||
@@ -128,8 +128,6 @@ void vtime_account_irq_enter(struct task_struct *tsk) | |||
128 | struct thread_info *ti = task_thread_info(tsk); | 128 | struct thread_info *ti = task_thread_info(tsk); |
129 | u64 timer, system; | 129 | u64 timer, system; |
130 | 130 | ||
131 | WARN_ON_ONCE(!irqs_disabled()); | ||
132 | |||
133 | timer = S390_lowcore.last_update_timer; | 131 | timer = S390_lowcore.last_update_timer; |
134 | S390_lowcore.last_update_timer = get_vtimer(); | 132 | S390_lowcore.last_update_timer = get_vtimer(); |
135 | S390_lowcore.system_timer += timer - S390_lowcore.last_update_timer; | 133 | S390_lowcore.system_timer += timer - S390_lowcore.last_update_timer; |
diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c index be99357d238c..3cf8cc03fff6 100644 --- a/arch/s390/mm/pgtable.c +++ b/arch/s390/mm/pgtable.c | |||
@@ -322,11 +322,12 @@ static int gmap_alloc_table(struct gmap *gmap, unsigned long *table, | |||
322 | static unsigned long __gmap_segment_gaddr(unsigned long *entry) | 322 | static unsigned long __gmap_segment_gaddr(unsigned long *entry) |
323 | { | 323 | { |
324 | struct page *page; | 324 | struct page *page; |
325 | unsigned long offset; | 325 | unsigned long offset, mask; |
326 | 326 | ||
327 | offset = (unsigned long) entry / sizeof(unsigned long); | 327 | offset = (unsigned long) entry / sizeof(unsigned long); |
328 | offset = (offset & (PTRS_PER_PMD - 1)) * PMD_SIZE; | 328 | offset = (offset & (PTRS_PER_PMD - 1)) * PMD_SIZE; |
329 | page = pmd_to_page((pmd_t *) entry); | 329 | mask = ~(PTRS_PER_PMD * sizeof(pmd_t) - 1); |
330 | page = virt_to_page((void *)((unsigned long) entry & mask)); | ||
330 | return page->index + offset; | 331 | return page->index + offset; |
331 | } | 332 | } |
332 | 333 | ||
diff --git a/arch/s390/net/bpf_jit_comp.c b/arch/s390/net/bpf_jit_comp.c index c52ac77408ca..524496d47ef5 100644 --- a/arch/s390/net/bpf_jit_comp.c +++ b/arch/s390/net/bpf_jit_comp.c | |||
@@ -431,8 +431,8 @@ static int bpf_jit_insn(struct bpf_jit *jit, struct sock_filter *filter, | |||
431 | EMIT4_DISP(0x88500000, K); | 431 | EMIT4_DISP(0x88500000, K); |
432 | break; | 432 | break; |
433 | case BPF_ALU | BPF_NEG: /* A = -A */ | 433 | case BPF_ALU | BPF_NEG: /* A = -A */ |
434 | /* lnr %r5,%r5 */ | 434 | /* lcr %r5,%r5 */ |
435 | EMIT2(0x1155); | 435 | EMIT2(0x1355); |
436 | break; | 436 | break; |
437 | case BPF_JMP | BPF_JA: /* ip += K */ | 437 | case BPF_JMP | BPF_JA: /* ip += K */ |
438 | offset = addrs[i + K] + jit->start - jit->prg; | 438 | offset = addrs[i + K] + jit->start - jit->prg; |
@@ -502,8 +502,8 @@ branch: if (filter->jt == filter->jf) { | |||
502 | xbranch: /* Emit compare if the branch targets are different */ | 502 | xbranch: /* Emit compare if the branch targets are different */ |
503 | if (filter->jt != filter->jf) { | 503 | if (filter->jt != filter->jf) { |
504 | jit->seen |= SEEN_XREG; | 504 | jit->seen |= SEEN_XREG; |
505 | /* cr %r5,%r12 */ | 505 | /* clr %r5,%r12 */ |
506 | EMIT2(0x195c); | 506 | EMIT2(0x155c); |
507 | } | 507 | } |
508 | goto branch; | 508 | goto branch; |
509 | case BPF_JMP | BPF_JSET | BPF_X: /* ip += (A & X) ? jt : jf */ | 509 | case BPF_JMP | BPF_JSET | BPF_X: /* ip += (A & X) ? jt : jf */ |
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index 91e97ec01418..4d41bf75c233 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c | |||
@@ -1163,9 +1163,13 @@ static inline int ap_test_config_card_id(unsigned int id) | |||
1163 | */ | 1163 | */ |
1164 | static inline int ap_test_config_domain(unsigned int domain) | 1164 | static inline int ap_test_config_domain(unsigned int domain) |
1165 | { | 1165 | { |
1166 | if (!ap_configuration) | 1166 | if (!ap_configuration) /* QCI not supported */ |
1167 | return 1; | 1167 | if (domain < 16) |
1168 | return ap_test_config(ap_configuration->aqm, domain); | 1168 | return 1; /* then domains 0...15 are configured */ |
1169 | else | ||
1170 | return 0; | ||
1171 | else | ||
1172 | return ap_test_config(ap_configuration->aqm, domain); | ||
1169 | } | 1173 | } |
1170 | 1174 | ||
1171 | /** | 1175 | /** |