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 | /** |
