aboutsummaryrefslogtreecommitdiff
path: root/arch/i386
diff options
context:
space:
mode:
Diffstat (limited to 'arch/i386')
-rw-r--r--arch/i386/cpu/interrupts.c23
-rw-r--r--arch/i386/include/asm/interrupt.h2
-rw-r--r--arch/i386/include/asm/ptrace.h24
3 files changed, 45 insertions, 4 deletions
diff --git a/arch/i386/cpu/interrupts.c b/arch/i386/cpu/interrupts.c
index 47a7a2901..e4d0868cd 100644
--- a/arch/i386/cpu/interrupts.c
+++ b/arch/i386/cpu/interrupts.c
@@ -104,7 +104,7 @@ static inline unsigned long get_debugreg(int regno)
return val;
}
-void dump_regs(struct pt_regs *regs)
+void dump_regs(struct irq_regs *regs)
{
unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L;
unsigned long d0, d1, d2, d3, d6, d7;
@@ -225,7 +225,7 @@ int disable_interrupts(void)
}
/* IRQ Low-Level Service Routine */
-void irq_llsr(struct pt_regs *regs)
+void irq_llsr(struct irq_regs *regs)
{
/*
* For detailed description of each exception, refer to:
@@ -234,7 +234,7 @@ void irq_llsr(struct pt_regs *regs)
* Order Number: 253665-029US, November 2008
* Table 6-1. Exceptions and Interrupts
*/
- switch (regs->orig_eax) {
+ switch (regs->irq_id) {
case 0x00:
printf("Divide Error (Division by zero)\n");
dump_regs(regs);
@@ -340,7 +340,7 @@ void irq_llsr(struct pt_regs *regs)
default:
/* Hardware or User IRQ */
- do_irq(regs->orig_eax);
+ do_irq(regs->irq_id);
}
}
@@ -352,17 +352,30 @@ void irq_llsr(struct pt_regs *regs)
* Interrupt entries are now very small (a push and a jump) but they are
* now slower (all registers pushed on stack which provides complete
* crash dumps in the low level handlers
+ *
+ * Interrupt Entry Point:
+ * - Interrupt has caused eflags, CS and EIP to be pushed
+ * - Interrupt Vector Handler has pushed orig_eax
+ * - pt_regs.esp needs to be adjusted by 40 bytes:
+ * 12 bytes pushed by CPU (EFLAGSF, CS, EIP)
+ * 4 bytes pushed by vector handler (irq_id)
+ * 24 bytes pushed before SP (SS, GS, FS, ES, DS, EAX)
+ * NOTE: Only longs are pushed on/popped off the stack!
*/
asm(".globl irq_common_entry\n" \
".hidden irq_common_entry\n" \
".type irq_common_entry, @function\n" \
"irq_common_entry:\n" \
"cld\n" \
+ "pushl %ss\n" \
"pushl %gs\n" \
"pushl %fs\n" \
"pushl %es\n" \
"pushl %ds\n" \
"pushl %eax\n" \
+ "movl %esp, %eax\n" \
+ "addl $40, %eax\n" \
+ "pushl %eax\n" \
"pushl %ebp\n" \
"pushl %edi\n" \
"pushl %esi\n" \
@@ -378,10 +391,12 @@ asm(".globl irq_common_entry\n" \
"popl %edi\n" \
"popl %ebp\n" \
"popl %eax\n" \
+ "popl %eax\n" \
"popl %ds\n" \
"popl %es\n" \
"popl %fs\n" \
"popl %gs\n" \
+ "popl %ss\n" \
"add $4, %esp\n" \
"iret\n" \
DECLARE_INTERRUPT(0) \
diff --git a/arch/i386/include/asm/interrupt.h b/arch/i386/include/asm/interrupt.h
index 99ae8437b..d32ef8b19 100644
--- a/arch/i386/include/asm/interrupt.h
+++ b/arch/i386/include/asm/interrupt.h
@@ -27,6 +27,8 @@
#ifndef __ASM_INTERRUPT_H_
#define __ASM_INTERRUPT_H_ 1
+#include <asm/types.h>
+
/* arch/i386/cpu/interrupts.c */
void set_vector(u8 intnum, void *routine);
diff --git a/arch/i386/include/asm/ptrace.h b/arch/i386/include/asm/ptrace.h
index 750e40d03..a727dbfb0 100644
--- a/arch/i386/include/asm/ptrace.h
+++ b/arch/i386/include/asm/ptrace.h
@@ -1,6 +1,8 @@
#ifndef _I386_PTRACE_H
#define _I386_PTRACE_H
+#include <asm/types.h>
+
#define EBX 0
#define ECX 1
#define EDX 2
@@ -43,6 +45,28 @@ struct pt_regs {
int xss;
} __attribute__ ((packed));
+struct irq_regs {
+ /* Pushed by irq_common_entry */
+ long ebx;
+ long ecx;
+ long edx;
+ long esi;
+ long edi;
+ long ebp;
+ long esp;
+ long eax;
+ long xds;
+ long xes;
+ long xfs;
+ long xgs;
+ long xss;
+ /* Pushed by vector handler (irq_<num>) */
+ long irq_id;
+ /* Pushed by cpu in response to interrupt */
+ long eip;
+ long xcs;
+ long eflags;
+} __attribute__ ((packed));
/* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */
#define PTRACE_GETREGS 12