aboutsummaryrefslogtreecommitdiffstats
path: root/arch/m68k/mm/hwtest.c
diff options
context:
space:
mode:
authorGeert Uytterhoeven <geert@linux-m68k.org>2014-09-28 04:50:06 -0400
committerGeert Uytterhoeven <geert@linux-m68k.org>2014-10-03 04:50:56 -0400
commite4dc601bf99ccd1c95b7e6eef1d3cf3c4b0d4961 (patch)
tree53d8c0365752e85cfe8491a91265944d64188cef /arch/m68k/mm/hwtest.c
parentfd4d453b64d409647c92de6395494b5dd82ce224 (diff)
m68k: Disable/restore interrupts in hwreg_present()/hwreg_write()
hwreg_present() and hwreg_write() temporarily change the VBR register to another vector table. This table contains a valid bus error handler only, all other entries point to arbitrary addresses. If an interrupt comes in while the temporary table is active, the processor will start executing at such an arbitrary address, and the kernel will crash. While most callers run early, before interrupts are enabled, or explicitly disable interrupts, Finn Thain pointed out that macsonic has one callsite that doesn't, causing intermittent boot crashes. There's another unsafe callsite in hilkbd. Fix this for good by disabling and restoring interrupts inside hwreg_present() and hwreg_write(). Explicitly disabling interrupts can be removed from the callsites later. Reported-by: Finn Thain <fthain@telegraphics.com.au> Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org> Cc: stable@vger.kernel.org
Diffstat (limited to 'arch/m68k/mm/hwtest.c')
-rw-r--r--arch/m68k/mm/hwtest.c6
1 files changed, 6 insertions, 0 deletions
diff --git a/arch/m68k/mm/hwtest.c b/arch/m68k/mm/hwtest.c
index 2c7dde3c6430..2a5259fd23eb 100644
--- a/arch/m68k/mm/hwtest.c
+++ b/arch/m68k/mm/hwtest.c
@@ -28,9 +28,11 @@
28int hwreg_present( volatile void *regp ) 28int hwreg_present( volatile void *regp )
29{ 29{
30 int ret = 0; 30 int ret = 0;
31 unsigned long flags;
31 long save_sp, save_vbr; 32 long save_sp, save_vbr;
32 long tmp_vectors[3]; 33 long tmp_vectors[3];
33 34
35 local_irq_save(flags);
34 __asm__ __volatile__ 36 __asm__ __volatile__
35 ( "movec %/vbr,%2\n\t" 37 ( "movec %/vbr,%2\n\t"
36 "movel #Lberr1,%4@(8)\n\t" 38 "movel #Lberr1,%4@(8)\n\t"
@@ -46,6 +48,7 @@ int hwreg_present( volatile void *regp )
46 : "=&d" (ret), "=&r" (save_sp), "=&r" (save_vbr) 48 : "=&d" (ret), "=&r" (save_sp), "=&r" (save_vbr)
47 : "a" (regp), "a" (tmp_vectors) 49 : "a" (regp), "a" (tmp_vectors)
48 ); 50 );
51 local_irq_restore(flags);
49 52
50 return( ret ); 53 return( ret );
51} 54}
@@ -58,9 +61,11 @@ EXPORT_SYMBOL(hwreg_present);
58int hwreg_write( volatile void *regp, unsigned short val ) 61int hwreg_write( volatile void *regp, unsigned short val )
59{ 62{
60 int ret; 63 int ret;
64 unsigned long flags;
61 long save_sp, save_vbr; 65 long save_sp, save_vbr;
62 long tmp_vectors[3]; 66 long tmp_vectors[3];
63 67
68 local_irq_save(flags);
64 __asm__ __volatile__ 69 __asm__ __volatile__
65 ( "movec %/vbr,%2\n\t" 70 ( "movec %/vbr,%2\n\t"
66 "movel #Lberr2,%4@(8)\n\t" 71 "movel #Lberr2,%4@(8)\n\t"
@@ -78,6 +83,7 @@ int hwreg_write( volatile void *regp, unsigned short val )
78 : "=&d" (ret), "=&r" (save_sp), "=&r" (save_vbr) 83 : "=&d" (ret), "=&r" (save_sp), "=&r" (save_vbr)
79 : "a" (regp), "a" (tmp_vectors), "g" (val) 84 : "a" (regp), "a" (tmp_vectors), "g" (val)
80 ); 85 );
86 local_irq_restore(flags);
81 87
82 return( ret ); 88 return( ret );
83} 89}