diff options
Diffstat (limited to 'arch/mips/kernel/signal.c')
-rw-r--r-- | arch/mips/kernel/signal.c | 139 |
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 | */ | ||
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 | ||