linux-mips
[Top] [All Lists]

[PATCH] MIPS: Read watch registers with interrupts disabled.

To: linux-mips@linux-mips.org
Subject: [PATCH] MIPS: Read watch registers with interrupts disabled.
From: David Daney <ddaney@caviumnetworks.com>
Date: Mon, 5 Jan 2009 15:29:58 -0800
Cc: David Daney <ddaney@caviumnetworks.com>
Original-recipient: rfc822;linux-mips@linux-mips.org
Sender: linux-mips-bounce@linux-mips.org
If a context switch occurred between the watch exception and reading
the watch registers, it would be possible for the new process to
corrupt their state.  Enabling interrupts only after the watch
registers are read avoids this race.

Signed-off-by: David Daney <ddaney@caviumnetworks.com>
---
 arch/mips/kernel/genex.S |    6 +++++-
 arch/mips/kernel/traps.c |    8 +++++++-
 2 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/arch/mips/kernel/genex.S b/arch/mips/kernel/genex.S
index fb6f731..8882e57 100644
--- a/arch/mips/kernel/genex.S
+++ b/arch/mips/kernel/genex.S
@@ -458,7 +458,11 @@ NESTED(nmi_handler, PT_SIZE, sp)
        BUILD_HANDLER fpe fpe fpe silent                /* #15 */
        BUILD_HANDLER mdmx mdmx sti silent              /* #22 */
 #ifdef         CONFIG_HARDWARE_WATCHPOINTS
-       BUILD_HANDLER watch watch sti silent            /* #23 */
+       /*
+        * For watch, interrupts will be enabled after the watch
+        * registers are read.
+        */
+       BUILD_HANDLER watch watch cli silent            /* #23 */
 #else
        BUILD_HANDLER watch watch sti verbose           /* #23 */
 #endif
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index f6083c6..7a97b3f 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -944,6 +944,9 @@ asmlinkage void do_mdmx(struct pt_regs *regs)
        force_sig(SIGILL, current);
 }
 
+/*
+ * Called with interrupts disabled.
+ */
 asmlinkage void do_watch(struct pt_regs *regs)
 {
        u32 cause;
@@ -963,9 +966,12 @@ asmlinkage void do_watch(struct pt_regs *regs)
         */
        if (test_tsk_thread_flag(current, TIF_LOAD_WATCH)) {
                mips_read_watch_registers();
+               local_irq_enable();
                force_sig(SIGTRAP, current);
-       } else
+       } else {
                mips_clear_watch_registers();
+               local_irq_enable();
+       }
 }
 
 asmlinkage void do_mcheck(struct pt_regs *regs)
-- 
1.5.6.6


<Prev in Thread] Current Thread [Next in Thread>