aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel/signal.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/kernel/signal.c')
-rw-r--r--arch/mips/kernel/signal.c139
1 files changed, 139 insertions, 0 deletions
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 */
44int 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
87int 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
132void __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
154int 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