diff options
author | Heiko Carstens <heiko.carstens@de.ibm.com> | 2012-10-18 12:10:06 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2012-11-23 05:14:25 -0500 |
commit | b01a37a749916ef1765e4d65dee8b43fde8407b8 (patch) | |
tree | 421be52e05d061fa356a64b9cbabbfee7ebc68c7 /arch/s390 | |
parent | f7817968d03df390d77d3af1b13298efa4f31047 (diff) |
s390/traps: preinitialize program check table
Preinitialize the program check table, so we can put it into the
read-only data section.
Also use only four byte entries for the table, since each program
check handler resides within the first 2GB. Therefore this reduces
the size of the table by 50% on 64 bit builds.
Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'arch/s390')
-rw-r--r-- | arch/s390/kernel/Makefile | 2 | ||||
-rw-r--r-- | arch/s390/kernel/entry.h | 21 | ||||
-rw-r--r-- | arch/s390/kernel/entry64.S | 4 | ||||
-rw-r--r-- | arch/s390/kernel/pgm_check.S | 152 | ||||
-rw-r--r-- | arch/s390/kernel/traps.c | 52 |
5 files changed, 182 insertions, 49 deletions
diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index 4da52fe31743..2ac311ef5c9b 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile | |||
@@ -23,7 +23,7 @@ CFLAGS_sysinfo.o += -Iinclude/math-emu -Iarch/s390/math-emu -w | |||
23 | obj-y := bitmap.o traps.o time.o process.o base.o early.o setup.o vtime.o \ | 23 | obj-y := bitmap.o traps.o time.o process.o base.o early.o setup.o vtime.o \ |
24 | processor.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o nmi.o \ | 24 | processor.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o nmi.o \ |
25 | debug.o irq.o ipl.o dis.o diag.o mem_detect.o sclp.o vdso.o \ | 25 | debug.o irq.o ipl.o dis.o diag.o mem_detect.o sclp.o vdso.o \ |
26 | sysinfo.o jump_label.o lgr.o os_info.o machine_kexec.o | 26 | sysinfo.o jump_label.o lgr.o os_info.o machine_kexec.o pgm_check.o |
27 | 27 | ||
28 | obj-y += $(if $(CONFIG_64BIT),entry64.o,entry.o) | 28 | obj-y += $(if $(CONFIG_64BIT),entry64.o,entry.o) |
29 | obj-y += $(if $(CONFIG_64BIT),reipl64.o,reipl.o) | 29 | obj-y += $(if $(CONFIG_64BIT),reipl64.o,reipl.o) |
diff --git a/arch/s390/kernel/entry.h b/arch/s390/kernel/entry.h index d0d3f69a7346..80ebb985f3b9 100644 --- a/arch/s390/kernel/entry.h +++ b/arch/s390/kernel/entry.h | |||
@@ -6,7 +6,6 @@ | |||
6 | #include <asm/ptrace.h> | 6 | #include <asm/ptrace.h> |
7 | #include <asm/cputime.h> | 7 | #include <asm/cputime.h> |
8 | 8 | ||
9 | extern void (*pgm_check_table[128])(struct pt_regs *); | ||
10 | extern void *restart_stack; | 9 | extern void *restart_stack; |
11 | 10 | ||
12 | void system_call(void); | 11 | void system_call(void); |
@@ -25,6 +24,26 @@ void do_protection_exception(struct pt_regs *regs); | |||
25 | void do_dat_exception(struct pt_regs *regs); | 24 | void do_dat_exception(struct pt_regs *regs); |
26 | void do_asce_exception(struct pt_regs *regs); | 25 | void do_asce_exception(struct pt_regs *regs); |
27 | 26 | ||
27 | void addressing_exception(struct pt_regs *regs); | ||
28 | void data_exception(struct pt_regs *regs); | ||
29 | void default_trap_handler(struct pt_regs *regs); | ||
30 | void divide_exception(struct pt_regs *regs); | ||
31 | void execute_exception(struct pt_regs *regs); | ||
32 | void hfp_divide_exception(struct pt_regs *regs); | ||
33 | void hfp_overflow_exception(struct pt_regs *regs); | ||
34 | void hfp_significance_exception(struct pt_regs *regs); | ||
35 | void hfp_sqrt_exception(struct pt_regs *regs); | ||
36 | void hfp_underflow_exception(struct pt_regs *regs); | ||
37 | void illegal_op(struct pt_regs *regs); | ||
38 | void operand_exception(struct pt_regs *regs); | ||
39 | void overflow_exception(struct pt_regs *regs); | ||
40 | void privileged_op(struct pt_regs *regs); | ||
41 | void space_switch_exception(struct pt_regs *regs); | ||
42 | void special_op_exception(struct pt_regs *regs); | ||
43 | void specification_exception(struct pt_regs *regs); | ||
44 | void transaction_exception(struct pt_regs *regs); | ||
45 | void translation_exception(struct pt_regs *regs); | ||
46 | |||
28 | void do_per_trap(struct pt_regs *regs); | 47 | void do_per_trap(struct pt_regs *regs); |
29 | void syscall_trace(struct pt_regs *regs, int entryexit); | 48 | void syscall_trace(struct pt_regs *regs, int entryexit); |
30 | void kernel_stack_overflow(struct pt_regs * regs); | 49 | void kernel_stack_overflow(struct pt_regs * regs); |
diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S index 07d8de353984..e42842a3072b 100644 --- a/arch/s390/kernel/entry64.S +++ b/arch/s390/kernel/entry64.S | |||
@@ -429,9 +429,9 @@ ENTRY(pgm_check_handler) | |||
429 | larl %r1,pgm_check_table | 429 | larl %r1,pgm_check_table |
430 | llgh %r10,__PT_INT_CODE+2(%r11) | 430 | llgh %r10,__PT_INT_CODE+2(%r11) |
431 | nill %r10,0x007f | 431 | nill %r10,0x007f |
432 | sll %r10,3 | 432 | sll %r10,2 |
433 | je sysc_return | 433 | je sysc_return |
434 | lg %r1,0(%r10,%r1) # load address of handler routine | 434 | lgf %r1,0(%r10,%r1) # load address of handler routine |
435 | lgr %r2,%r11 # pass pointer to pt_regs | 435 | lgr %r2,%r11 # pass pointer to pt_regs |
436 | basr %r14,%r1 # branch to interrupt-handler | 436 | basr %r14,%r1 # branch to interrupt-handler |
437 | j sysc_return | 437 | j sysc_return |
diff --git a/arch/s390/kernel/pgm_check.S b/arch/s390/kernel/pgm_check.S new file mode 100644 index 000000000000..14bdecb61923 --- /dev/null +++ b/arch/s390/kernel/pgm_check.S | |||
@@ -0,0 +1,152 @@ | |||
1 | /* | ||
2 | * Program check table. | ||
3 | * | ||
4 | * Copyright IBM Corp. 2012 | ||
5 | */ | ||
6 | |||
7 | #include <linux/linkage.h> | ||
8 | |||
9 | #ifdef CONFIG_32BIT | ||
10 | #define PGM_CHECK_64BIT(handler) .long default_trap_handler | ||
11 | #else | ||
12 | #define PGM_CHECK_64BIT(handler) .long handler | ||
13 | #endif | ||
14 | |||
15 | #define PGM_CHECK(handler) .long handler | ||
16 | #define PGM_CHECK_DEFAULT PGM_CHECK(default_trap_handler) | ||
17 | |||
18 | /* | ||
19 | * The program check table contains exactly 128 (0x00-0x7f) entries. Each | ||
20 | * line defines the 31 and/or 64 bit function to be called corresponding | ||
21 | * to the program check interruption code. | ||
22 | */ | ||
23 | .section .rodata, "a" | ||
24 | ENTRY(pgm_check_table) | ||
25 | PGM_CHECK_DEFAULT /* 00 */ | ||
26 | PGM_CHECK(illegal_op) /* 01 */ | ||
27 | PGM_CHECK(privileged_op) /* 02 */ | ||
28 | PGM_CHECK(execute_exception) /* 03 */ | ||
29 | PGM_CHECK(do_protection_exception) /* 04 */ | ||
30 | PGM_CHECK(addressing_exception) /* 05 */ | ||
31 | PGM_CHECK(specification_exception) /* 06 */ | ||
32 | PGM_CHECK(data_exception) /* 07 */ | ||
33 | PGM_CHECK(overflow_exception) /* 08 */ | ||
34 | PGM_CHECK(divide_exception) /* 09 */ | ||
35 | PGM_CHECK(overflow_exception) /* 0a */ | ||
36 | PGM_CHECK(divide_exception) /* 0b */ | ||
37 | PGM_CHECK(hfp_overflow_exception) /* 0c */ | ||
38 | PGM_CHECK(hfp_underflow_exception) /* 0d */ | ||
39 | PGM_CHECK(hfp_significance_exception) /* 0e */ | ||
40 | PGM_CHECK(hfp_divide_exception) /* 0f */ | ||
41 | PGM_CHECK(do_dat_exception) /* 10 */ | ||
42 | PGM_CHECK(do_dat_exception) /* 11 */ | ||
43 | PGM_CHECK(translation_exception) /* 12 */ | ||
44 | PGM_CHECK(special_op_exception) /* 13 */ | ||
45 | PGM_CHECK_DEFAULT /* 14 */ | ||
46 | PGM_CHECK(operand_exception) /* 15 */ | ||
47 | PGM_CHECK_DEFAULT /* 16 */ | ||
48 | PGM_CHECK_DEFAULT /* 17 */ | ||
49 | PGM_CHECK_64BIT(transaction_exception) /* 18 */ | ||
50 | PGM_CHECK_DEFAULT /* 19 */ | ||
51 | PGM_CHECK_DEFAULT /* 1a */ | ||
52 | PGM_CHECK_DEFAULT /* 1b */ | ||
53 | PGM_CHECK(space_switch_exception) /* 1c */ | ||
54 | PGM_CHECK(hfp_sqrt_exception) /* 1d */ | ||
55 | PGM_CHECK_DEFAULT /* 1e */ | ||
56 | PGM_CHECK_DEFAULT /* 1f */ | ||
57 | PGM_CHECK_DEFAULT /* 20 */ | ||
58 | PGM_CHECK_DEFAULT /* 21 */ | ||
59 | PGM_CHECK_DEFAULT /* 22 */ | ||
60 | PGM_CHECK_DEFAULT /* 23 */ | ||
61 | PGM_CHECK_DEFAULT /* 24 */ | ||
62 | PGM_CHECK_DEFAULT /* 25 */ | ||
63 | PGM_CHECK_DEFAULT /* 26 */ | ||
64 | PGM_CHECK_DEFAULT /* 27 */ | ||
65 | PGM_CHECK_DEFAULT /* 28 */ | ||
66 | PGM_CHECK_DEFAULT /* 29 */ | ||
67 | PGM_CHECK_DEFAULT /* 2a */ | ||
68 | PGM_CHECK_DEFAULT /* 2b */ | ||
69 | PGM_CHECK_DEFAULT /* 2c */ | ||
70 | PGM_CHECK_DEFAULT /* 2d */ | ||
71 | PGM_CHECK_DEFAULT /* 2e */ | ||
72 | PGM_CHECK_DEFAULT /* 2f */ | ||
73 | PGM_CHECK_DEFAULT /* 30 */ | ||
74 | PGM_CHECK_DEFAULT /* 31 */ | ||
75 | PGM_CHECK_DEFAULT /* 32 */ | ||
76 | PGM_CHECK_DEFAULT /* 33 */ | ||
77 | PGM_CHECK_DEFAULT /* 34 */ | ||
78 | PGM_CHECK_DEFAULT /* 35 */ | ||
79 | PGM_CHECK_DEFAULT /* 36 */ | ||
80 | PGM_CHECK_DEFAULT /* 37 */ | ||
81 | PGM_CHECK_64BIT(do_asce_exception) /* 38 */ | ||
82 | PGM_CHECK_64BIT(do_dat_exception) /* 39 */ | ||
83 | PGM_CHECK_64BIT(do_dat_exception) /* 3a */ | ||
84 | PGM_CHECK_64BIT(do_dat_exception) /* 3b */ | ||
85 | PGM_CHECK_DEFAULT /* 3c */ | ||
86 | PGM_CHECK_DEFAULT /* 3d */ | ||
87 | PGM_CHECK_DEFAULT /* 3e */ | ||
88 | PGM_CHECK_DEFAULT /* 3f */ | ||
89 | PGM_CHECK_DEFAULT /* 40 */ | ||
90 | PGM_CHECK_DEFAULT /* 41 */ | ||
91 | PGM_CHECK_DEFAULT /* 42 */ | ||
92 | PGM_CHECK_DEFAULT /* 43 */ | ||
93 | PGM_CHECK_DEFAULT /* 44 */ | ||
94 | PGM_CHECK_DEFAULT /* 45 */ | ||
95 | PGM_CHECK_DEFAULT /* 46 */ | ||
96 | PGM_CHECK_DEFAULT /* 47 */ | ||
97 | PGM_CHECK_DEFAULT /* 48 */ | ||
98 | PGM_CHECK_DEFAULT /* 49 */ | ||
99 | PGM_CHECK_DEFAULT /* 4a */ | ||
100 | PGM_CHECK_DEFAULT /* 4b */ | ||
101 | PGM_CHECK_DEFAULT /* 4c */ | ||
102 | PGM_CHECK_DEFAULT /* 4d */ | ||
103 | PGM_CHECK_DEFAULT /* 4e */ | ||
104 | PGM_CHECK_DEFAULT /* 4f */ | ||
105 | PGM_CHECK_DEFAULT /* 50 */ | ||
106 | PGM_CHECK_DEFAULT /* 51 */ | ||
107 | PGM_CHECK_DEFAULT /* 52 */ | ||
108 | PGM_CHECK_DEFAULT /* 53 */ | ||
109 | PGM_CHECK_DEFAULT /* 54 */ | ||
110 | PGM_CHECK_DEFAULT /* 55 */ | ||
111 | PGM_CHECK_DEFAULT /* 56 */ | ||
112 | PGM_CHECK_DEFAULT /* 57 */ | ||
113 | PGM_CHECK_DEFAULT /* 58 */ | ||
114 | PGM_CHECK_DEFAULT /* 59 */ | ||
115 | PGM_CHECK_DEFAULT /* 5a */ | ||
116 | PGM_CHECK_DEFAULT /* 5b */ | ||
117 | PGM_CHECK_DEFAULT /* 5c */ | ||
118 | PGM_CHECK_DEFAULT /* 5d */ | ||
119 | PGM_CHECK_DEFAULT /* 5e */ | ||
120 | PGM_CHECK_DEFAULT /* 5f */ | ||
121 | PGM_CHECK_DEFAULT /* 60 */ | ||
122 | PGM_CHECK_DEFAULT /* 61 */ | ||
123 | PGM_CHECK_DEFAULT /* 62 */ | ||
124 | PGM_CHECK_DEFAULT /* 63 */ | ||
125 | PGM_CHECK_DEFAULT /* 64 */ | ||
126 | PGM_CHECK_DEFAULT /* 65 */ | ||
127 | PGM_CHECK_DEFAULT /* 66 */ | ||
128 | PGM_CHECK_DEFAULT /* 67 */ | ||
129 | PGM_CHECK_DEFAULT /* 68 */ | ||
130 | PGM_CHECK_DEFAULT /* 69 */ | ||
131 | PGM_CHECK_DEFAULT /* 6a */ | ||
132 | PGM_CHECK_DEFAULT /* 6b */ | ||
133 | PGM_CHECK_DEFAULT /* 6c */ | ||
134 | PGM_CHECK_DEFAULT /* 6d */ | ||
135 | PGM_CHECK_DEFAULT /* 6e */ | ||
136 | PGM_CHECK_DEFAULT /* 6f */ | ||
137 | PGM_CHECK_DEFAULT /* 70 */ | ||
138 | PGM_CHECK_DEFAULT /* 71 */ | ||
139 | PGM_CHECK_DEFAULT /* 72 */ | ||
140 | PGM_CHECK_DEFAULT /* 73 */ | ||
141 | PGM_CHECK_DEFAULT /* 74 */ | ||
142 | PGM_CHECK_DEFAULT /* 75 */ | ||
143 | PGM_CHECK_DEFAULT /* 76 */ | ||
144 | PGM_CHECK_DEFAULT /* 77 */ | ||
145 | PGM_CHECK_DEFAULT /* 78 */ | ||
146 | PGM_CHECK_DEFAULT /* 79 */ | ||
147 | PGM_CHECK_DEFAULT /* 7a */ | ||
148 | PGM_CHECK_DEFAULT /* 7b */ | ||
149 | PGM_CHECK_DEFAULT /* 7c */ | ||
150 | PGM_CHECK_DEFAULT /* 7d */ | ||
151 | PGM_CHECK_DEFAULT /* 7e */ | ||
152 | PGM_CHECK_DEFAULT /* 7f */ | ||
diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c index 3d2b0fa37db0..70ecfc5fe8f0 100644 --- a/arch/s390/kernel/traps.c +++ b/arch/s390/kernel/traps.c | |||
@@ -41,8 +41,6 @@ | |||
41 | #include <asm/ipl.h> | 41 | #include <asm/ipl.h> |
42 | #include "entry.h" | 42 | #include "entry.h" |
43 | 43 | ||
44 | void (*pgm_check_table[128])(struct pt_regs *regs); | ||
45 | |||
46 | int show_unhandled_signals = 1; | 44 | int show_unhandled_signals = 1; |
47 | 45 | ||
48 | #define stack_pointer ({ void **sp; asm("la %0,0(15)" : "=&d" (sp)); sp; }) | 46 | #define stack_pointer ({ void **sp; asm("la %0,0(15)" : "=&d" (sp)); sp; }) |
@@ -350,7 +348,7 @@ void __kprobes do_per_trap(struct pt_regs *regs) | |||
350 | force_sig_info(SIGTRAP, &info, current); | 348 | force_sig_info(SIGTRAP, &info, current); |
351 | } | 349 | } |
352 | 350 | ||
353 | static void default_trap_handler(struct pt_regs *regs) | 351 | void default_trap_handler(struct pt_regs *regs) |
354 | { | 352 | { |
355 | if (user_mode(regs)) { | 353 | if (user_mode(regs)) { |
356 | report_user_fault(regs, SIGSEGV); | 354 | report_user_fault(regs, SIGSEGV); |
@@ -360,9 +358,9 @@ static void default_trap_handler(struct pt_regs *regs) | |||
360 | } | 358 | } |
361 | 359 | ||
362 | #define DO_ERROR_INFO(name, signr, sicode, str) \ | 360 | #define DO_ERROR_INFO(name, signr, sicode, str) \ |
363 | static void name(struct pt_regs *regs) \ | 361 | void name(struct pt_regs *regs) \ |
364 | { \ | 362 | { \ |
365 | do_trap(regs, signr, sicode, str); \ | 363 | do_trap(regs, signr, sicode, str); \ |
366 | } | 364 | } |
367 | 365 | ||
368 | DO_ERROR_INFO(addressing_exception, SIGILL, ILL_ILLADR, | 366 | DO_ERROR_INFO(addressing_exception, SIGILL, ILL_ILLADR, |
@@ -417,7 +415,7 @@ static inline void do_fp_trap(struct pt_regs *regs, int fpc) | |||
417 | do_trap(regs, SIGFPE, si_code, "floating point exception"); | 415 | do_trap(regs, SIGFPE, si_code, "floating point exception"); |
418 | } | 416 | } |
419 | 417 | ||
420 | static void __kprobes illegal_op(struct pt_regs *regs) | 418 | void __kprobes illegal_op(struct pt_regs *regs) |
421 | { | 419 | { |
422 | siginfo_t info; | 420 | siginfo_t info; |
423 | __u8 opcode[6]; | 421 | __u8 opcode[6]; |
@@ -536,7 +534,7 @@ DO_ERROR_INFO(specification_exception, SIGILL, ILL_ILLOPN, | |||
536 | "specification exception"); | 534 | "specification exception"); |
537 | #endif | 535 | #endif |
538 | 536 | ||
539 | static void data_exception(struct pt_regs *regs) | 537 | void data_exception(struct pt_regs *regs) |
540 | { | 538 | { |
541 | __u16 __user *location; | 539 | __u16 __user *location; |
542 | int signal = 0; | 540 | int signal = 0; |
@@ -611,7 +609,7 @@ static void data_exception(struct pt_regs *regs) | |||
611 | do_trap(regs, signal, ILL_ILLOPN, "data exception"); | 609 | do_trap(regs, signal, ILL_ILLOPN, "data exception"); |
612 | } | 610 | } |
613 | 611 | ||
614 | static void space_switch_exception(struct pt_regs *regs) | 612 | void space_switch_exception(struct pt_regs *regs) |
615 | { | 613 | { |
616 | /* Set user psw back to home space mode. */ | 614 | /* Set user psw back to home space mode. */ |
617 | if (user_mode(regs)) | 615 | if (user_mode(regs)) |
@@ -629,43 +627,7 @@ void __kprobes kernel_stack_overflow(struct pt_regs * regs) | |||
629 | panic("Corrupt kernel stack, can't continue."); | 627 | panic("Corrupt kernel stack, can't continue."); |
630 | } | 628 | } |
631 | 629 | ||
632 | /* init is done in lowcore.S and head.S */ | ||
633 | |||
634 | void __init trap_init(void) | 630 | void __init trap_init(void) |
635 | { | 631 | { |
636 | int i; | ||
637 | |||
638 | for (i = 0; i < 128; i++) | ||
639 | pgm_check_table[i] = &default_trap_handler; | ||
640 | pgm_check_table[1] = &illegal_op; | ||
641 | pgm_check_table[2] = &privileged_op; | ||
642 | pgm_check_table[3] = &execute_exception; | ||
643 | pgm_check_table[4] = &do_protection_exception; | ||
644 | pgm_check_table[5] = &addressing_exception; | ||
645 | pgm_check_table[6] = &specification_exception; | ||
646 | pgm_check_table[7] = &data_exception; | ||
647 | pgm_check_table[8] = &overflow_exception; | ||
648 | pgm_check_table[9] = ÷_exception; | ||
649 | pgm_check_table[0x0A] = &overflow_exception; | ||
650 | pgm_check_table[0x0B] = ÷_exception; | ||
651 | pgm_check_table[0x0C] = &hfp_overflow_exception; | ||
652 | pgm_check_table[0x0D] = &hfp_underflow_exception; | ||
653 | pgm_check_table[0x0E] = &hfp_significance_exception; | ||
654 | pgm_check_table[0x0F] = &hfp_divide_exception; | ||
655 | pgm_check_table[0x10] = &do_dat_exception; | ||
656 | pgm_check_table[0x11] = &do_dat_exception; | ||
657 | pgm_check_table[0x12] = &translation_exception; | ||
658 | pgm_check_table[0x13] = &special_op_exception; | ||
659 | #ifdef CONFIG_64BIT | ||
660 | pgm_check_table[0x18] = &transaction_exception; | ||
661 | pgm_check_table[0x38] = &do_asce_exception; | ||
662 | pgm_check_table[0x39] = &do_dat_exception; | ||
663 | pgm_check_table[0x3A] = &do_dat_exception; | ||
664 | pgm_check_table[0x3B] = &do_dat_exception; | ||
665 | #endif /* CONFIG_64BIT */ | ||
666 | pgm_check_table[0x15] = &operand_exception; | ||
667 | pgm_check_table[0x1C] = &space_switch_exception; | ||
668 | pgm_check_table[0x1D] = &hfp_sqrt_exception; | ||
669 | /* Enable machine checks early. */ | ||
670 | local_mcck_enable(); | 632 | local_mcck_enable(); |
671 | } | 633 | } |