aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMaciej W. Rozycki <macro@linux-mips.org>2014-03-31 19:14:41 -0400
committerRalf Baechle <ralf@linux-mips.org>2014-05-12 18:29:35 -0400
commit824122a319d827d42aeb4646a3bf639937fdb2ce (patch)
treee28921d9bd4f85c09d7c3c1d838a9f816b0cf96e
parentaf37530bbe9cae2a17044525b9f898ff60012157 (diff)
MIPS: DEC/SNI: O32 wrapper stack switching fixes
Commit 231a35d37293ab88d325a9cb94e5474c156282c0 [[MIPS] RM: Collected changes] broke DECstation support by introducing an incompatible copy of arch/mips/dec/prom/call_o32.S in arch/mips/fw/lib/, built unconditionally. The copy happens to land earlier of the two among the modules used in the link and is therefore chosen for the DECstation rather than the intended original. As a result random kernel data is corrupted because a pointer to the "%s" formatted output template is used as a temporary stack pointer rather than being passed down to prom_printf. This also explains why prom_printf still works, up to a point -- the next argument is the actual string to output so it works just fine as the output template until enough kernel data has been corrupted to cause a crash. This change adjusts the modified wrapper in arch/mips/fw/lib/call_o32.S to let callers request no stack switching by passing a null temporary stack pointer in $a1, reworks the DECstation callers to work with the updated interface and removes the old copy from arch/mips/dec/prom/call_o32.S. A few minor readability adjustments are included as well, most importantly O32_SZREG is now used throughout where applicable rather than hardcoded multiplies of 4 and $fp is used to access the argument save area as a more usual register to operate the stack with rather than $s0. Finally an update is made to the temporary stack space used by the SNI platform to guarantee 8-byte alignment as per o32 requirements. Signed-off-by: Maciej W. Rozycki <macro@linux-mips.org> Cc: Thomas Bogendoerfer <tsbogend@alpha.franken.de> Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/6668/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
-rw-r--r--arch/mips/dec/prom/Makefile1
-rw-r--r--arch/mips/dec/prom/call_o32.S89
-rw-r--r--arch/mips/fw/lib/call_o32.S57
-rw-r--r--arch/mips/fw/sni/sniprom.c3
-rw-r--r--arch/mips/include/asm/dec/prom.h48
5 files changed, 61 insertions, 137 deletions
diff --git a/arch/mips/dec/prom/Makefile b/arch/mips/dec/prom/Makefile
index 064ae7a76bdc..ae73e42ac20b 100644
--- a/arch/mips/dec/prom/Makefile
+++ b/arch/mips/dec/prom/Makefile
@@ -6,4 +6,3 @@
6lib-y += init.o memory.o cmdline.o identify.o console.o 6lib-y += init.o memory.o cmdline.o identify.o console.o
7 7
8lib-$(CONFIG_32BIT) += locore.o 8lib-$(CONFIG_32BIT) += locore.o
9lib-$(CONFIG_64BIT) += call_o32.o
diff --git a/arch/mips/dec/prom/call_o32.S b/arch/mips/dec/prom/call_o32.S
deleted file mode 100644
index 8c8498159e43..000000000000
--- a/arch/mips/dec/prom/call_o32.S
+++ /dev/null
@@ -1,89 +0,0 @@
1/*
2 * O32 interface for the 64 (or N32) ABI.
3 *
4 * Copyright (C) 2002 Maciej W. Rozycki
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 */
11
12#include <asm/asm.h>
13#include <asm/regdef.h>
14
15/* Maximum number of arguments supported. Must be even! */
16#define O32_ARGC 32
17/* Number of static registers we save. */
18#define O32_STATC 11
19/* Frame size for both of the above. */
20#define O32_FRAMESZ (4 * O32_ARGC + SZREG * O32_STATC)
21
22 .text
23
24/*
25 * O32 function call dispatcher, for interfacing 32-bit ROM routines.
26 *
27 * The standard 64 (N32) calling sequence is supported, with a0
28 * holding a function pointer, a1-a7 -- its first seven arguments
29 * and the stack -- remaining ones (up to O32_ARGC, including a1-a7).
30 * Static registers, gp and fp are preserved, v0 holds a result.
31 * This code relies on the called o32 function for sp and ra
32 * restoration and thus both this dispatcher and the current stack
33 * have to be placed in a KSEGx (or KUSEG) address space. Any
34 * pointers passed have to point to addresses within one of these
35 * spaces as well.
36 */
37NESTED(call_o32, O32_FRAMESZ, ra)
38 REG_SUBU sp,O32_FRAMESZ
39
40 REG_S ra,O32_FRAMESZ-1*SZREG(sp)
41 REG_S fp,O32_FRAMESZ-2*SZREG(sp)
42 REG_S gp,O32_FRAMESZ-3*SZREG(sp)
43 REG_S s7,O32_FRAMESZ-4*SZREG(sp)
44 REG_S s6,O32_FRAMESZ-5*SZREG(sp)
45 REG_S s5,O32_FRAMESZ-6*SZREG(sp)
46 REG_S s4,O32_FRAMESZ-7*SZREG(sp)
47 REG_S s3,O32_FRAMESZ-8*SZREG(sp)
48 REG_S s2,O32_FRAMESZ-9*SZREG(sp)
49 REG_S s1,O32_FRAMESZ-10*SZREG(sp)
50 REG_S s0,O32_FRAMESZ-11*SZREG(sp)
51
52 move jp,a0
53
54 sll a0,a1,zero
55 sll a1,a2,zero
56 sll a2,a3,zero
57 sll a3,a4,zero
58 sw a5,0x10(sp)
59 sw a6,0x14(sp)
60 sw a7,0x18(sp)
61
62 PTR_LA t0,O32_FRAMESZ(sp)
63 PTR_LA t1,0x1c(sp)
64 li t2,O32_ARGC-7
651:
66 lw t3,(t0)
67 REG_ADDU t0,SZREG
68 sw t3,(t1)
69 REG_SUBU t2,1
70 REG_ADDU t1,4
71 bnez t2,1b
72
73 jalr jp
74
75 REG_L s0,O32_FRAMESZ-11*SZREG(sp)
76 REG_L s1,O32_FRAMESZ-10*SZREG(sp)
77 REG_L s2,O32_FRAMESZ-9*SZREG(sp)
78 REG_L s3,O32_FRAMESZ-8*SZREG(sp)
79 REG_L s4,O32_FRAMESZ-7*SZREG(sp)
80 REG_L s5,O32_FRAMESZ-6*SZREG(sp)
81 REG_L s6,O32_FRAMESZ-5*SZREG(sp)
82 REG_L s7,O32_FRAMESZ-4*SZREG(sp)
83 REG_L gp,O32_FRAMESZ-3*SZREG(sp)
84 REG_L fp,O32_FRAMESZ-2*SZREG(sp)
85 REG_L ra,O32_FRAMESZ-1*SZREG(sp)
86
87 REG_ADDU sp,O32_FRAMESZ
88 jr ra
89END(call_o32)
diff --git a/arch/mips/fw/lib/call_o32.S b/arch/mips/fw/lib/call_o32.S
index b308b2a0613e..4703fe4dbd9a 100644
--- a/arch/mips/fw/lib/call_o32.S
+++ b/arch/mips/fw/lib/call_o32.S
@@ -1,7 +1,7 @@
1/* 1/*
2 * O32 interface for the 64 (or N32) ABI. 2 * O32 interface for the 64 (or N32) ABI.
3 * 3 *
4 * Copyright (C) 2002 Maciej W. Rozycki 4 * Copyright (C) 2002, 2014 Maciej W. Rozycki
5 * 5 *
6 * This program is free software; you can redistribute it and/or 6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License 7 * modify it under the terms of the GNU General Public License
@@ -12,28 +12,37 @@
12#include <asm/asm.h> 12#include <asm/asm.h>
13#include <asm/regdef.h> 13#include <asm/regdef.h>
14 14
15/* O32 register size. */
16#define O32_SZREG 4
15/* Maximum number of arguments supported. Must be even! */ 17/* Maximum number of arguments supported. Must be even! */
16#define O32_ARGC 32 18#define O32_ARGC 32
17/* Number of static registers we save. */ 19/* Number of static registers we save. */
18#define O32_STATC 11 20#define O32_STATC 11
19/* Frame size for static register */ 21/* Argument area frame size. */
20#define O32_FRAMESZ (SZREG * O32_STATC) 22#define O32_ARGSZ (O32_SZREG * O32_ARGC)
21/* Frame size on new stack */ 23/* Static register save area frame size. */
22#define O32_FRAMESZ_NEW (SZREG + 4 * O32_ARGC) 24#define O32_STATSZ (SZREG * O32_STATC)
25/* Stack pointer register save area frame size. */
26#define O32_SPSZ SZREG
27/* Combined area frame size. */
28#define O32_FRAMESZ (O32_ARGSZ + O32_SPSZ + O32_STATSZ)
29/* Switched stack frame size. */
30#define O32_NFRAMESZ (O32_ARGSZ + O32_SPSZ)
23 31
24 .text 32 .text
25 33
26/* 34/*
27 * O32 function call dispatcher, for interfacing 32-bit ROM routines. 35 * O32 function call dispatcher, for interfacing 32-bit ROM routines.
28 * 36 *
29 * The standard 64 (N32) calling sequence is supported, with a0 37 * The standard 64 (N32) calling sequence is supported, with a0 holding
30 * holding a function pointer, a1 a new stack pointer, a2-a7 -- its 38 * a function pointer, a1 a pointer to the new stack to call the
31 * first six arguments and the stack -- remaining ones (up to O32_ARGC, 39 * function with or 0 if no stack switching is requested, a2-a7 -- the
32 * including a2-a7). Static registers, gp and fp are preserved, v0 holds 40 * function call's first six arguments, and the stack -- the remaining
33 * a result. This code relies on the called o32 function for sp and ra 41 * arguments (up to O32_ARGC, including a2-a7). Static registers, gp
34 * restoration and this dispatcher has to be placed in a KSEGx (or KUSEG) 42 * and fp are preserved, v0 holds the result. This code relies on the
35 * address space. Any pointers passed have to point to addresses within 43 * called o32 function for sp and ra restoration and this dispatcher has
36 * one of these spaces as well. 44 * to be placed in a KSEGx (or KUSEG) address space. Any pointers
45 * passed have to point to addresses within one of these spaces as well.
37 */ 46 */
38NESTED(call_o32, O32_FRAMESZ, ra) 47NESTED(call_o32, O32_FRAMESZ, ra)
39 REG_SUBU sp,O32_FRAMESZ 48 REG_SUBU sp,O32_FRAMESZ
@@ -51,32 +60,36 @@ NESTED(call_o32, O32_FRAMESZ, ra)
51 REG_S s0,O32_FRAMESZ-11*SZREG(sp) 60 REG_S s0,O32_FRAMESZ-11*SZREG(sp)
52 61
53 move jp,a0 62 move jp,a0
54 REG_SUBU s0,a1,O32_FRAMESZ_NEW 63
55 REG_S sp,O32_FRAMESZ_NEW-1*SZREG(s0) 64 move fp,sp
65 beqz a1,0f
66 REG_SUBU fp,a1,O32_NFRAMESZ
670:
68 REG_S sp,O32_NFRAMESZ-1*SZREG(fp)
56 69
57 sll a0,a2,zero 70 sll a0,a2,zero
58 sll a1,a3,zero 71 sll a1,a3,zero
59 sll a2,a4,zero 72 sll a2,a4,zero
60 sll a3,a5,zero 73 sll a3,a5,zero
61 sw a6,0x10(s0) 74 sw a6,4*O32_SZREG(fp)
62 sw a7,0x14(s0) 75 sw a7,5*O32_SZREG(fp)
63 76
64 PTR_LA t0,O32_FRAMESZ(sp) 77 PTR_LA t0,O32_FRAMESZ(sp)
65 PTR_LA t1,0x18(s0) 78 PTR_LA t1,6*O32_SZREG(fp)
66 li t2,O32_ARGC-6 79 li t2,O32_ARGC-6
671: 801:
68 lw t3,(t0) 81 lw t3,(t0)
69 REG_ADDU t0,SZREG 82 REG_ADDU t0,SZREG
70 sw t3,(t1) 83 sw t3,(t1)
71 REG_SUBU t2,1 84 REG_SUBU t2,1
72 REG_ADDU t1,4 85 REG_ADDU t1,O32_SZREG
73 bnez t2,1b 86 bnez t2,1b
74 87
75 move sp,s0 88 move sp,fp
76 89
77 jalr jp 90 jalr jp
78 91
79 REG_L sp,O32_FRAMESZ_NEW-1*SZREG(sp) 92 REG_L sp,O32_NFRAMESZ-1*SZREG(sp)
80 93
81 REG_L s0,O32_FRAMESZ-11*SZREG(sp) 94 REG_L s0,O32_FRAMESZ-11*SZREG(sp)
82 REG_L s1,O32_FRAMESZ-10*SZREG(sp) 95 REG_L s1,O32_FRAMESZ-10*SZREG(sp)
diff --git a/arch/mips/fw/sni/sniprom.c b/arch/mips/fw/sni/sniprom.c
index 2c2cb182af4e..6aa264b9856a 100644
--- a/arch/mips/fw/sni/sniprom.c
+++ b/arch/mips/fw/sni/sniprom.c
@@ -40,7 +40,8 @@
40 40
41#ifdef CONFIG_64BIT 41#ifdef CONFIG_64BIT
42 42
43static u8 o32_stk[16384]; 43/* O32 stack has to be 8-byte aligned. */
44static u64 o32_stk[4096];
44#define O32_STK &o32_stk[sizeof(o32_stk)] 45#define O32_STK &o32_stk[sizeof(o32_stk)]
45 46
46#define __PROM_O32(fun, arg) fun arg __asm__(#fun); \ 47#define __PROM_O32(fun, arg) fun arg __asm__(#fun); \
diff --git a/arch/mips/include/asm/dec/prom.h b/arch/mips/include/asm/dec/prom.h
index c0ead6313845..b59a2103b61a 100644
--- a/arch/mips/include/asm/dec/prom.h
+++ b/arch/mips/include/asm/dec/prom.h
@@ -113,31 +113,31 @@ extern int (*__pmax_close)(int);
113#define __DEC_PROM_O32(fun, arg) fun arg __asm__(#fun); \ 113#define __DEC_PROM_O32(fun, arg) fun arg __asm__(#fun); \
114 __asm__(#fun " = call_o32") 114 __asm__(#fun " = call_o32")
115 115
116int __DEC_PROM_O32(_rex_bootinit, (int (*)(void))); 116int __DEC_PROM_O32(_rex_bootinit, (int (*)(void), void *));
117int __DEC_PROM_O32(_rex_bootread, (int (*)(void))); 117int __DEC_PROM_O32(_rex_bootread, (int (*)(void), void *));
118int __DEC_PROM_O32(_rex_getbitmap, (int (*)(memmap *), memmap *)); 118int __DEC_PROM_O32(_rex_getbitmap, (int (*)(memmap *), void *, memmap *));
119unsigned long *__DEC_PROM_O32(_rex_slot_address, 119unsigned long *__DEC_PROM_O32(_rex_slot_address,
120 (unsigned long *(*)(int), int)); 120 (unsigned long *(*)(int), void *, int));
121void *__DEC_PROM_O32(_rex_gettcinfo, (void *(*)(void))); 121void *__DEC_PROM_O32(_rex_gettcinfo, (void *(*)(void), void *));
122int __DEC_PROM_O32(_rex_getsysid, (int (*)(void))); 122int __DEC_PROM_O32(_rex_getsysid, (int (*)(void), void *));
123void __DEC_PROM_O32(_rex_clear_cache, (void (*)(void))); 123void __DEC_PROM_O32(_rex_clear_cache, (void (*)(void), void *));
124 124
125int __DEC_PROM_O32(_prom_getchar, (int (*)(void))); 125int __DEC_PROM_O32(_prom_getchar, (int (*)(void), void *));
126char *__DEC_PROM_O32(_prom_getenv, (char *(*)(char *), char *)); 126char *__DEC_PROM_O32(_prom_getenv, (char *(*)(char *), void *, char *));
127int __DEC_PROM_O32(_prom_printf, (int (*)(char *, ...), char *, ...)); 127int __DEC_PROM_O32(_prom_printf, (int (*)(char *, ...), void *, char *, ...));
128 128
129 129
130#define rex_bootinit() _rex_bootinit(__rex_bootinit) 130#define rex_bootinit() _rex_bootinit(__rex_bootinit, NULL)
131#define rex_bootread() _rex_bootread(__rex_bootread) 131#define rex_bootread() _rex_bootread(__rex_bootread, NULL)
132#define rex_getbitmap(x) _rex_getbitmap(__rex_getbitmap, x) 132#define rex_getbitmap(x) _rex_getbitmap(__rex_getbitmap, NULL, x)
133#define rex_slot_address(x) _rex_slot_address(__rex_slot_address, x) 133#define rex_slot_address(x) _rex_slot_address(__rex_slot_address, NULL, x)
134#define rex_gettcinfo() _rex_gettcinfo(__rex_gettcinfo) 134#define rex_gettcinfo() _rex_gettcinfo(__rex_gettcinfo, NULL)
135#define rex_getsysid() _rex_getsysid(__rex_getsysid) 135#define rex_getsysid() _rex_getsysid(__rex_getsysid, NULL)
136#define rex_clear_cache() _rex_clear_cache(__rex_clear_cache) 136#define rex_clear_cache() _rex_clear_cache(__rex_clear_cache, NULL)
137 137
138#define prom_getchar() _prom_getchar(__prom_getchar) 138#define prom_getchar() _prom_getchar(__prom_getchar, NULL)
139#define prom_getenv(x) _prom_getenv(__prom_getenv, x) 139#define prom_getenv(x) _prom_getenv(__prom_getenv, NULL, x)
140#define prom_printf(x...) _prom_printf(__prom_printf, x) 140#define prom_printf(x...) _prom_printf(__prom_printf, NULL, x)
141 141
142#else /* !CONFIG_64BIT */ 142#else /* !CONFIG_64BIT */
143 143