diff options
-rw-r--r-- | arch/s390/include/asm/elf.h | 1 | ||||
-rw-r--r-- | arch/s390/include/asm/lowcore.h | 6 | ||||
-rw-r--r-- | arch/s390/include/asm/processor.h | 6 | ||||
-rw-r--r-- | arch/s390/include/asm/ptrace.h | 8 | ||||
-rw-r--r-- | arch/s390/include/asm/setup.h | 3 | ||||
-rw-r--r-- | arch/s390/kernel/asm-offsets.c | 2 | ||||
-rw-r--r-- | arch/s390/kernel/dis.c | 12 | ||||
-rw-r--r-- | arch/s390/kernel/early.c | 3 | ||||
-rw-r--r-- | arch/s390/kernel/entry64.S | 12 | ||||
-rw-r--r-- | arch/s390/kernel/processor.c | 6 | ||||
-rw-r--r-- | arch/s390/kernel/ptrace.c | 69 | ||||
-rw-r--r-- | arch/s390/kernel/setup.c | 6 | ||||
-rw-r--r-- | arch/s390/kernel/traps.c | 37 | ||||
-rw-r--r-- | include/linux/elf.h | 1 |
14 files changed, 151 insertions, 21 deletions
diff --git a/arch/s390/include/asm/elf.h b/arch/s390/include/asm/elf.h index 9b94a160fe7f..db57594e94b0 100644 --- a/arch/s390/include/asm/elf.h +++ b/arch/s390/include/asm/elf.h | |||
@@ -101,6 +101,7 @@ | |||
101 | #define HWCAP_S390_HPAGE 128 | 101 | #define HWCAP_S390_HPAGE 128 |
102 | #define HWCAP_S390_ETF3EH 256 | 102 | #define HWCAP_S390_ETF3EH 256 |
103 | #define HWCAP_S390_HIGH_GPRS 512 | 103 | #define HWCAP_S390_HIGH_GPRS 512 |
104 | #define HWCAP_S390_TE 1024 | ||
104 | 105 | ||
105 | /* | 106 | /* |
106 | * These are used to set parameters in the core dumps. | 107 | * These are used to set parameters in the core dumps. |
diff --git a/arch/s390/include/asm/lowcore.h b/arch/s390/include/asm/lowcore.h index aab5555bbbda..bbf8141408cd 100644 --- a/arch/s390/include/asm/lowcore.h +++ b/arch/s390/include/asm/lowcore.h | |||
@@ -329,9 +329,13 @@ struct _lowcore { | |||
329 | __u8 pad_0x1338[0x1340-0x1338]; /* 0x1338 */ | 329 | __u8 pad_0x1338[0x1340-0x1338]; /* 0x1338 */ |
330 | __u32 access_regs_save_area[16]; /* 0x1340 */ | 330 | __u32 access_regs_save_area[16]; /* 0x1340 */ |
331 | __u64 cregs_save_area[16]; /* 0x1380 */ | 331 | __u64 cregs_save_area[16]; /* 0x1380 */ |
332 | __u8 pad_0x1400[0x1800-0x1400]; /* 0x1400 */ | ||
333 | |||
334 | /* Transaction abort diagnostic block */ | ||
335 | __u8 pgm_tdb[256]; /* 0x1800 */ | ||
332 | 336 | ||
333 | /* align to the top of the prefix area */ | 337 | /* align to the top of the prefix area */ |
334 | __u8 pad_0x1400[0x2000-0x1400]; /* 0x1400 */ | 338 | __u8 pad_0x1900[0x2000-0x1900]; /* 0x1900 */ |
335 | } __packed; | 339 | } __packed; |
336 | 340 | ||
337 | #endif /* CONFIG_32BIT */ | 341 | #endif /* CONFIG_32BIT */ |
diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h index 0fff583d2c7c..46fe1fbf91c5 100644 --- a/arch/s390/include/asm/processor.h +++ b/arch/s390/include/asm/processor.h | |||
@@ -76,14 +76,20 @@ struct thread_struct { | |||
76 | unsigned long gmap_addr; /* address of last gmap fault. */ | 76 | unsigned long gmap_addr; /* address of last gmap fault. */ |
77 | struct per_regs per_user; /* User specified PER registers */ | 77 | struct per_regs per_user; /* User specified PER registers */ |
78 | struct per_event per_event; /* Cause of the last PER trap */ | 78 | struct per_event per_event; /* Cause of the last PER trap */ |
79 | unsigned long per_flags; /* Flags to control debug behavior */ | ||
79 | /* pfault_wait is used to block the process on a pfault event */ | 80 | /* pfault_wait is used to block the process on a pfault event */ |
80 | unsigned long pfault_wait; | 81 | unsigned long pfault_wait; |
81 | struct list_head list; | 82 | struct list_head list; |
82 | /* cpu runtime instrumentation */ | 83 | /* cpu runtime instrumentation */ |
83 | struct runtime_instr_cb *ri_cb; | 84 | struct runtime_instr_cb *ri_cb; |
84 | int ri_signum; | 85 | int ri_signum; |
86 | #ifdef CONFIG_64BIT | ||
87 | unsigned char trap_tdb[256]; /* Transaction abort diagnose block */ | ||
88 | #endif | ||
85 | }; | 89 | }; |
86 | 90 | ||
91 | #define PER_FLAG_NO_TE 1UL /* Flag to disable transactions. */ | ||
92 | |||
87 | typedef struct thread_struct thread_struct; | 93 | typedef struct thread_struct thread_struct; |
88 | 94 | ||
89 | /* | 95 | /* |
diff --git a/arch/s390/include/asm/ptrace.h b/arch/s390/include/asm/ptrace.h index 5c32bae6b760..ce20a53afe91 100644 --- a/arch/s390/include/asm/ptrace.h +++ b/arch/s390/include/asm/ptrace.h | |||
@@ -361,17 +361,19 @@ struct per_struct_kernel { | |||
361 | unsigned char access_id; /* PER trap access identification */ | 361 | unsigned char access_id; /* PER trap access identification */ |
362 | }; | 362 | }; |
363 | 363 | ||
364 | #define PER_EVENT_MASK 0xE9000000UL | 364 | #define PER_EVENT_MASK 0xEB000000UL |
365 | 365 | ||
366 | #define PER_EVENT_BRANCH 0x80000000UL | 366 | #define PER_EVENT_BRANCH 0x80000000UL |
367 | #define PER_EVENT_IFETCH 0x40000000UL | 367 | #define PER_EVENT_IFETCH 0x40000000UL |
368 | #define PER_EVENT_STORE 0x20000000UL | 368 | #define PER_EVENT_STORE 0x20000000UL |
369 | #define PER_EVENT_STORE_REAL 0x08000000UL | 369 | #define PER_EVENT_STORE_REAL 0x08000000UL |
370 | #define PER_EVENT_TRANSACTION_END 0x02000000UL | ||
370 | #define PER_EVENT_NULLIFICATION 0x01000000UL | 371 | #define PER_EVENT_NULLIFICATION 0x01000000UL |
371 | 372 | ||
372 | #define PER_CONTROL_MASK 0x00a00000UL | 373 | #define PER_CONTROL_MASK 0x00e00000UL |
373 | 374 | ||
374 | #define PER_CONTROL_BRANCH_ADDRESS 0x00800000UL | 375 | #define PER_CONTROL_BRANCH_ADDRESS 0x00800000UL |
376 | #define PER_CONTROL_SUSPENSION 0x00400000UL | ||
375 | #define PER_CONTROL_ALTERATION 0x00200000UL | 377 | #define PER_CONTROL_ALTERATION 0x00200000UL |
376 | 378 | ||
377 | #endif | 379 | #endif |
@@ -485,6 +487,8 @@ typedef struct | |||
485 | #define PTRACE_GET_LAST_BREAK 0x5006 | 487 | #define PTRACE_GET_LAST_BREAK 0x5006 |
486 | #define PTRACE_PEEK_SYSTEM_CALL 0x5007 | 488 | #define PTRACE_PEEK_SYSTEM_CALL 0x5007 |
487 | #define PTRACE_POKE_SYSTEM_CALL 0x5008 | 489 | #define PTRACE_POKE_SYSTEM_CALL 0x5008 |
490 | #define PTRACE_ENABLE_TE 0x5009 | ||
491 | #define PTRACE_DISABLE_TE 0x5010 | ||
488 | 492 | ||
489 | /* | 493 | /* |
490 | * PT_PROT definition is loosely based on hppa bsd definition in | 494 | * PT_PROT definition is loosely based on hppa bsd definition in |
diff --git a/arch/s390/include/asm/setup.h b/arch/s390/include/asm/setup.h index e6859d16ee2d..908f68871393 100644 --- a/arch/s390/include/asm/setup.h +++ b/arch/s390/include/asm/setup.h | |||
@@ -80,6 +80,7 @@ extern unsigned int addressing_mode; | |||
80 | #define MACHINE_FLAG_LPAR (1UL << 12) | 80 | #define MACHINE_FLAG_LPAR (1UL << 12) |
81 | #define MACHINE_FLAG_SPP (1UL << 13) | 81 | #define MACHINE_FLAG_SPP (1UL << 13) |
82 | #define MACHINE_FLAG_TOPOLOGY (1UL << 14) | 82 | #define MACHINE_FLAG_TOPOLOGY (1UL << 14) |
83 | #define MACHINE_FLAG_TE (1UL << 15) | ||
83 | 84 | ||
84 | #define MACHINE_IS_VM (S390_lowcore.machine_flags & MACHINE_FLAG_VM) | 85 | #define MACHINE_IS_VM (S390_lowcore.machine_flags & MACHINE_FLAG_VM) |
85 | #define MACHINE_IS_KVM (S390_lowcore.machine_flags & MACHINE_FLAG_KVM) | 86 | #define MACHINE_IS_KVM (S390_lowcore.machine_flags & MACHINE_FLAG_KVM) |
@@ -98,6 +99,7 @@ extern unsigned int addressing_mode; | |||
98 | #define MACHINE_HAS_PFMF (0) | 99 | #define MACHINE_HAS_PFMF (0) |
99 | #define MACHINE_HAS_SPP (0) | 100 | #define MACHINE_HAS_SPP (0) |
100 | #define MACHINE_HAS_TOPOLOGY (0) | 101 | #define MACHINE_HAS_TOPOLOGY (0) |
102 | #define MACHINE_HAS_TE (0) | ||
101 | #else /* CONFIG_64BIT */ | 103 | #else /* CONFIG_64BIT */ |
102 | #define MACHINE_HAS_IEEE (1) | 104 | #define MACHINE_HAS_IEEE (1) |
103 | #define MACHINE_HAS_CSP (1) | 105 | #define MACHINE_HAS_CSP (1) |
@@ -109,6 +111,7 @@ extern unsigned int addressing_mode; | |||
109 | #define MACHINE_HAS_PFMF (S390_lowcore.machine_flags & MACHINE_FLAG_PFMF) | 111 | #define MACHINE_HAS_PFMF (S390_lowcore.machine_flags & MACHINE_FLAG_PFMF) |
110 | #define MACHINE_HAS_SPP (S390_lowcore.machine_flags & MACHINE_FLAG_SPP) | 112 | #define MACHINE_HAS_SPP (S390_lowcore.machine_flags & MACHINE_FLAG_SPP) |
111 | #define MACHINE_HAS_TOPOLOGY (S390_lowcore.machine_flags & MACHINE_FLAG_TOPOLOGY) | 113 | #define MACHINE_HAS_TOPOLOGY (S390_lowcore.machine_flags & MACHINE_FLAG_TOPOLOGY) |
114 | #define MACHINE_HAS_TE (S390_lowcore.machine_flags & MACHINE_FLAG_TE) | ||
112 | #endif /* CONFIG_64BIT */ | 115 | #endif /* CONFIG_64BIT */ |
113 | 116 | ||
114 | #define ZFCPDUMP_HSA_SIZE (32UL<<20) | 117 | #define ZFCPDUMP_HSA_SIZE (32UL<<20) |
diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c index 45ef1a7b08f9..fface87056eb 100644 --- a/arch/s390/kernel/asm-offsets.c +++ b/arch/s390/kernel/asm-offsets.c | |||
@@ -157,6 +157,8 @@ int main(void) | |||
157 | DEFINE(__LC_LAST_BREAK, offsetof(struct _lowcore, breaking_event_addr)); | 157 | DEFINE(__LC_LAST_BREAK, offsetof(struct _lowcore, breaking_event_addr)); |
158 | DEFINE(__LC_VDSO_PER_CPU, offsetof(struct _lowcore, vdso_per_cpu_data)); | 158 | DEFINE(__LC_VDSO_PER_CPU, offsetof(struct _lowcore, vdso_per_cpu_data)); |
159 | DEFINE(__LC_GMAP, offsetof(struct _lowcore, gmap)); | 159 | DEFINE(__LC_GMAP, offsetof(struct _lowcore, gmap)); |
160 | DEFINE(__LC_PGM_TDB, offsetof(struct _lowcore, pgm_tdb)); | ||
161 | DEFINE(__THREAD_trap_tdb, offsetof(struct task_struct, thread.trap_tdb)); | ||
160 | DEFINE(__GMAP_ASCE, offsetof(struct gmap, asce)); | 162 | DEFINE(__GMAP_ASCE, offsetof(struct gmap, asce)); |
161 | #endif /* CONFIG_32BIT */ | 163 | #endif /* CONFIG_32BIT */ |
162 | return 0; | 164 | return 0; |
diff --git a/arch/s390/kernel/dis.c b/arch/s390/kernel/dis.c index 4bc67db63522..7b6ad271155d 100644 --- a/arch/s390/kernel/dis.c +++ b/arch/s390/kernel/dis.c | |||
@@ -317,6 +317,9 @@ enum { | |||
317 | LONG_INSN_RISBLG, | 317 | LONG_INSN_RISBLG, |
318 | LONG_INSN_RINEXT, | 318 | LONG_INSN_RINEXT, |
319 | LONG_INSN_RIEMIT, | 319 | LONG_INSN_RIEMIT, |
320 | LONG_INSN_TABORT, | ||
321 | LONG_INSN_TBEGIN, | ||
322 | LONG_INSN_TBEGINC, | ||
320 | }; | 323 | }; |
321 | 324 | ||
322 | static char *long_insn_name[] = { | 325 | static char *long_insn_name[] = { |
@@ -334,6 +337,9 @@ static char *long_insn_name[] = { | |||
334 | [LONG_INSN_RISBLG] = "risblk", | 337 | [LONG_INSN_RISBLG] = "risblk", |
335 | [LONG_INSN_RINEXT] = "rinext", | 338 | [LONG_INSN_RINEXT] = "rinext", |
336 | [LONG_INSN_RIEMIT] = "riemit", | 339 | [LONG_INSN_RIEMIT] = "riemit", |
340 | [LONG_INSN_TABORT] = "tabort", | ||
341 | [LONG_INSN_TBEGIN] = "tbegin", | ||
342 | [LONG_INSN_TBEGINC] = "tbeginc", | ||
337 | }; | 343 | }; |
338 | 344 | ||
339 | static struct insn opcode[] = { | 345 | static struct insn opcode[] = { |
@@ -609,6 +615,9 @@ static struct insn opcode_b2[] = { | |||
609 | { "lpswe", 0xb2, INSTR_S_RD }, | 615 | { "lpswe", 0xb2, INSTR_S_RD }, |
610 | { "srnmt", 0xb9, INSTR_S_RD }, | 616 | { "srnmt", 0xb9, INSTR_S_RD }, |
611 | { "lfas", 0xbd, INSTR_S_RD }, | 617 | { "lfas", 0xbd, INSTR_S_RD }, |
618 | { "etndg", 0xec, INSTR_RRE_R0 }, | ||
619 | { { 0, LONG_INSN_TABORT }, 0xfc, INSTR_S_RD }, | ||
620 | { "tend", 0xf8, INSTR_S_RD }, | ||
612 | #endif | 621 | #endif |
613 | { "stidp", 0x02, INSTR_S_RD }, | 622 | { "stidp", 0x02, INSTR_S_RD }, |
614 | { "sck", 0x04, INSTR_S_RD }, | 623 | { "sck", 0x04, INSTR_S_RD }, |
@@ -1165,6 +1174,7 @@ static struct insn opcode_e3[] = { | |||
1165 | { "stfh", 0xcb, INSTR_RXY_RRRD }, | 1174 | { "stfh", 0xcb, INSTR_RXY_RRRD }, |
1166 | { "chf", 0xcd, INSTR_RXY_RRRD }, | 1175 | { "chf", 0xcd, INSTR_RXY_RRRD }, |
1167 | { "clhf", 0xcf, INSTR_RXY_RRRD }, | 1176 | { "clhf", 0xcf, INSTR_RXY_RRRD }, |
1177 | { "ntstg", 0x25, INSTR_RXY_RRRD }, | ||
1168 | #endif | 1178 | #endif |
1169 | { "lrv", 0x1e, INSTR_RXY_RRRD }, | 1179 | { "lrv", 0x1e, INSTR_RXY_RRRD }, |
1170 | { "lrvh", 0x1f, INSTR_RXY_RRRD }, | 1180 | { "lrvh", 0x1f, INSTR_RXY_RRRD }, |
@@ -1188,6 +1198,8 @@ static struct insn opcode_e5[] = { | |||
1188 | { "mvhhi", 0x44, INSTR_SIL_RDI }, | 1198 | { "mvhhi", 0x44, INSTR_SIL_RDI }, |
1189 | { "mvhi", 0x4c, INSTR_SIL_RDI }, | 1199 | { "mvhi", 0x4c, INSTR_SIL_RDI }, |
1190 | { "mvghi", 0x48, INSTR_SIL_RDI }, | 1200 | { "mvghi", 0x48, INSTR_SIL_RDI }, |
1201 | { { 0, LONG_INSN_TBEGIN }, 0x60, INSTR_SIL_RDU }, | ||
1202 | { { 0, LONG_INSN_TBEGINC }, 0x61, INSTR_SIL_RDU }, | ||
1191 | #endif | 1203 | #endif |
1192 | { "lasp", 0x00, INSTR_SSE_RDRD }, | 1204 | { "lasp", 0x00, INSTR_SSE_RDRD }, |
1193 | { "tprot", 0x01, INSTR_SSE_RDRD }, | 1205 | { "tprot", 0x01, INSTR_SSE_RDRD }, |
diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c index e48407962b0f..1345ba452c83 100644 --- a/arch/s390/kernel/early.c +++ b/arch/s390/kernel/early.c | |||
@@ -370,6 +370,8 @@ static __init void detect_machine_facilities(void) | |||
370 | S390_lowcore.machine_flags |= MACHINE_FLAG_MVCOS; | 370 | S390_lowcore.machine_flags |= MACHINE_FLAG_MVCOS; |
371 | if (test_facility(40)) | 371 | if (test_facility(40)) |
372 | S390_lowcore.machine_flags |= MACHINE_FLAG_SPP; | 372 | S390_lowcore.machine_flags |= MACHINE_FLAG_SPP; |
373 | if (test_facility(50) && test_facility(73)) | ||
374 | S390_lowcore.machine_flags |= MACHINE_FLAG_TE; | ||
373 | #endif | 375 | #endif |
374 | } | 376 | } |
375 | 377 | ||
@@ -439,7 +441,6 @@ static void __init setup_boot_command_line(void) | |||
439 | append_to_cmdline(append_ipl_scpdata); | 441 | append_to_cmdline(append_ipl_scpdata); |
440 | } | 442 | } |
441 | 443 | ||
442 | |||
443 | /* | 444 | /* |
444 | * Save ipl parameters, clear bss memory, initialize storage keys | 445 | * Save ipl parameters, clear bss memory, initialize storage keys |
445 | * and create a kernel NSS at startup if the SAVESYS= parm is defined | 446 | * and create a kernel NSS at startup if the SAVESYS= parm is defined |
diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S index 349b7eeb348a..95e9d93d4f41 100644 --- a/arch/s390/kernel/entry64.S +++ b/arch/s390/kernel/entry64.S | |||
@@ -412,6 +412,11 @@ ENTRY(pgm_check_handler) | |||
412 | 1: UPDATE_VTIME %r14,__LC_SYNC_ENTER_TIMER | 412 | 1: UPDATE_VTIME %r14,__LC_SYNC_ENTER_TIMER |
413 | LAST_BREAK %r14 | 413 | LAST_BREAK %r14 |
414 | lg %r15,__LC_KERNEL_STACK | 414 | lg %r15,__LC_KERNEL_STACK |
415 | lg %r14,__TI_task(%r12) | ||
416 | lghi %r13,__LC_PGM_TDB | ||
417 | tm __LC_PGM_ILC+2,0x02 # check for transaction abort | ||
418 | jz 2f | ||
419 | mvc __THREAD_trap_tdb(256,%r14),0(%r13) | ||
415 | 2: aghi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE) | 420 | 2: aghi %r15,-(STACK_FRAME_OVERHEAD + __PT_SIZE) |
416 | la %r11,STACK_FRAME_OVERHEAD(%r15) | 421 | la %r11,STACK_FRAME_OVERHEAD(%r15) |
417 | stmg %r0,%r7,__PT_R0(%r11) | 422 | stmg %r0,%r7,__PT_R0(%r11) |
@@ -422,13 +427,12 @@ ENTRY(pgm_check_handler) | |||
422 | stg %r10,__PT_ARGS(%r11) | 427 | stg %r10,__PT_ARGS(%r11) |
423 | tm __LC_PGM_ILC+3,0x80 # check for per exception | 428 | tm __LC_PGM_ILC+3,0x80 # check for per exception |
424 | jz 0f | 429 | jz 0f |
425 | lg %r1,__TI_task(%r12) | ||
426 | tmhh %r8,0x0001 # kernel per event ? | 430 | tmhh %r8,0x0001 # kernel per event ? |
427 | jz pgm_kprobe | 431 | jz pgm_kprobe |
428 | oi __TI_flags+7(%r12),_TIF_PER_TRAP | 432 | oi __TI_flags+7(%r12),_TIF_PER_TRAP |
429 | mvc __THREAD_per_address(8,%r1),__LC_PER_ADDRESS | 433 | mvc __THREAD_per_address(8,%r14),__LC_PER_ADDRESS |
430 | mvc __THREAD_per_cause(2,%r1),__LC_PER_CAUSE | 434 | mvc __THREAD_per_cause(2,%r14),__LC_PER_CAUSE |
431 | mvc __THREAD_per_paid(1,%r1),__LC_PER_PAID | 435 | mvc __THREAD_per_paid(1,%r14),__LC_PER_PAID |
432 | 0: REENABLE_IRQS | 436 | 0: REENABLE_IRQS |
433 | xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) | 437 | xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) |
434 | larl %r1,pgm_check_table | 438 | larl %r1,pgm_check_table |
diff --git a/arch/s390/kernel/processor.c b/arch/s390/kernel/processor.c index 572d4c9cb33b..22bf8f0ee093 100644 --- a/arch/s390/kernel/processor.c +++ b/arch/s390/kernel/processor.c | |||
@@ -39,9 +39,9 @@ void __cpuinit cpu_init(void) | |||
39 | */ | 39 | */ |
40 | static int show_cpuinfo(struct seq_file *m, void *v) | 40 | static int show_cpuinfo(struct seq_file *m, void *v) |
41 | { | 41 | { |
42 | static const char *hwcap_str[10] = { | 42 | static const char *hwcap_str[11] = { |
43 | "esan3", "zarch", "stfle", "msa", "ldisp", "eimm", "dfp", | 43 | "esan3", "zarch", "stfle", "msa", "ldisp", "eimm", "dfp", |
44 | "edat", "etf3eh", "highgprs" | 44 | "edat", "etf3eh", "highgprs", "te" |
45 | }; | 45 | }; |
46 | unsigned long n = (unsigned long) v - 1; | 46 | unsigned long n = (unsigned long) v - 1; |
47 | int i; | 47 | int i; |
@@ -54,7 +54,7 @@ static int show_cpuinfo(struct seq_file *m, void *v) | |||
54 | num_online_cpus(), loops_per_jiffy/(500000/HZ), | 54 | num_online_cpus(), loops_per_jiffy/(500000/HZ), |
55 | (loops_per_jiffy/(5000/HZ))%100); | 55 | (loops_per_jiffy/(5000/HZ))%100); |
56 | seq_puts(m, "features\t: "); | 56 | seq_puts(m, "features\t: "); |
57 | for (i = 0; i < 10; i++) | 57 | for (i = 0; i < 11; i++) |
58 | if (hwcap_str[i] && (elf_hwcap & (1UL << i))) | 58 | if (hwcap_str[i] && (elf_hwcap & (1UL << i))) |
59 | seq_printf(m, "%s ", hwcap_str[i]); | 59 | seq_printf(m, "%s ", hwcap_str[i]); |
60 | seq_puts(m, "\n"); | 60 | seq_puts(m, "\n"); |
diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c index e4be113fbac6..b817cc5e49ae 100644 --- a/arch/s390/kernel/ptrace.c +++ b/arch/s390/kernel/ptrace.c | |||
@@ -42,6 +42,7 @@ enum s390_regset { | |||
42 | REGSET_GENERAL, | 42 | REGSET_GENERAL, |
43 | REGSET_FP, | 43 | REGSET_FP, |
44 | REGSET_LAST_BREAK, | 44 | REGSET_LAST_BREAK, |
45 | REGSET_TDB, | ||
45 | REGSET_SYSTEM_CALL, | 46 | REGSET_SYSTEM_CALL, |
46 | REGSET_GENERAL_EXTENDED, | 47 | REGSET_GENERAL_EXTENDED, |
47 | }; | 48 | }; |
@@ -52,6 +53,21 @@ void update_per_regs(struct task_struct *task) | |||
52 | struct thread_struct *thread = &task->thread; | 53 | struct thread_struct *thread = &task->thread; |
53 | struct per_regs old, new; | 54 | struct per_regs old, new; |
54 | 55 | ||
56 | /* Take care of the enable/disable of transactional execution. */ | ||
57 | if (MACHINE_HAS_TE) { | ||
58 | unsigned long cr0, cr0_new; | ||
59 | |||
60 | __ctl_store(cr0, 0, 0); | ||
61 | /* set or clear transaction execution bits 8 and 9. */ | ||
62 | if (task->thread.per_flags & PER_FLAG_NO_TE) | ||
63 | cr0_new = cr0 & ~(3UL << 54); | ||
64 | else | ||
65 | cr0_new = cr0 | (3UL << 54); | ||
66 | /* Only load control register 0 if necessary. */ | ||
67 | if (cr0 != cr0_new) | ||
68 | __ctl_load(cr0_new, 0, 0); | ||
69 | } | ||
70 | |||
55 | /* Copy user specified PER registers */ | 71 | /* Copy user specified PER registers */ |
56 | new.control = thread->per_user.control; | 72 | new.control = thread->per_user.control; |
57 | new.start = thread->per_user.start; | 73 | new.start = thread->per_user.start; |
@@ -60,6 +76,10 @@ void update_per_regs(struct task_struct *task) | |||
60 | /* merge TIF_SINGLE_STEP into user specified PER registers. */ | 76 | /* merge TIF_SINGLE_STEP into user specified PER registers. */ |
61 | if (test_tsk_thread_flag(task, TIF_SINGLE_STEP)) { | 77 | if (test_tsk_thread_flag(task, TIF_SINGLE_STEP)) { |
62 | new.control |= PER_EVENT_IFETCH; | 78 | new.control |= PER_EVENT_IFETCH; |
79 | #ifdef CONFIG_64BIT | ||
80 | new.control |= PER_CONTROL_SUSPENSION; | ||
81 | new.control |= PER_EVENT_TRANSACTION_END; | ||
82 | #endif | ||
63 | new.start = 0; | 83 | new.start = 0; |
64 | new.end = PSW_ADDR_INSN; | 84 | new.end = PSW_ADDR_INSN; |
65 | } | 85 | } |
@@ -100,6 +120,7 @@ void ptrace_disable(struct task_struct *task) | |||
100 | memset(&task->thread.per_event, 0, sizeof(task->thread.per_event)); | 120 | memset(&task->thread.per_event, 0, sizeof(task->thread.per_event)); |
101 | clear_tsk_thread_flag(task, TIF_SINGLE_STEP); | 121 | clear_tsk_thread_flag(task, TIF_SINGLE_STEP); |
102 | clear_tsk_thread_flag(task, TIF_PER_TRAP); | 122 | clear_tsk_thread_flag(task, TIF_PER_TRAP); |
123 | task->thread.per_flags = 0; | ||
103 | } | 124 | } |
104 | 125 | ||
105 | #ifndef CONFIG_64BIT | 126 | #ifndef CONFIG_64BIT |
@@ -416,6 +437,16 @@ long arch_ptrace(struct task_struct *child, long request, | |||
416 | put_user(task_thread_info(child)->last_break, | 437 | put_user(task_thread_info(child)->last_break, |
417 | (unsigned long __user *) data); | 438 | (unsigned long __user *) data); |
418 | return 0; | 439 | return 0; |
440 | case PTRACE_ENABLE_TE: | ||
441 | if (!MACHINE_HAS_TE) | ||
442 | return -EIO; | ||
443 | child->thread.per_flags &= ~PER_FLAG_NO_TE; | ||
444 | return 0; | ||
445 | case PTRACE_DISABLE_TE: | ||
446 | if (!MACHINE_HAS_TE) | ||
447 | return -EIO; | ||
448 | child->thread.per_flags |= PER_FLAG_NO_TE; | ||
449 | return 0; | ||
419 | default: | 450 | default: |
420 | /* Removing high order bit from addr (only for 31 bit). */ | 451 | /* Removing high order bit from addr (only for 31 bit). */ |
421 | addr &= PSW_ADDR_INSN; | 452 | addr &= PSW_ADDR_INSN; |
@@ -903,6 +934,28 @@ static int s390_last_break_set(struct task_struct *target, | |||
903 | return 0; | 934 | return 0; |
904 | } | 935 | } |
905 | 936 | ||
937 | static int s390_tdb_get(struct task_struct *target, | ||
938 | const struct user_regset *regset, | ||
939 | unsigned int pos, unsigned int count, | ||
940 | void *kbuf, void __user *ubuf) | ||
941 | { | ||
942 | struct pt_regs *regs = task_pt_regs(target); | ||
943 | unsigned char *data; | ||
944 | |||
945 | if (!(regs->int_code & 0x200)) | ||
946 | return -ENODATA; | ||
947 | data = target->thread.trap_tdb; | ||
948 | return user_regset_copyout(&pos, &count, &kbuf, &ubuf, data, 0, 256); | ||
949 | } | ||
950 | |||
951 | static int s390_tdb_set(struct task_struct *target, | ||
952 | const struct user_regset *regset, | ||
953 | unsigned int pos, unsigned int count, | ||
954 | const void *kbuf, const void __user *ubuf) | ||
955 | { | ||
956 | return 0; | ||
957 | } | ||
958 | |||
906 | #endif | 959 | #endif |
907 | 960 | ||
908 | static int s390_system_call_get(struct task_struct *target, | 961 | static int s390_system_call_get(struct task_struct *target, |
@@ -951,6 +1004,14 @@ static const struct user_regset s390_regsets[] = { | |||
951 | .get = s390_last_break_get, | 1004 | .get = s390_last_break_get, |
952 | .set = s390_last_break_set, | 1005 | .set = s390_last_break_set, |
953 | }, | 1006 | }, |
1007 | [REGSET_TDB] = { | ||
1008 | .core_note_type = NT_S390_TDB, | ||
1009 | .n = 1, | ||
1010 | .size = 256, | ||
1011 | .align = 1, | ||
1012 | .get = s390_tdb_get, | ||
1013 | .set = s390_tdb_set, | ||
1014 | }, | ||
954 | #endif | 1015 | #endif |
955 | [REGSET_SYSTEM_CALL] = { | 1016 | [REGSET_SYSTEM_CALL] = { |
956 | .core_note_type = NT_S390_SYSTEM_CALL, | 1017 | .core_note_type = NT_S390_SYSTEM_CALL, |
@@ -1148,6 +1209,14 @@ static const struct user_regset s390_compat_regsets[] = { | |||
1148 | .get = s390_compat_last_break_get, | 1209 | .get = s390_compat_last_break_get, |
1149 | .set = s390_compat_last_break_set, | 1210 | .set = s390_compat_last_break_set, |
1150 | }, | 1211 | }, |
1212 | [REGSET_TDB] = { | ||
1213 | .core_note_type = NT_S390_TDB, | ||
1214 | .n = 1, | ||
1215 | .size = 256, | ||
1216 | .align = 1, | ||
1217 | .get = s390_tdb_get, | ||
1218 | .set = s390_tdb_set, | ||
1219 | }, | ||
1151 | [REGSET_SYSTEM_CALL] = { | 1220 | [REGSET_SYSTEM_CALL] = { |
1152 | .core_note_type = NT_S390_SYSTEM_CALL, | 1221 | .core_note_type = NT_S390_SYSTEM_CALL, |
1153 | .n = 1, | 1222 | .n = 1, |
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 40b57693de38..7b59fff85f2f 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c | |||
@@ -980,6 +980,12 @@ static void __init setup_hwcaps(void) | |||
980 | * HWCAP_S390_HIGH_GPRS is bit 9. | 980 | * HWCAP_S390_HIGH_GPRS is bit 9. |
981 | */ | 981 | */ |
982 | elf_hwcap |= HWCAP_S390_HIGH_GPRS; | 982 | elf_hwcap |= HWCAP_S390_HIGH_GPRS; |
983 | |||
984 | /* | ||
985 | * Transactional execution support HWCAP_S390_TE is bit 10. | ||
986 | */ | ||
987 | if (test_facility(50) && test_facility(73)) | ||
988 | elf_hwcap |= HWCAP_S390_TE; | ||
983 | #endif | 989 | #endif |
984 | 990 | ||
985 | get_cpu_id(&cpu_id); | 991 | get_cpu_id(&cpu_id); |
diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c index 01775c04a90e..29af52628e8b 100644 --- a/arch/s390/kernel/traps.c +++ b/arch/s390/kernel/traps.c | |||
@@ -57,6 +57,23 @@ static int kstack_depth_to_print = 12; | |||
57 | static int kstack_depth_to_print = 20; | 57 | static int kstack_depth_to_print = 20; |
58 | #endif /* CONFIG_64BIT */ | 58 | #endif /* CONFIG_64BIT */ |
59 | 59 | ||
60 | static inline void __user *get_trap_ip(struct pt_regs *regs) | ||
61 | { | ||
62 | #ifdef CONFIG_64BIT | ||
63 | unsigned long address; | ||
64 | |||
65 | if (regs->int_code & 0x200) | ||
66 | address = *(unsigned long *)(current->thread.trap_tdb + 24); | ||
67 | else | ||
68 | address = regs->psw.addr; | ||
69 | return (void __user *) | ||
70 | ((address - (regs->int_code >> 16)) & PSW_ADDR_INSN); | ||
71 | #else | ||
72 | return (void __user *) | ||
73 | ((regs->psw.addr - (regs->int_code >> 16)) & PSW_ADDR_INSN); | ||
74 | #endif | ||
75 | } | ||
76 | |||
60 | /* | 77 | /* |
61 | * For show_trace we have tree different stack to consider: | 78 | * For show_trace we have tree different stack to consider: |
62 | * - the panic stack which is used if the kernel stack has overflown | 79 | * - the panic stack which is used if the kernel stack has overflown |
@@ -285,12 +302,6 @@ int is_valid_bugaddr(unsigned long addr) | |||
285 | return 1; | 302 | return 1; |
286 | } | 303 | } |
287 | 304 | ||
288 | static inline void __user *get_psw_address(struct pt_regs *regs) | ||
289 | { | ||
290 | return (void __user *) | ||
291 | ((regs->psw.addr - (regs->int_code >> 16)) & PSW_ADDR_INSN); | ||
292 | } | ||
293 | |||
294 | static void __kprobes do_trap(struct pt_regs *regs, | 305 | static void __kprobes do_trap(struct pt_regs *regs, |
295 | int si_signo, int si_code, char *str) | 306 | int si_signo, int si_code, char *str) |
296 | { | 307 | { |
@@ -304,7 +315,7 @@ static void __kprobes do_trap(struct pt_regs *regs, | |||
304 | info.si_signo = si_signo; | 315 | info.si_signo = si_signo; |
305 | info.si_errno = 0; | 316 | info.si_errno = 0; |
306 | info.si_code = si_code; | 317 | info.si_code = si_code; |
307 | info.si_addr = get_psw_address(regs); | 318 | info.si_addr = get_trap_ip(regs); |
308 | force_sig_info(si_signo, &info, current); | 319 | force_sig_info(si_signo, &info, current); |
309 | report_user_fault(regs, si_signo); | 320 | report_user_fault(regs, si_signo); |
310 | } else { | 321 | } else { |
@@ -381,6 +392,11 @@ DO_ERROR_INFO(special_op_exception, SIGILL, ILL_ILLOPN, | |||
381 | DO_ERROR_INFO(translation_exception, SIGILL, ILL_ILLOPN, | 392 | DO_ERROR_INFO(translation_exception, SIGILL, ILL_ILLOPN, |
382 | "translation exception") | 393 | "translation exception") |
383 | 394 | ||
395 | #ifdef CONFIG_64BIT | ||
396 | DO_ERROR_INFO(transaction_exception, SIGILL, ILL_ILLOPN, | ||
397 | "transaction constraint exception") | ||
398 | #endif | ||
399 | |||
384 | static inline void do_fp_trap(struct pt_regs *regs, int fpc) | 400 | static inline void do_fp_trap(struct pt_regs *regs, int fpc) |
385 | { | 401 | { |
386 | int si_code = 0; | 402 | int si_code = 0; |
@@ -408,7 +424,7 @@ static void __kprobes illegal_op(struct pt_regs *regs) | |||
408 | __u16 __user *location; | 424 | __u16 __user *location; |
409 | int signal = 0; | 425 | int signal = 0; |
410 | 426 | ||
411 | location = get_psw_address(regs); | 427 | location = get_trap_ip(regs); |
412 | 428 | ||
413 | if (user_mode(regs)) { | 429 | if (user_mode(regs)) { |
414 | if (get_user(*((__u16 *) opcode), (__u16 __user *) location)) | 430 | if (get_user(*((__u16 *) opcode), (__u16 __user *) location)) |
@@ -476,7 +492,7 @@ void specification_exception(struct pt_regs *regs) | |||
476 | __u16 __user *location = NULL; | 492 | __u16 __user *location = NULL; |
477 | int signal = 0; | 493 | int signal = 0; |
478 | 494 | ||
479 | location = (__u16 __user *) get_psw_address(regs); | 495 | location = (__u16 __user *) get_trap_ip(regs); |
480 | 496 | ||
481 | if (user_mode(regs)) { | 497 | if (user_mode(regs)) { |
482 | get_user(*((__u16 *) opcode), location); | 498 | get_user(*((__u16 *) opcode), location); |
@@ -525,7 +541,7 @@ static void data_exception(struct pt_regs *regs) | |||
525 | __u16 __user *location; | 541 | __u16 __user *location; |
526 | int signal = 0; | 542 | int signal = 0; |
527 | 543 | ||
528 | location = get_psw_address(regs); | 544 | location = get_trap_ip(regs); |
529 | 545 | ||
530 | if (MACHINE_HAS_IEEE) | 546 | if (MACHINE_HAS_IEEE) |
531 | asm volatile("stfpc %0" : "=m" (current->thread.fp_regs.fpc)); | 547 | asm volatile("stfpc %0" : "=m" (current->thread.fp_regs.fpc)); |
@@ -641,6 +657,7 @@ void __init trap_init(void) | |||
641 | pgm_check_table[0x12] = &translation_exception; | 657 | pgm_check_table[0x12] = &translation_exception; |
642 | pgm_check_table[0x13] = &special_op_exception; | 658 | pgm_check_table[0x13] = &special_op_exception; |
643 | #ifdef CONFIG_64BIT | 659 | #ifdef CONFIG_64BIT |
660 | pgm_check_table[0x18] = &transaction_exception; | ||
644 | pgm_check_table[0x38] = &do_asce_exception; | 661 | pgm_check_table[0x38] = &do_asce_exception; |
645 | pgm_check_table[0x39] = &do_dat_exception; | 662 | pgm_check_table[0x39] = &do_dat_exception; |
646 | pgm_check_table[0x3A] = &do_dat_exception; | 663 | pgm_check_table[0x3A] = &do_dat_exception; |
diff --git a/include/linux/elf.h b/include/linux/elf.h index 999b4f52e8e5..f930b1a390ab 100644 --- a/include/linux/elf.h +++ b/include/linux/elf.h | |||
@@ -387,6 +387,7 @@ typedef struct elf64_shdr { | |||
387 | #define NT_S390_PREFIX 0x305 /* s390 prefix register */ | 387 | #define NT_S390_PREFIX 0x305 /* s390 prefix register */ |
388 | #define NT_S390_LAST_BREAK 0x306 /* s390 breaking event address */ | 388 | #define NT_S390_LAST_BREAK 0x306 /* s390 breaking event address */ |
389 | #define NT_S390_SYSTEM_CALL 0x307 /* s390 system call restart data */ | 389 | #define NT_S390_SYSTEM_CALL 0x307 /* s390 system call restart data */ |
390 | #define NT_S390_TDB 0x308 /* s390 transaction diagnostic block */ | ||
390 | #define NT_ARM_VFP 0x400 /* ARM VFP/NEON registers */ | 391 | #define NT_ARM_VFP 0x400 /* ARM VFP/NEON registers */ |
391 | 392 | ||
392 | 393 | ||