x86: Fix %ss and %esp in register structure for interrupts
authorGraeme Russ <graeme.russ@gmail.com>
Thu, 7 Oct 2010 09:03:23 +0000 (20:03 +1100)
committerGraeme Russ <graeme.russ@gmail.com>
Thu, 7 Oct 2010 09:03:23 +0000 (20:03 +1100)
arch/i386/cpu/interrupts.c
arch/i386/include/asm/interrupt.h
arch/i386/include/asm/ptrace.h

index 47a7a290130257a4838b28c8b10d3163a25b4490..e4d0868cde39cb2b783f04635e01a2d679088b81 100644 (file)
@@ -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) \
index 99ae8437b88750fde56544250b62dbb6b3c05ba2..d32ef8b190ef22c606e7fa951ef3cd21393dc780 100644 (file)
@@ -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);
 
index 750e40d030cca8938cfc92ebf2b6ea50ba83ec05..a727dbfb0577d50d905c5ef6e6e3b4c19948fa58 100644 (file)
@@ -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