diff options
author | Jan Beulich <jbeulich@novell.com> | 2006-01-11 16:43:00 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-01-11 22:01:13 -0500 |
commit | b556b35e98ad2b9174a7a623d152cdf412d1a999 (patch) | |
tree | 10f99d70e719fba811dee85d2f3a82b26d7a4ce8 /arch/x86_64/kernel/traps.c | |
parent | ed8388a5d9db0445322f86ee8381b0f04a2057ee (diff) |
[PATCH] x86_64: Move int 3 handler to debug stack and allow to increase it.
This
- switches the INT3 handler to run on an IST stack (to cope with
breakpoints set by a kernel debugger on places where the kernel's
%gs base hasn't been set up, yet); the IST stack used is shared with
the INT1 handler's
[AK: this also allows setting a kprobe on the interrupt/exception entry
points]
- allows nesting of INT1/INT3 handlers so that one can, with a kernel
debugger, debug (at least) the user-mode portions of the INT1/INT3
handling; the nesting isn't actively enabled here since a kernel-
debugger-free kernel doesn't need it
Signed-Off-By: Jan Beulich <jbeulich@novell.com>
Signed-off-by: Andi Kleen <ak@suse.de>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/x86_64/kernel/traps.c')
-rw-r--r-- | arch/x86_64/kernel/traps.c | 35 |
1 files changed, 32 insertions, 3 deletions
diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c index bd71ddac0dc5..1a9094dab682 100644 --- a/arch/x86_64/kernel/traps.c +++ b/arch/x86_64/kernel/traps.c | |||
@@ -121,19 +121,31 @@ int printk_address(unsigned long address) | |||
121 | static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack, | 121 | static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack, |
122 | unsigned *usedp, const char **idp) | 122 | unsigned *usedp, const char **idp) |
123 | { | 123 | { |
124 | static const char ids[N_EXCEPTION_STACKS][8] = { | 124 | static char ids[][8] = { |
125 | [DEBUG_STACK - 1] = "#DB", | 125 | [DEBUG_STACK - 1] = "#DB", |
126 | [NMI_STACK - 1] = "NMI", | 126 | [NMI_STACK - 1] = "NMI", |
127 | [DOUBLEFAULT_STACK - 1] = "#DF", | 127 | [DOUBLEFAULT_STACK - 1] = "#DF", |
128 | [STACKFAULT_STACK - 1] = "#SS", | 128 | [STACKFAULT_STACK - 1] = "#SS", |
129 | [MCE_STACK - 1] = "#MC", | 129 | [MCE_STACK - 1] = "#MC", |
130 | #if DEBUG_STKSZ > EXCEPTION_STKSZ | ||
131 | [N_EXCEPTION_STACKS ... N_EXCEPTION_STACKS + DEBUG_STKSZ / EXCEPTION_STKSZ - 2] = "#DB[?]" | ||
132 | #endif | ||
130 | }; | 133 | }; |
131 | unsigned k; | 134 | unsigned k; |
132 | 135 | ||
133 | for (k = 0; k < N_EXCEPTION_STACKS; k++) { | 136 | for (k = 0; k < N_EXCEPTION_STACKS; k++) { |
134 | unsigned long end; | 137 | unsigned long end; |
135 | 138 | ||
136 | end = per_cpu(init_tss, cpu).ist[k]; | 139 | switch (k + 1) { |
140 | #if DEBUG_STKSZ > EXCEPTION_STKSZ | ||
141 | case DEBUG_STACK: | ||
142 | end = cpu_pda[cpu].debugstack + DEBUG_STKSZ; | ||
143 | break; | ||
144 | #endif | ||
145 | default: | ||
146 | end = per_cpu(init_tss, cpu).ist[k]; | ||
147 | break; | ||
148 | } | ||
137 | if (stack >= end) | 149 | if (stack >= end) |
138 | continue; | 150 | continue; |
139 | if (stack >= end - EXCEPTION_STKSZ) { | 151 | if (stack >= end - EXCEPTION_STKSZ) { |
@@ -143,6 +155,22 @@ static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack, | |||
143 | *idp = ids[k]; | 155 | *idp = ids[k]; |
144 | return (unsigned long *)end; | 156 | return (unsigned long *)end; |
145 | } | 157 | } |
158 | #if DEBUG_STKSZ > EXCEPTION_STKSZ | ||
159 | if (k == DEBUG_STACK - 1 && stack >= end - DEBUG_STKSZ) { | ||
160 | unsigned j = N_EXCEPTION_STACKS - 1; | ||
161 | |||
162 | do { | ||
163 | ++j; | ||
164 | end -= EXCEPTION_STKSZ; | ||
165 | ids[j][4] = '1' + (j - N_EXCEPTION_STACKS); | ||
166 | } while (stack < end - EXCEPTION_STKSZ); | ||
167 | if (*usedp & (1U << j)) | ||
168 | break; | ||
169 | *usedp |= 1U << j; | ||
170 | *idp = ids[j]; | ||
171 | return (unsigned long *)end; | ||
172 | } | ||
173 | #endif | ||
146 | } | 174 | } |
147 | return NULL; | 175 | return NULL; |
148 | } | 176 | } |
@@ -613,6 +641,7 @@ asmlinkage void default_do_nmi(struct pt_regs *regs) | |||
613 | io_check_error(reason, regs); | 641 | io_check_error(reason, regs); |
614 | } | 642 | } |
615 | 643 | ||
644 | /* runs on IST stack. */ | ||
616 | asmlinkage void __kprobes do_int3(struct pt_regs * regs, long error_code) | 645 | asmlinkage void __kprobes do_int3(struct pt_regs * regs, long error_code) |
617 | { | 646 | { |
618 | if (notify_die(DIE_INT3, "int3", regs, error_code, 3, SIGTRAP) == NOTIFY_STOP) { | 647 | if (notify_die(DIE_INT3, "int3", regs, error_code, 3, SIGTRAP) == NOTIFY_STOP) { |
@@ -894,7 +923,7 @@ void __init trap_init(void) | |||
894 | set_intr_gate(0,÷_error); | 923 | set_intr_gate(0,÷_error); |
895 | set_intr_gate_ist(1,&debug,DEBUG_STACK); | 924 | set_intr_gate_ist(1,&debug,DEBUG_STACK); |
896 | set_intr_gate_ist(2,&nmi,NMI_STACK); | 925 | set_intr_gate_ist(2,&nmi,NMI_STACK); |
897 | set_system_gate(3,&int3); | 926 | set_system_gate_ist(3,&int3,DEBUG_STACK); /* int3 can be called from all */ |
898 | set_system_gate(4,&overflow); /* int4 can be called from all */ | 927 | set_system_gate(4,&overflow); /* int4 can be called from all */ |
899 | set_intr_gate(5,&bounds); | 928 | set_intr_gate(5,&bounds); |
900 | set_intr_gate(6,&invalid_op); | 929 | set_intr_gate(6,&invalid_op); |