master
c 175 lines 4.54 KB
Raw
1 /*
2 * Emulation of Linux signals
3 *
4 * Copyright (c) 2003 Fabrice Bellard
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
18 */
19 #include "qemu/osdep.h"
20 #include "qemu.h"
21 #include "user-internals.h"
22 #include "signal-common.h"
23 #include "linux-user/trace.h"
24 #include "target_ptrace.h"
25
26 struct target_sigcontext {
27 struct target_pt_regs regs; /* needs to be first */
28 uint32_t oldmask;
29 };
30
31 struct target_stack_t {
32 abi_ulong ss_sp;
33 int ss_flags;
34 unsigned int ss_size;
35 };
36
37 struct target_ucontext {
38 abi_ulong tuc_flags;
39 abi_ulong tuc_link;
40 target_stack_t tuc_stack;
41 struct target_sigcontext tuc_mcontext;
42 target_sigset_t tuc_sigmask;
43 };
44
45 /* Signal frames. */
46 struct target_rt_sigframe {
47 target_siginfo_t info;
48 struct target_ucontext uc;
49 uint32_t tramp[2];
50 };
51
52 static void setup_sigcontext(struct target_sigcontext *sc, CPUMBState *env)
53 {
54 for (int i = 0; i < 32; ++i) {
55 __put_user(env->regs[i], &sc->regs.r[i]);
56 }
57 __put_user(env->pc, &sc->regs.pc);
58 }
59
60 static void restore_sigcontext(struct target_sigcontext *sc, CPUMBState *env)
61 {
62 for (int i = 0; i < 32; ++i) {
63 __get_user(env->regs[i], &sc->regs.r[i]);
64 }
65 __get_user(env->pc, &sc->regs.pc);
66 }
67
68 static abi_ulong get_sigframe(struct target_sigaction *ka,
69 CPUMBState *env, int frame_size)
70 {
71 abi_ulong sp = env->regs[1];
72
73 sp = target_sigsp(sp, ka);
74
75 return ((sp - frame_size) & -8UL);
76 }
77
78 void setup_rt_frame(int sig, struct target_sigaction *ka,
79 target_siginfo_t *info,
80 target_sigset_t *set, CPUMBState *env)
81 {
82 struct target_rt_sigframe *frame;
83 abi_ulong frame_addr;
84
85 frame_addr = get_sigframe(ka, env, sizeof *frame);
86 trace_user_setup_rt_frame(env, frame_addr);
87
88 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
89 force_sigsegv(sig);
90 return;
91 }
92
93 frame->info = *info;
94
95 __put_user(0, &frame->uc.tuc_flags);
96 __put_user(0, &frame->uc.tuc_link);
97
98 target_save_altstack(&frame->uc.tuc_stack, env);
99 setup_sigcontext(&frame->uc.tuc_mcontext, env);
100
101 for (int i = 0; i < TARGET_NSIG_WORDS; i++) {
102 __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
103 }
104
105 /* Kernel does not use SA_RESTORER. */
106
107 /*
108 * Return from sighandler will jump to the tramp.
109 * Negative 8 offset because return is rtsd r15, 8
110 */
111 env->regs[15] = default_rt_sigreturn - 8;
112
113 /* Set up registers for signal handler */
114 env->regs[1] = frame_addr;
115
116 /* Signal handler args: */
117 env->regs[5] = sig;
118 env->regs[6] = frame_addr + offsetof(struct target_rt_sigframe, info);
119 env->regs[7] = frame_addr + offsetof(struct target_rt_sigframe, uc);
120
121 /* Offset to handle microblaze rtid r14, 0 */
122 env->pc = (unsigned long)ka->_sa_handler;
123
124 unlock_user_struct(frame, frame_addr, 1);
125 }
126
127
128 long do_sigreturn(CPUMBState *env)
129 {
130 return -TARGET_ENOSYS;
131 }
132
133 long do_rt_sigreturn(CPUMBState *env)
134 {
135 struct target_rt_sigframe *frame = NULL;
136 abi_ulong frame_addr = env->regs[1];
137 sigset_t set;
138
139 trace_user_do_rt_sigreturn(env, frame_addr);
140
141 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
142 goto badframe;
143 }
144
145 target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
146 set_sigmask(&set);
147
148 restore_sigcontext(&frame->uc.tuc_mcontext, env);
149
150 target_restore_altstack(&frame->uc.tuc_stack, env);
151
152 unlock_user_struct(frame, frame_addr, 0);
153 return -QEMU_ESIGRETURN;
154
155 badframe:
156 unlock_user_struct(frame, frame_addr, 0);
157 force_sig(TARGET_SIGSEGV);
158 return -QEMU_ESIGRETURN;
159 }
160
161 void setup_sigtramp(abi_ulong sigtramp_page)
162 {
163 uint32_t *tramp = lock_user(VERIFY_WRITE, sigtramp_page, 8, 0);
164 assert(tramp != NULL);
165
166 /*
167 * addi r12, r0, __NR_rt_sigreturn
168 * brki r14, 0x8
169 */
170 __put_user(0x31800000U | TARGET_NR_rt_sigreturn, tramp);
171 __put_user(0xb9cc0008U, tramp + 1);
172
173 default_rt_sigreturn = sigtramp_page;
174 unlock_user(tramp, sigtramp_page, 8);
175 }