1 /* $NetBSD: irix_exec.c,v 1.52 2008/04/29 15:56:11 ad Exp $ */
2
3 /*-
4 * Copyright (c) 2001-2002 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Emmanuel Dreyfus.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: irix_exec.c,v 1.52 2008/04/29 15:56:11 ad Exp $");
34
35 #ifdef _KERNEL_OPT
36 #include "opt_syscall_debug.h"
37 #endif
38
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/proc.h>
42 #include <sys/rwlock.h>
43 #include <sys/exec.h>
44 #include <sys/types.h>
45 #include <sys/malloc.h>
46
47 #include <machine/regnum.h>
48 #include <uvm/uvm_extern.h>
49
50 #include <compat/irix/irix_syscall.h>
51 #include <compat/irix/irix_types.h>
52 #include <compat/irix/irix_exec.h>
53 #include <compat/irix/irix_prctl.h>
54 #include <compat/irix/irix_signal.h>
55 #include <compat/irix/irix_errno.h>
56 #include <compat/irix/irix_sysctl.h>
57 #include <compat/irix/irix_usema.h>
58
59 extern const int native_to_svr4_signo[];
60
61 static void irix_e_proc_exec(struct proc *, struct exec_package *);
62 static void irix_e_proc_fork(struct proc *, struct proc *, int);
63 static void irix_e_proc_exit(struct proc *);
64 static void irix_e_proc_init(struct proc *, struct vmspace *);
65
66 extern struct sysent irix_sysent[];
67 extern const char * const irix_syscallnames[];
68
69 #ifndef __HAVE_SYSCALL_INTERN
70 void irix_syscall(void);
71 #else
72 void irix_syscall_intern(struct proc *);
73 #endif
74
75 /*
76 * Fake sigcode. COMPAT_IRIX does not use it, since the
77 * signal trampoline is provided by libc. However, some
78 * other part of the kernel will be happier if we still
79 * provide non NULL sigcode and esigcode.
80 */
81 char irix_sigcode[] = { 0 };
82
83 const struct emul emul_irix = {
84 "irix",
85 "/emul/irix",
86 #ifndef __HAVE_MINIMAL_EMUL
87 0,
88 native_to_irix_errno,
89 IRIX_SYS_syscall,
90 IRIX_SYS_NSYSENT,
91 #endif
92 irix_sysent,
93 #ifdef SYSCALL_DEBUG
94 irix_syscallnames,
95 #else
96 NULL,
97 #endif
98 irix_sendsig,
99 trapsignal,
100 NULL,
101 irix_sigcode,
102 irix_sigcode,
103 NULL,
104 setregs,
105 irix_e_proc_exec,
106 irix_e_proc_fork,
107 irix_e_proc_exit,
108 NULL,
109 NULL,
110 #ifdef __HAVE_SYSCALL_INTERN
111 irix_syscall_intern,
112 #else
113 irix_syscall,
114 #endif
115 NULL,
116 irix_vm_fault,
117
118 uvm_default_mapaddr,
119 };
120
121 /*
122 * set registers on exec for N32 applications
123 */
124 void
125 irix_n32_setregs(struct lwp *l, struct exec_package *pack, u_long stack)
126 {
127 struct frame *f = (struct frame *)l->l_md.md_regs;
128
129 /* Enable 64 bit instructions (eg: sd) */
130 f->f_regs[_R_SR] |= MIPS3_SR_UX;
131 }
132
133 /*
134 * per-process emuldata allocation
135 */
136 static void
137 irix_e_proc_init(struct proc *p, struct vmspace *vmspace)
138 {
139 struct irix_emuldata *ied;
140 vaddr_t vm_min;
141 vsize_t vm_len;
142
143 if (!p->p_emuldata)
144 p->p_emuldata = malloc(sizeof(struct irix_emuldata),
145 M_EMULDATA, M_WAITOK | M_ZERO);
146
147 ied = p->p_emuldata;
148 ied->ied_p = p;
149
150 LIST_INIT(&ied->ied_shared_regions);
151 vm_min = vm_map_min(&vmspace->vm_map);
152 vm_len = vm_map_max(&vmspace->vm_map) - vm_min;
153 irix_isrr_insert(vm_min, vm_len, IRIX_ISRR_SHARED, p);
154 }
155
156 /*
157 * exec() hook used to allocate per process structures
158 */
159 static void
160 irix_e_proc_exec(struct proc *p, struct exec_package *epp)
161 {
162 int error;
163
164 irix_e_proc_init(p, p->p_vmspace);
165
166 /* Initialize the process private area (PRDA) */
167 error = irix_prda_init(p);
168 #ifdef DEBUG_IRIX
169 if (error != 0)
170 printf("irix_e_proc_exec(): PRDA map failed ");
171 #endif
172 }
173
174 /*
175 * exit() hook used to free per process data structures
176 */
177 static void
178 irix_e_proc_exit(struct proc *p)
179 {
180 struct proc *pp;
181 struct irix_emuldata *ied;
182 struct irix_share_group *isg;
183 struct irix_shared_regions_rec *isrr;
184
185 /*
186 * Send SIGHUP to child process as requested using prctl(2)
187 */
188 mutex_enter(proc_lock);
189 PROCLIST_FOREACH(pp, &allproc) {
190 if ((pp->p_flag & PK_MARKER) != 0)
191 continue;
192 /* Select IRIX processes */
193 if (irix_check_exec(pp) == 0)
194 continue;
195
196 ied = (struct irix_emuldata *)(pp->p_emuldata);
197 if (ied->ied_termchild && pp->p_pptr == p)
198 psignal(pp, native_to_svr4_signo[SIGHUP]);
199 }
200 mutex_exit(proc_lock);
201
202 /*
203 * Remove the process from share group processes list, if relevant.
204 */
205 ied = (struct irix_emuldata *)(p->p_emuldata);
206
207 if ((isg = ied->ied_share_group) != NULL) {
208 rw_enter(&isg->isg_lock, RW_WRITER);
209 LIST_REMOVE(ied, ied_sglist);
210 isg->isg_refcount--;
211
212 if (isg->isg_refcount == 0) {
213 /*
214 * This was the last process in the share group.
215 * Call irix_usema_exit_cleanup() to free in-kernel
216 * structures hold by the share group through
217 * the irix_usync_cntl system call.
218 */
219 irix_usema_exit_cleanup(p, NULL);
220 /*
221 * Free the share group structure (no need to free
222 * the lock since we destroy it now).
223 */
224 rw_destroy(&isg->isg_lock);
225 free(isg, M_EMULDATA);
226 ied->ied_share_group = NULL;
227 } else {
228 /*
229 * There are other processes remaining in the share
230 * group. Call irix_usema_exit_cleanup() to set the
231 * first of them as the owner of the structures
232 * hold in the kernel by the share group.
233 */
234 irix_usema_exit_cleanup(p,
235 LIST_FIRST(&isg->isg_head)->ied_p);
236 rw_exit(&isg->isg_lock);
237 }
238
239 } else {
240 /*
241 * The process is not part of a share group. Call
242 * irix_usema_exit_cleanup() to free in-kernel structures hold
243 * by the process through the irix_usync_cntl system call.
244 */
245 irix_usema_exit_cleanup(p, NULL);
246 }
247
248 /* Free (un)shared region list */
249 while (!LIST_EMPTY(&ied->ied_shared_regions)) {
250 isrr = LIST_FIRST(&ied->ied_shared_regions);
251 LIST_REMOVE(isrr , isrr_list);
252 free(isrr, M_EMULDATA);
253 }
254
255 free(p->p_emuldata, M_EMULDATA);
256 p->p_emuldata = NULL;
257 }
258
259 /*
260 * fork() hook used to allocate per process structures
261 */
262 static void
263 irix_e_proc_fork(p, parent, forkflags)
264 struct proc *p, *parent;
265 int forkflags;
266 {
267 struct irix_emuldata *ied1;
268 struct irix_emuldata *ied2;
269
270 p->p_emuldata = NULL;
271
272 /* Use parent's vmspace because our vmspace may not be setup yet */
273 irix_e_proc_init(p, parent->p_vmspace);
274
275 ied1 = p->p_emuldata;
276 ied2 = parent->p_emuldata;
277
278 (void) memcpy(ied1, ied2, (unsigned)
279 ((char *)&ied1->ied_endcopy - (char *)&ied1->ied_startcopy));
280 }
Cache object: 0edbca0fa479726b0e1e35aa64f77142
|