aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Bottomley <jejb@parisc-linux.org>2005-10-21 22:53:26 -0400
committerKyle McMartin <kyle@parisc-linux.org>2005-10-21 22:53:26 -0400
commit618febd6784054eea928d712b7e564558a7cefd5 (patch)
tree13a60c377dc5a17f44e9b3b227e5996e0ba7e5a4
parentb2450cc1b7ce07d73545ece32db50197d649e230 (diff)
[PARISC] Fix the alloc_slabmgmt panic
Fix the alloc_slabmgmt panic Hopefully this should also fix a lot of other intermittent kernel bugs. The problem has been around since 2.6.9-rc2-pa6 when we allowed floating point registers to be used in kernel code. The essence of the problem is that gcc prefers to use floating point for integer divides and multiples. Further, it can rely on the values in the no clobber fp regs being correct across a function call. Unfortunately, our task switch function only saves the integer no clobber registers, not the fp ones, so if gcc makes a function call to any function in the kernel which could sleep, the values it is relying on in any no clobber floating point register may be lost. In the case of alloc_slabmgmt, the value of the page offset is being stored in %fr12 across a call to kmem_getpages(), which sleeps if no pages are available. Thus, the offset can be trashed and the slab code can end up with a completely bogus address leading to corruption. Kudos to Randolph who came up with the program to trip this problem at will and thus allowed it to be tracked and fixed. Signed-off-by: James Bottomley <jejb@parisc-linux.org> Signed-off-by: Kyle McMartin <kyle@parisc-linux.org>
-rw-r--r--arch/parisc/kernel/entry.S2
-rw-r--r--include/asm-parisc/assembly.h40
2 files changed, 36 insertions, 6 deletions
diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S
index 0ca49710d95e..166df5bab769 100644
--- a/arch/parisc/kernel/entry.S
+++ b/arch/parisc/kernel/entry.S
@@ -863,6 +863,7 @@ __execve:
863_switch_to: 863_switch_to:
864 STREG %r2, -RP_OFFSET(%r30) 864 STREG %r2, -RP_OFFSET(%r30)
865 865
866 callee_save_float
866 callee_save 867 callee_save
867 868
868 load32 _switch_to_ret, %r2 869 load32 _switch_to_ret, %r2
@@ -879,6 +880,7 @@ _switch_to:
879_switch_to_ret: 880_switch_to_ret:
880 mtctl %r0, %cr0 /* Needed for single stepping */ 881 mtctl %r0, %cr0 /* Needed for single stepping */
881 callee_rest 882 callee_rest
883 callee_rest_float
882 884
883 LDREG -RP_OFFSET(%r30), %r2 885 LDREG -RP_OFFSET(%r30), %r2
884 bv %r0(%r2) 886 bv %r0(%r2)
diff --git a/include/asm-parisc/assembly.h b/include/asm-parisc/assembly.h
index b24a99e3ef9c..fb8bc7c16e0e 100644
--- a/include/asm-parisc/assembly.h
+++ b/include/asm-parisc/assembly.h
@@ -21,6 +21,7 @@
21#ifndef _PARISC_ASSEMBLY_H 21#ifndef _PARISC_ASSEMBLY_H
22#define _PARISC_ASSEMBLY_H 22#define _PARISC_ASSEMBLY_H
23 23
24#define CALLEE_FLOAT_FRAME_SIZE 80
24#ifdef __LP64__ 25#ifdef __LP64__
25#define LDREG ldd 26#define LDREG ldd
26#define STREG std 27#define STREG std
@@ -30,7 +31,7 @@
30#define SHRREG shrd 31#define SHRREG shrd
31#define RP_OFFSET 16 32#define RP_OFFSET 16
32#define FRAME_SIZE 128 33#define FRAME_SIZE 128
33#define CALLEE_SAVE_FRAME_SIZE 144 34#define CALLEE_REG_FRAME_SIZE 144
34#else 35#else
35#define LDREG ldw 36#define LDREG ldw
36#define STREG stw 37#define STREG stw
@@ -40,8 +41,9 @@
40#define SHRREG shr 41#define SHRREG shr
41#define RP_OFFSET 20 42#define RP_OFFSET 20
42#define FRAME_SIZE 64 43#define FRAME_SIZE 64
43#define CALLEE_SAVE_FRAME_SIZE 128 44#define CALLEE_REG_FRAME_SIZE 128
44#endif 45#endif
46#define CALLEE_SAVE_FRAME_SIZE (CALLEE_REG_FRAME_SIZE + CALLEE_FLOAT_FRAME_SIZE)
45 47
46#ifdef CONFIG_PA20 48#ifdef CONFIG_PA20
47#define BL b,l 49#define BL b,l
@@ -300,9 +302,35 @@
300 fldd,mb -8(\regs), %fr0 302 fldd,mb -8(\regs), %fr0
301 .endm 303 .endm
302 304
305 .macro callee_save_float
306 fstd,ma %fr12, 8(%r30)
307 fstd,ma %fr13, 8(%r30)
308 fstd,ma %fr14, 8(%r30)
309 fstd,ma %fr15, 8(%r30)
310 fstd,ma %fr16, 8(%r30)
311 fstd,ma %fr17, 8(%r30)
312 fstd,ma %fr18, 8(%r30)
313 fstd,ma %fr19, 8(%r30)
314 fstd,ma %fr20, 8(%r30)
315 fstd,ma %fr21, 8(%r30)
316 .endm
317
318 .macro callee_rest_float
319 fldd,mb -8(%r30), %fr21
320 fldd,mb -8(%r30), %fr20
321 fldd,mb -8(%r30), %fr19
322 fldd,mb -8(%r30), %fr18
323 fldd,mb -8(%r30), %fr17
324 fldd,mb -8(%r30), %fr16
325 fldd,mb -8(%r30), %fr15
326 fldd,mb -8(%r30), %fr14
327 fldd,mb -8(%r30), %fr13
328 fldd,mb -8(%r30), %fr12
329 .endm
330
303#ifdef __LP64__ 331#ifdef __LP64__
304 .macro callee_save 332 .macro callee_save
305 std,ma %r3, CALLEE_SAVE_FRAME_SIZE(%r30) 333 std,ma %r3, CALLEE_REG_FRAME_SIZE(%r30)
306 mfctl %cr27, %r3 334 mfctl %cr27, %r3
307 std %r4, -136(%r30) 335 std %r4, -136(%r30)
308 std %r5, -128(%r30) 336 std %r5, -128(%r30)
@@ -340,13 +368,13 @@
340 ldd -128(%r30), %r5 368 ldd -128(%r30), %r5
341 ldd -136(%r30), %r4 369 ldd -136(%r30), %r4
342 mtctl %r3, %cr27 370 mtctl %r3, %cr27
343 ldd,mb -CALLEE_SAVE_FRAME_SIZE(%r30), %r3 371 ldd,mb -CALLEE_REG_FRAME_SIZE(%r30), %r3
344 .endm 372 .endm
345 373
346#else /* ! __LP64__ */ 374#else /* ! __LP64__ */
347 375
348 .macro callee_save 376 .macro callee_save
349 stw,ma %r3, CALLEE_SAVE_FRAME_SIZE(%r30) 377 stw,ma %r3, CALLEE_REG_FRAME_SIZE(%r30)
350 mfctl %cr27, %r3 378 mfctl %cr27, %r3
351 stw %r4, -124(%r30) 379 stw %r4, -124(%r30)
352 stw %r5, -120(%r30) 380 stw %r5, -120(%r30)
@@ -384,7 +412,7 @@
384 ldw -120(%r30), %r5 412 ldw -120(%r30), %r5
385 ldw -124(%r30), %r4 413 ldw -124(%r30), %r4
386 mtctl %r3, %cr27 414 mtctl %r3, %cr27
387 ldw,mb -CALLEE_SAVE_FRAME_SIZE(%r30), %r3 415 ldw,mb -CALLEE_REG_FRAME_SIZE(%r30), %r3
388 .endm 416 .endm
389#endif /* ! __LP64__ */ 417#endif /* ! __LP64__ */
390 418