diff options
Diffstat (limited to 'arch/mips/kernel')
-rw-r--r-- | arch/mips/kernel/signal-common.h | 150 | ||||
-rw-r--r-- | arch/mips/kernel/signal.c | 139 |
2 files changed, 153 insertions, 136 deletions
diff --git a/arch/mips/kernel/signal-common.h b/arch/mips/kernel/signal-common.h index bb3c631b808e..03d2b603fb84 100644 --- a/arch/mips/kernel/signal-common.h +++ b/arch/mips/kernel/signal-common.h | |||
@@ -8,145 +8,23 @@ | |||
8 | * Copyright (C) 1999, 2000 Silicon Graphics, Inc. | 8 | * Copyright (C) 1999, 2000 Silicon Graphics, Inc. |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #ifndef __SIGNAL_COMMON_H | ||
12 | #define __SIGNAL_COMMON_H | ||
11 | 13 | ||
12 | static inline int | 14 | /* |
13 | setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) | 15 | * handle hardware context |
14 | { | 16 | */ |
15 | int err = 0; | 17 | extern int setup_sigcontext(struct pt_regs *, struct sigcontext __user *); |
16 | int i; | 18 | extern int restore_sigcontext(struct pt_regs *, struct sigcontext __user *); |
17 | |||
18 | err |= __put_user(regs->cp0_epc, &sc->sc_pc); | ||
19 | |||
20 | err |= __put_user(0, &sc->sc_regs[0]); | ||
21 | for (i = 1; i < 32; i++) | ||
22 | err |= __put_user(regs->regs[i], &sc->sc_regs[i]); | ||
23 | |||
24 | err |= __put_user(regs->hi, &sc->sc_mdhi); | ||
25 | err |= __put_user(regs->lo, &sc->sc_mdlo); | ||
26 | if (cpu_has_dsp) { | ||
27 | err |= __put_user(mfhi1(), &sc->sc_hi1); | ||
28 | err |= __put_user(mflo1(), &sc->sc_lo1); | ||
29 | err |= __put_user(mfhi2(), &sc->sc_hi2); | ||
30 | err |= __put_user(mflo2(), &sc->sc_lo2); | ||
31 | err |= __put_user(mfhi3(), &sc->sc_hi3); | ||
32 | err |= __put_user(mflo3(), &sc->sc_lo3); | ||
33 | err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp); | ||
34 | } | ||
35 | |||
36 | err |= __put_user(!!used_math(), &sc->sc_used_math); | ||
37 | |||
38 | if (used_math()) { | ||
39 | /* | ||
40 | * Save FPU state to signal context. Signal handler | ||
41 | * will "inherit" current FPU state. | ||
42 | */ | ||
43 | preempt_disable(); | ||
44 | |||
45 | if (!is_fpu_owner()) { | ||
46 | own_fpu(); | ||
47 | restore_fp(current); | ||
48 | } | ||
49 | err |= save_fp_context(sc); | ||
50 | |||
51 | preempt_enable(); | ||
52 | } | ||
53 | return err; | ||
54 | } | ||
55 | |||
56 | static inline int | ||
57 | restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) | ||
58 | { | ||
59 | unsigned int used_math; | ||
60 | unsigned long treg; | ||
61 | int err = 0; | ||
62 | int i; | ||
63 | |||
64 | /* Always make any pending restarted system calls return -EINTR */ | ||
65 | current_thread_info()->restart_block.fn = do_no_restart_syscall; | ||
66 | |||
67 | err |= __get_user(regs->cp0_epc, &sc->sc_pc); | ||
68 | err |= __get_user(regs->hi, &sc->sc_mdhi); | ||
69 | err |= __get_user(regs->lo, &sc->sc_mdlo); | ||
70 | if (cpu_has_dsp) { | ||
71 | err |= __get_user(treg, &sc->sc_hi1); mthi1(treg); | ||
72 | err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg); | ||
73 | err |= __get_user(treg, &sc->sc_hi2); mthi2(treg); | ||
74 | err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg); | ||
75 | err |= __get_user(treg, &sc->sc_hi3); mthi3(treg); | ||
76 | err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg); | ||
77 | err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK); | ||
78 | } | ||
79 | |||
80 | for (i = 1; i < 32; i++) | ||
81 | err |= __get_user(regs->regs[i], &sc->sc_regs[i]); | ||
82 | |||
83 | err |= __get_user(used_math, &sc->sc_used_math); | ||
84 | conditional_used_math(used_math); | ||
85 | |||
86 | preempt_disable(); | ||
87 | |||
88 | if (used_math()) { | ||
89 | /* restore fpu context if we have used it before */ | ||
90 | own_fpu(); | ||
91 | err |= restore_fp_context(sc); | ||
92 | } else { | ||
93 | /* signal handler may have used FPU. Give it up. */ | ||
94 | lose_fpu(); | ||
95 | } | ||
96 | |||
97 | preempt_enable(); | ||
98 | |||
99 | return err; | ||
100 | } | ||
101 | 19 | ||
102 | /* | 20 | /* |
103 | * Determine which stack to use.. | 21 | * Determine which stack to use.. |
104 | */ | 22 | */ |
105 | static inline void __user * | 23 | extern void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, |
106 | get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size) | 24 | size_t frame_size); |
107 | { | 25 | /* |
108 | unsigned long sp; | 26 | * install trampoline code to get back from the sig handler |
109 | 27 | */ | |
110 | /* Default to using normal stack */ | 28 | extern int install_sigtramp(unsigned int __user *tramp, unsigned int syscall); |
111 | sp = regs->regs[29]; | ||
112 | |||
113 | /* | ||
114 | * FPU emulator may have it's own trampoline active just | ||
115 | * above the user stack, 16-bytes before the next lowest | ||
116 | * 16 byte boundary. Try to avoid trashing it. | ||
117 | */ | ||
118 | sp -= 32; | ||
119 | |||
120 | /* This is the X/Open sanctioned signal stack switching. */ | ||
121 | if ((ka->sa.sa_flags & SA_ONSTACK) && (sas_ss_flags (sp) == 0)) | ||
122 | sp = current->sas_ss_sp + current->sas_ss_size; | ||
123 | |||
124 | return (void __user *)((sp - frame_size) & (ICACHE_REFILLS_WORKAROUND_WAR ? ~(cpu_icache_line_size()-1) : ALMASK)); | ||
125 | } | ||
126 | |||
127 | static inline int install_sigtramp(unsigned int __user *tramp, | ||
128 | unsigned int syscall) | ||
129 | { | ||
130 | int err; | ||
131 | |||
132 | /* | ||
133 | * Set up the return code ... | ||
134 | * | ||
135 | * li v0, __NR__foo_sigreturn | ||
136 | * syscall | ||
137 | */ | ||
138 | |||
139 | err = __put_user(0x24020000 + syscall, tramp + 0); | ||
140 | err |= __put_user(0x0000000c , tramp + 1); | ||
141 | if (ICACHE_REFILLS_WORKAROUND_WAR) { | ||
142 | err |= __put_user(0, tramp + 2); | ||
143 | err |= __put_user(0, tramp + 3); | ||
144 | err |= __put_user(0, tramp + 4); | ||
145 | err |= __put_user(0, tramp + 5); | ||
146 | err |= __put_user(0, tramp + 6); | ||
147 | err |= __put_user(0, tramp + 7); | ||
148 | } | ||
149 | flush_cache_sigtramp((unsigned long) tramp); | ||
150 | 29 | ||
151 | return err; | 30 | #endif /* __SIGNAL_COMMON_H */ |
152 | } | ||
diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index 9a44053cd9f1..7d5a631d6cab 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c | |||
@@ -39,6 +39,145 @@ | |||
39 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) | 39 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) |
40 | 40 | ||
41 | /* | 41 | /* |
42 | * Helper routines | ||
43 | */ | ||
44 | int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) | ||
45 | { | ||
46 | int err = 0; | ||
47 | int i; | ||
48 | |||
49 | err |= __put_user(regs->cp0_epc, &sc->sc_pc); | ||
50 | |||
51 | err |= __put_user(0, &sc->sc_regs[0]); | ||
52 | for (i = 1; i < 32; i++) | ||
53 | err |= __put_user(regs->regs[i], &sc->sc_regs[i]); | ||
54 | |||
55 | err |= __put_user(regs->hi, &sc->sc_mdhi); | ||
56 | err |= __put_user(regs->lo, &sc->sc_mdlo); | ||
57 | if (cpu_has_dsp) { | ||
58 | err |= __put_user(mfhi1(), &sc->sc_hi1); | ||
59 | err |= __put_user(mflo1(), &sc->sc_lo1); | ||
60 | err |= __put_user(mfhi2(), &sc->sc_hi2); | ||
61 | err |= __put_user(mflo2(), &sc->sc_lo2); | ||
62 | err |= __put_user(mfhi3(), &sc->sc_hi3); | ||
63 | err |= __put_user(mflo3(), &sc->sc_lo3); | ||
64 | err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp); | ||
65 | } | ||
66 | |||
67 | err |= __put_user(!!used_math(), &sc->sc_used_math); | ||
68 | |||
69 | if (used_math()) { | ||
70 | /* | ||
71 | * Save FPU state to signal context. Signal handler | ||
72 | * will "inherit" current FPU state. | ||
73 | */ | ||
74 | preempt_disable(); | ||
75 | |||
76 | if (!is_fpu_owner()) { | ||
77 | own_fpu(); | ||
78 | restore_fp(current); | ||
79 | } | ||
80 | err |= save_fp_context(sc); | ||
81 | |||
82 | preempt_enable(); | ||
83 | } | ||
84 | return err; | ||
85 | } | ||
86 | |||
87 | int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) | ||
88 | { | ||
89 | unsigned int used_math; | ||
90 | unsigned long treg; | ||
91 | int err = 0; | ||
92 | int i; | ||
93 | |||
94 | /* Always make any pending restarted system calls return -EINTR */ | ||
95 | current_thread_info()->restart_block.fn = do_no_restart_syscall; | ||
96 | |||
97 | err |= __get_user(regs->cp0_epc, &sc->sc_pc); | ||
98 | err |= __get_user(regs->hi, &sc->sc_mdhi); | ||
99 | err |= __get_user(regs->lo, &sc->sc_mdlo); | ||
100 | if (cpu_has_dsp) { | ||
101 | err |= __get_user(treg, &sc->sc_hi1); mthi1(treg); | ||
102 | err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg); | ||
103 | err |= __get_user(treg, &sc->sc_hi2); mthi2(treg); | ||
104 | err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg); | ||
105 | err |= __get_user(treg, &sc->sc_hi3); mthi3(treg); | ||
106 | err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg); | ||
107 | err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK); | ||
108 | } | ||
109 | |||
110 | for (i = 1; i < 32; i++) | ||
111 | err |= __get_user(regs->regs[i], &sc->sc_regs[i]); | ||
112 | |||
113 | err |= __get_user(used_math, &sc->sc_used_math); | ||
114 | conditional_used_math(used_math); | ||
115 | |||
116 | preempt_disable(); | ||
117 | |||
118 | if (used_math()) { | ||
119 | /* restore fpu context if we have used it before */ | ||
120 | own_fpu(); | ||
121 | err |= restore_fp_context(sc); | ||
122 | } else { | ||
123 | /* signal handler may have used FPU. Give it up. */ | ||
124 | lose_fpu(); | ||
125 | } | ||
126 | |||
127 | preempt_enable(); | ||
128 | |||
129 | return err; | ||
130 | } | ||
131 | |||
132 | void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, | ||
133 | size_t frame_size) | ||
134 | { | ||
135 | unsigned long sp; | ||
136 | |||
137 | /* Default to using normal stack */ | ||
138 | sp = regs->regs[29]; | ||
139 | |||
140 | /* | ||
141 | * FPU emulator may have it's own trampoline active just | ||
142 | * above the user stack, 16-bytes before the next lowest | ||
143 | * 16 byte boundary. Try to avoid trashing it. | ||
144 | */ | ||
145 | sp -= 32; | ||
146 | |||
147 | /* This is the X/Open sanctioned signal stack switching. */ | ||
148 | if ((ka->sa.sa_flags & SA_ONSTACK) && (sas_ss_flags (sp) == 0)) | ||
149 | sp = current->sas_ss_sp + current->sas_ss_size; | ||
150 | |||
151 | return (void __user *)((sp - frame_size) & (ICACHE_REFILLS_WORKAROUND_WAR ? ~(cpu_icache_line_size()-1) : ALMASK)); | ||
152 | } | ||
153 | |||
154 | int install_sigtramp(unsigned int __user *tramp, unsigned int syscall) | ||
155 | { | ||
156 | int err; | ||
157 | |||
158 | /* | ||
159 | * Set up the return code ... | ||
160 | * | ||
161 | * li v0, __NR__foo_sigreturn | ||
162 | * syscall | ||
163 | */ | ||
164 | |||
165 | err = __put_user(0x24020000 + syscall, tramp + 0); | ||
166 | err |= __put_user(0x0000000c , tramp + 1); | ||
167 | if (ICACHE_REFILLS_WORKAROUND_WAR) { | ||
168 | err |= __put_user(0, tramp + 2); | ||
169 | err |= __put_user(0, tramp + 3); | ||
170 | err |= __put_user(0, tramp + 4); | ||
171 | err |= __put_user(0, tramp + 5); | ||
172 | err |= __put_user(0, tramp + 6); | ||
173 | err |= __put_user(0, tramp + 7); | ||
174 | } | ||
175 | flush_cache_sigtramp((unsigned long) tramp); | ||
176 | |||
177 | return err; | ||
178 | } | ||
179 | |||
180 | /* | ||
42 | * Atomically swap in the new signal mask, and wait for a signal. | 181 | * Atomically swap in the new signal mask, and wait for a signal. |
43 | */ | 182 | */ |
44 | 183 | ||