No empty .Rs/.Re
[netbsd-mini2440.git] / sys / compat / irix / irix_prctl.c
blob02b31d178167ee710352218396d254ef32bedd48
1 /* $NetBSD: irix_prctl.c,v 1.49 2009/03/18 16:00:16 cegger Exp $ */
3 /*-
4 * Copyright (c) 2001-2002 The NetBSD Foundation, Inc.
5 * All rights reserved.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Emmanuel Dreyfus.
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.
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.
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: irix_prctl.c,v 1.49 2009/03/18 16:00:16 cegger Exp $");
35 #include <sys/errno.h>
36 #include <sys/types.h>
37 #include <sys/param.h>
38 #include <sys/signal.h>
39 #include <sys/signalvar.h>
40 #include <sys/systm.h>
41 #include <sys/exec.h>
42 #include <sys/malloc.h>
43 #include <sys/pool.h>
44 #include <sys/rwlock.h>
45 #include <sys/filedesc.h>
46 #include <sys/vnode.h>
47 #include <sys/resourcevar.h>
48 #include <sys/kauth.h>
50 #include <uvm/uvm_extern.h>
51 #include <uvm/uvm_map.h>
53 #include <machine/regnum.h>
54 #include <machine/vmparam.h>
56 #include <compat/svr4/svr4_types.h>
58 #include <compat/irix/irix_types.h>
59 #include <compat/irix/irix_exec.h>
60 #include <compat/irix/irix_prctl.h>
61 #include <compat/irix/irix_signal.h>
62 #include <compat/irix/irix_syscallargs.h>
64 struct irix_sproc_child_args {
65 struct proc **isc_proc;
66 void *isc_entry;
67 void *isc_arg;
68 size_t isc_len;
69 int isc_inh;
70 struct lwp *isc_parent_lwp;
71 struct irix_share_group *isc_share_group;
72 int isc_child_done;
74 static void irix_sproc_child(struct irix_sproc_child_args *);
75 static int irix_sproc(void *, unsigned int, void *, void *, size_t,
76 pid_t, struct lwp *, register_t *);
77 static struct irix_shared_regions_rec *irix_isrr_create(vaddr_t,
78 vsize_t, int);
79 #ifdef DEBUG_IRIX
80 static void irix_isrr_debug(struct proc *);
81 #endif
82 static void irix_isrr_cleanup(struct proc *);
84 int
85 irix_sys_prctl(struct lwp *l, const struct irix_sys_prctl_args *uap, register_t *retval)
87 /* {
88 syscallarg(unsigned) option;
89 syscallarg(void *) arg1;
90 } */
91 struct proc *p = l->l_proc;
92 unsigned int option = SCARG(uap, option);
94 #ifdef DEBUG_IRIX
95 printf("irix_sys_prctl(): option = %d\n", option);
96 #endif
98 switch(option) {
99 case IRIX_PR_GETSHMASK: { /* Get shared resources */
100 struct proc *p2;
101 int shmask = 0;
102 struct irix_emuldata *ied;
104 p2 = pfind((pid_t)(uintptr_t)SCARG(uap, arg1));
106 if (p2 == p || SCARG(uap, arg1) == NULL) {
107 /* XXX return our own shmask */
108 return 0;
111 if (p2 == NULL)
112 return EINVAL;
114 ied = (struct irix_emuldata *)p->p_emuldata;
115 if (ied->ied_shareaddr)
116 shmask |= IRIX_PR_SADDR;
117 if (p->p_fd == p2->p_fd)
118 shmask |= IRIX_PR_SFDS;
119 if (p->p_cwdi == p2->p_cwdi)
120 shmask |= (IRIX_PR_SDIR|IRIX_PR_SUMASK);
122 *retval = (register_t)shmask;
123 return 0;
124 break;
127 case IRIX_PR_LASTSHEXIT: /* "Last sproc exit" */
128 /* We no nothing */
129 break;
131 case IRIX_PR_GETNSHARE: { /* Number of sproc share group memb.*/
132 struct irix_emuldata *ied;
133 struct irix_emuldata *iedp;
134 struct irix_share_group *isg;
135 int count;
137 ied = (struct irix_emuldata *)p->p_emuldata;
138 if ((isg = ied->ied_share_group) == NULL) {
139 *retval = 0;
140 return 0;
143 count = 0;
144 rw_enter(&isg->isg_lock, RW_READER);
145 LIST_FOREACH(iedp, &isg->isg_head, ied_sglist)
146 count++;
147 rw_exit(&isg->isg_lock);
149 *retval = count;
150 return 0;
151 break;
154 case IRIX_PR_TERMCHILD: { /* Get SIGHUP when parent's exit */
155 struct irix_emuldata *ied;
157 ied = (struct irix_emuldata *)(p->p_emuldata);
158 ied->ied_termchild = 1;
159 break;
162 case IRIX_PR_ISBLOCKED: { /* Is process blocked? */
163 pid_t pid = (pid_t)(uintptr_t)SCARG(uap, arg1);
164 struct irix_emuldata *ied;
165 struct proc *target;
167 if (pid == 0)
168 pid = p->p_pid;
170 if ((target = pfind(pid)) == NULL)
171 return ESRCH;
173 if (irix_check_exec(target) == 0)
174 return 0;
176 if (kauth_authorize_process(l->l_cred, KAUTH_PROCESS_CANSEE,
177 target, KAUTH_ARG(KAUTH_REQ_PROCESS_CANSEE_ENTRY), NULL,
178 NULL) != 0)
179 return EPERM;
181 ied = (struct irix_emuldata *)(target->p_emuldata);
182 *retval = (ied->ied_procblk_count < 0);
183 return 0;
184 break;
187 default:
188 printf("Warning: call to unimplemented prctl() command %d\n",
189 option);
190 return EINVAL;
191 break;
193 return 0;
198 irix_sys_pidsprocsp(struct lwp *l, const struct irix_sys_pidsprocsp_args *uap, register_t *retval)
200 /* {
201 syscallarg(void *) entry;
202 syscallarg(unsigned) inh;
203 syscallarg(void *) arg;
204 syscallarg(void *) sp;
205 syscallarg(irix_size_t) len;
206 syscallarg(irix_pid_t) pid;
207 } */
209 /* pid is ignored for now */
210 printf("Warning: unsupported pid argument to IRIX sproc\n");
212 return irix_sproc(SCARG(uap, entry), SCARG(uap, inh), SCARG(uap, arg),
213 SCARG(uap, sp), SCARG(uap, len), SCARG(uap, pid), l, retval);
217 irix_sys_sprocsp(struct lwp *l, const struct irix_sys_sprocsp_args *uap, register_t *retval)
219 /* {
220 syscallarg(void *) entry;
221 syscallarg(unsigned) inh;
222 syscallarg(void *) arg;
223 syscallarg(void *) sp;
224 syscallarg(irix_size_t) len;
225 } */
227 return irix_sproc(SCARG(uap, entry), SCARG(uap, inh), SCARG(uap, arg),
228 SCARG(uap, sp), SCARG(uap, len), 0, l, retval);
232 irix_sys_sproc(struct lwp *l, const struct irix_sys_sproc_args *uap, register_t *retval)
234 /* {
235 syscallarg(void *) entry;
236 syscallarg(unsigned) inh;
237 syscallarg(void *) arg;
238 } */
239 struct proc *p = l->l_proc;
241 return irix_sproc(SCARG(uap, entry), SCARG(uap, inh), SCARG(uap, arg),
242 NULL, p->p_rlimit[RLIMIT_STACK].rlim_cur, 0, l, retval);
246 static int
247 irix_sproc(void *entry, unsigned int inh, void *arg, void *sp, size_t len, pid_t pid, struct lwp *l, register_t *retval)
249 struct proc *p = l->l_proc;
250 int bsd_flags = 0;
251 struct exec_vmcmd vmc;
252 int error;
253 struct proc *p2;
254 struct irix_sproc_child_args *isc;
255 struct irix_emuldata *ied;
256 struct irix_emuldata *iedp;
257 struct irix_share_group *isg = NULL;
258 segsz_t stacksize;
260 #ifdef DEBUG_IRIX
261 printf("irix_sproc(): entry = %p, inh = %x, arg = %p, sp = 0x%08lx, len = 0x%08lx, pid = %d\n", entry, inh, arg, (u_long)sp, (u_long)len, pid);
262 #endif
264 if (len == 0)
265 return EINVAL;
267 if (inh & IRIX_PR_SFDS)
268 bsd_flags |= FORK_SHAREFILES;
269 if (inh & IRIX_PR_SUMASK && inh & IRIX_PR_SDIR) {
270 bsd_flags |= FORK_SHARECWD;
271 /* Forget them so that we don't get warning below */
272 inh &= ~(IRIX_PR_SUMASK|IRIX_PR_SDIR);
274 /* We know how to do PR_SUMASK and PR_SDIR together only */
275 if (inh & IRIX_PR_SUMASK)
276 printf("Warning: unimplemented IRIX sproc flag PR_SUMASK\n");
277 if (inh & IRIX_PR_SDIR)
278 printf("Warning: unimplemented IRIX sproc flag PR_SDIR\n");
279 if (inh & IRIX_PR_SULIMIT)
280 bsd_flags |= FORK_SHARELIMIT;
283 * If relevant, initialize the share group structure
285 ied = (struct irix_emuldata *)(p->p_emuldata);
286 if (ied->ied_share_group == NULL) {
287 isg = malloc(sizeof(struct irix_share_group),
288 M_EMULDATA, M_WAITOK);
289 rw_init(&isg->isg_lock);
290 isg->isg_refcount = 0;
292 rw_enter(&isg->isg_lock, RW_WRITER);
293 LIST_INIT(&isg->isg_head);
294 LIST_INSERT_HEAD(&isg->isg_head, ied, ied_sglist);
295 isg->isg_refcount++;
296 rw_exit(&isg->isg_lock);
298 ied->ied_share_group = isg;
302 * Setting up child stack
304 if (inh & IRIX_PR_SADDR) {
305 if (sp == NULL) {
307 * All share group members have vm_maxsaddr set
308 * to the bottom of the lowest stack in address space,
309 * therefore we map the new stack there.
311 sp = p->p_vmspace->vm_maxsaddr;
313 /* Compute new stacks's bottom address */
314 sp = (void *)trunc_page((u_long)sp - len);
317 /* Now map the new stack */
318 memset(&vmc, 0, sizeof(vmc));
319 vmc.ev_addr = trunc_page((u_long)sp);
320 vmc.ev_len = round_page(len);
321 vmc.ev_prot = UVM_PROT_RWX;
322 vmc.ev_flags = UVM_FLAG_COPYONW|UVM_FLAG_FIXED|UVM_FLAG_OVERLAY;
323 vmc.ev_proc = vmcmd_map_zero;
324 #ifdef DEBUG_IRIX
325 printf("irix_sproc(): new stack addr=0x%08lx, len=0x%08lx\n",
326 (u_long)sp, (u_long)len);
327 #endif
328 /* Normally it cannot be NULL since we just initialized it */
329 if ((isg = ied->ied_share_group) == NULL)
330 panic("irix_sproc: NULL ied->ied_share_group");
332 IRIX_VM_SYNC(p, error = (*vmc.ev_proc)(l, &vmc));
333 if (error)
334 return error;
336 /* Update stack parameters for the share group members */
337 ied = (struct irix_emuldata *)p->p_emuldata;
338 stacksize = ((char *)p->p_vmspace->vm_minsaddr - (char *)sp)
339 / PAGE_SIZE;
342 rw_enter(&isg->isg_lock, RW_WRITER);
343 LIST_FOREACH(iedp, &isg->isg_head, ied_sglist) {
344 iedp->ied_p->p_vmspace->vm_maxsaddr = (void *)sp;
345 iedp->ied_p->p_vmspace->vm_ssize = stacksize;
347 rw_exit(&isg->isg_lock);
351 * Arguments for irix_sproc_child()
352 * This will be freed by the child.
354 isc = malloc(sizeof(*isc), M_TEMP, M_WAITOK);
355 isc->isc_proc = &p2;
356 isc->isc_entry = entry;
357 isc->isc_arg = arg;
358 isc->isc_len = len;
359 isc->isc_inh = inh;
360 isc->isc_parent_lwp = l;
361 isc->isc_share_group = isg;
362 isc->isc_child_done = 0;
364 if (inh & IRIX_PR_SADDR) {
365 ied->ied_shareaddr = 1;
368 if ((error = fork1(l, bsd_flags, SIGCHLD, (void *)sp, len,
369 (void *)irix_sproc_child, (void *)isc, retval, &p2)) != 0)
370 return error;
373 * The child needs the parent to stay alive until it has
374 * copied a few things from it. We sleep whatever happen
375 * until the child is done.
377 while (!isc->isc_child_done)
378 (void)tsleep(&isc->isc_child_done, PZERO, "sproc", 0);
379 free(isc, M_TEMP);
381 retval[0] = (register_t)p2->p_pid;
382 retval[1] = 0;
384 return 0;
387 static void
388 irix_sproc_child(struct irix_sproc_child_args *isc)
390 struct proc *p2 = *isc->isc_proc;
391 struct lwp *l2 = curlwp;
392 int inh = isc->isc_inh;
393 struct lwp *lparent = isc->isc_parent_lwp;
394 struct proc *parent = lparent->l_proc;
395 struct frame *tf = (struct frame *)l2->l_md.md_regs;
396 struct frame *ptf = (struct frame *)lparent->l_md.md_regs;
397 kauth_cred_t pc;
398 struct irix_emuldata *ied;
399 struct irix_emuldata *parent_ied;
401 #ifdef DEBUG_IRIX
402 printf("irix_sproc_child()\n");
403 #endif
405 * Handle shared VM space. The process private arena is not shared
407 if (inh & IRIX_PR_SADDR) {
408 int error;
409 vaddr_t minp, maxp;
410 vsize_t len;
411 struct irix_shared_regions_rec *isrr;
414 * First, unmap the whole address space
416 minp = vm_map_min(&p2->p_vmspace->vm_map);
417 maxp = vm_map_max(&p2->p_vmspace->vm_map);
418 uvm_unmap(&p2->p_vmspace->vm_map, minp, maxp);
421 * Now, copy the mapping from the parent for shared regions
423 parent_ied = (struct irix_emuldata *)parent->p_emuldata;
424 LIST_FOREACH(isrr, &parent_ied->ied_shared_regions, isrr_list) {
425 minp = isrr->isrr_start;
426 len = isrr->isrr_len;
427 maxp = minp + len;
428 /* If this is a private region, skip */
429 if (isrr->isrr_shared == IRIX_ISRR_PRIVATE)
430 continue;
432 /* Copy the new mapping from the parent */
433 error = uvm_map_extract(&parent->p_vmspace->vm_map,
434 minp, len, &p2->p_vmspace->vm_map, &minp, 0);
435 if (error != 0) {
436 #ifdef DEBUG_IRIX
437 printf("irix_sproc_child(): error %d\n", error);
438 #endif
439 isc->isc_child_done = 1;
440 wakeup(&isc->isc_child_done);
441 mutex_enter(proc_lock);
442 killproc(p2,
443 "failed to initialize share group VM");
444 mutex_exit(proc_lock);
448 /* Map and initialize the process private arena (unshared) */
449 error = irix_prda_init(p2);
450 if (error != 0) {
451 isc->isc_child_done = 1;
452 wakeup(&isc->isc_child_done);
453 mutex_enter(proc_lock);
454 killproc(p2, "failed to initialize the PRDA");
455 mutex_exit(proc_lock);
460 * Handle shared process UID/GID
462 if (inh & IRIX_PR_SID) {
463 pc = p2->p_cred;
464 kauth_cred_hold(parent->p_cred);
465 p2->p_cred = parent->p_cred;
466 kauth_cred_free(pc);
470 * Setup PC to return to the child entry point
472 tf->f_regs[_R_PC] = (unsigned long)isc->isc_entry;
473 tf->f_regs[_R_RA] = 0;
476 * Setup child arguments
478 tf->f_regs[_R_A0] = (unsigned long)isc->isc_arg;
479 tf->f_regs[_R_A1] = 0;
480 tf->f_regs[_R_A2] = 0;
481 tf->f_regs[_R_A3] = 0;
482 if (ptf->f_regs[_R_S3] == (unsigned long)isc->isc_len) {
483 tf->f_regs[_R_S0] = ptf->f_regs[_R_S0];
484 tf->f_regs[_R_S1] = ptf->f_regs[_R_S1];
485 tf->f_regs[_R_S2] = ptf->f_regs[_R_S2];
486 tf->f_regs[_R_S3] = ptf->f_regs[_R_S3];
490 * Join the share group
492 ied = (struct irix_emuldata *)(p2->p_emuldata);
493 parent_ied = (struct irix_emuldata *)(parent->p_emuldata);
494 ied->ied_share_group = parent_ied->ied_share_group;
496 rw_enter(&ied->ied_share_group->isg_lock, RW_WRITER);
497 LIST_INSERT_HEAD(&ied->ied_share_group->isg_head, ied, ied_sglist);
498 ied->ied_share_group->isg_refcount++;
499 rw_exit(&ied->ied_share_group->isg_lock);
501 if (inh & IRIX_PR_SADDR)
502 ied->ied_shareaddr = 1;
505 * wakeup the parent as it can now die without
506 * causing a panic in the child.
508 isc->isc_child_done = 1;
509 wakeup(&isc->isc_child_done);
512 * Return to userland for a newly created process
514 child_return((void *)l2);
515 return;
519 irix_sys_procblk(struct lwp *l, const struct irix_sys_procblk_args *uap, register_t *retval)
521 /* {
522 syscallarg(int) cmd;
523 syscallarg(pid_t) pid;
524 syscallarg(int) count;
525 } */
526 int cmd = SCARG(uap, cmd);
527 struct irix_emuldata *ied;
528 struct irix_emuldata *iedp;
529 struct irix_share_group *isg;
530 struct proc *target;
531 int oldcount;
532 struct lwp *ied_lwp;
533 int error, last_error;
534 struct irix_sys_procblk_args cup;
536 /* Find the process */
537 if ((target = pfind(SCARG(uap, pid))) == NULL)
538 return ESRCH;
540 /* May we stop it? */
541 /* XXX-elad: Is hardcoding SIGSTOP here correct? */
542 if (kauth_authorize_process(l->l_cred, KAUTH_PROCESS_SIGNAL, target,
543 KAUTH_ARG(SIGSTOP), NULL, NULL) != 0)
544 return EPERM;
546 /* Is it an IRIX process? */
547 if (irix_check_exec(target) == 0)
548 return EPERM;
550 ied = (struct irix_emuldata *)(target->p_emuldata);
551 oldcount = ied->ied_procblk_count;
553 switch (cmd) {
554 case IRIX_PROCBLK_BLOCK:
555 ied->ied_procblk_count--;
556 break;
558 case IRIX_PROCBLK_UNBLOCK:
559 ied->ied_procblk_count++;
560 break;
562 case IRIX_PROCBLK_COUNT:
563 if (SCARG(uap, count) > IRIX_PR_MAXBLOCKCNT ||
564 SCARG(uap, count) < IRIX_PR_MINBLOCKCNT)
565 return EINVAL;
566 ied->ied_procblk_count = SCARG(uap, count);
567 break;
569 case IRIX_PROCBLK_BLOCKALL:
570 case IRIX_PROCBLK_UNBLOCKALL:
571 case IRIX_PROCBLK_COUNTALL:
572 SCARG(&cup, cmd) = cmd -IRIX_PROCBLK_ONLYONE;
573 SCARG(&cup, count) = SCARG(uap, count);
574 last_error = 0;
577 * If the process does not belong to a
578 * share group, do it just for the process
580 if ((isg = ied->ied_share_group) == NULL) {
581 SCARG(&cup, pid) = SCARG(uap, pid);
582 return irix_sys_procblk(l, &cup, retval);
585 rw_enter(&isg->isg_lock, RW_READER);
586 LIST_FOREACH(iedp, &isg->isg_head, ied_sglist) {
587 struct proc *p;
588 /* Recall procblk for this process */
589 p = iedp->ied_p;
590 SCARG(&cup, pid) = p->p_pid;
591 ied_lwp = LIST_FIRST(&p->p_lwps);
592 KASSERT(ied_lwp != NULL);
593 error = irix_sys_procblk(ied_lwp, &cup, retval);
594 if (error != 0)
595 last_error = error;
597 rw_exit(&isg->isg_lock);
599 return last_error;
600 break;
601 default:
602 printf("Warning: unimplemented IRIX procblk command %d\n", cmd);
603 return EINVAL;
604 break;
608 * We emulate the process block/unblock using SIGSTOP and SIGCONT
609 * signals. This is not very accurate, since on IRIX theses way
610 * of blocking a process are completely separated.
612 if (oldcount >= 0 && ied->ied_procblk_count < 0) /* blocked */
613 psignal(target, SIGSTOP);
615 if (oldcount < 0 && ied->ied_procblk_count >= 0) /* unblocked */
616 psignal(target, SIGCONT);
618 return 0;
622 irix_prda_init(struct proc *p)
624 int error;
625 struct exec_vmcmd evc;
626 struct irix_prda *ip;
627 struct irix_prda_sys ips;
628 struct lwp *l;
630 memset(&evc, 0, sizeof(evc));
631 evc.ev_addr = (u_long)IRIX_PRDA;
632 evc.ev_len = sizeof(struct irix_prda);
633 evc.ev_prot = UVM_PROT_RW;
634 evc.ev_proc = *vmcmd_map_zero;
636 /* XXXSMP */
637 l = LIST_FIRST(&p->p_lwps);
638 KASSERT(l != NULL);
640 if ((error = (*evc.ev_proc)(l, &evc)) != 0)
641 return error;
643 ip = (struct irix_prda *)IRIX_PRDA;
644 memset(&ips, 0, sizeof(ips));
646 ips.t_pid = p->p_pid;
648 * The PRDA ID must be unique for a PRDA. IRIX uses a small
649 * integer, but we don't know how it is chosen. The PID
650 * should be unique enough to get the work done.
652 ips.t_prid = p->p_pid;
654 error = copyout(&ips, (void *)&ip->sys_prda.prda_sys, sizeof(ips));
655 if (error)
656 return error;
658 /* Remeber the PRDA is private */
659 irix_isrr_insert((vaddr_t)IRIX_PRDA, sizeof(ips), IRIX_ISRR_PRIVATE, p);
661 return 0;
665 irix_vm_fault(struct proc *p, vaddr_t vaddr, vm_prot_t access_type)
667 int error;
668 struct irix_emuldata *ied;
669 struct vm_map *map;
671 ied = (struct irix_emuldata *)p->p_emuldata;
672 map = &p->p_vmspace->vm_map;
674 if (ied->ied_share_group == NULL || ied->ied_shareaddr == 0)
675 return uvm_fault(map, vaddr, access_type);
677 /* share group version */
678 rw_enter(&ied->ied_share_group->isg_lock, RW_WRITER);
679 error = uvm_fault(map, vaddr, access_type);
680 irix_vm_sync(p);
681 rw_exit(&ied->ied_share_group->isg_lock);
683 return error;
687 * Propagate changes to address space to other members of the share group
689 void
690 irix_vm_sync(struct proc *p)
692 struct proc *pp;
693 struct irix_emuldata *iedp;
694 struct irix_emuldata *ied = (struct irix_emuldata *)p->p_emuldata;
695 struct irix_shared_regions_rec *isrr;
696 vaddr_t minp;
697 vaddr_t maxp;
698 vsize_t len;
699 int error;
701 LIST_FOREACH(iedp, &ied->ied_share_group->isg_head, ied_sglist) {
702 if (iedp->ied_shareaddr != 1 || iedp->ied_p == p)
703 continue;
705 pp = iedp->ied_p;
707 error = 0;
708 /* for each region in the target process ... */
709 LIST_FOREACH(isrr, &iedp->ied_shared_regions, isrr_list) {
710 /* skip regions private to the target process */
711 if (isrr->isrr_shared == IRIX_ISRR_PRIVATE)
712 continue;
715 * XXX We should also skip regions private to the
716 * original process...
719 /* The region is shared */
720 minp = isrr->isrr_start;
721 len = isrr->isrr_len;
722 maxp = minp + len;
724 /* Drop the region */
725 uvm_unmap(&pp->p_vmspace->vm_map, minp, maxp);
727 /* Clone it from the parent */
728 error = uvm_map_extract(&p->p_vmspace->vm_map,
729 minp, len, &pp->p_vmspace->vm_map, &minp, 0);
731 if (error)
732 break;
735 if (error) {
736 mutex_enter(proc_lock);
737 killproc(pp, "failed to keep share group VM in sync");
738 mutex_exit(proc_lock);
742 return;
745 static struct irix_shared_regions_rec *
746 irix_isrr_create(vaddr_t start, vsize_t len, int shared)
748 struct irix_shared_regions_rec *new_isrr;
750 new_isrr = malloc(sizeof(struct irix_shared_regions_rec),
751 M_EMULDATA, M_WAITOK);
752 new_isrr->isrr_start = start;
753 new_isrr->isrr_len = len;
754 new_isrr->isrr_shared = shared;
756 return new_isrr;
760 * Insert a record for a new region in the list. The new region may be
761 * overlaping or be included in an existing region.
763 void
764 irix_isrr_insert(vaddr_t start, vsize_t len, int shared, struct proc *p)
766 struct irix_emuldata *ied = (struct irix_emuldata *)p->p_emuldata;
767 struct irix_shared_regions_rec *isrr;
768 struct irix_shared_regions_rec *new_isrr;
769 vaddr_t end, cur_start, cur_end;
770 int cur_shared;
772 start = trunc_page(start);
773 len = round_page(len);
774 end = start + len;
776 new_isrr = irix_isrr_create(start, len, shared);
778 /* Do we need to insert the new region at the begining of the list? */
779 if (LIST_EMPTY(&ied->ied_shared_regions) ||
780 LIST_FIRST(&ied->ied_shared_regions)->isrr_start > start) {
781 LIST_INSERT_HEAD(&ied->ied_shared_regions, new_isrr, isrr_list);
782 } else {
783 /* Find the place where to insert it */
784 LIST_FOREACH(isrr, &ied->ied_shared_regions, isrr_list) {
785 cur_start = isrr->isrr_start;
786 cur_end = isrr->isrr_start + isrr->isrr_len;
787 cur_shared = isrr->isrr_shared;
790 * if there is no intersection between inserted
791 * and current region: skip to next region
793 if (cur_end <= start)
794 continue;
797 * if new region is included into the current
798 * region. Right-crop the current region,
799 * insert a new one, and insert a new region
800 * for the end of the split region
802 if (cur_end > end && cur_start < start) {
803 isrr->isrr_len = start - isrr->isrr_start;
804 LIST_INSERT_AFTER(isrr, new_isrr, isrr_list);
805 isrr = new_isrr;
807 new_isrr = irix_isrr_create(end,
808 cur_end - end, cur_shared);
809 LIST_INSERT_AFTER(isrr, new_isrr, isrr_list);
811 /* Nothing more to do, exit now */
812 #ifdef DEBUG_IRIX
813 irix_isrr_debug(p);
814 #endif
815 irix_isrr_cleanup(p);
816 #ifdef DEBUG_IRIX
817 irix_isrr_debug(p);
818 #endif
819 return;
823 * if inserted block overlap some part
824 * of current region: right-crop current region
825 * and insert the new region
827 if (start < cur_end) {
828 isrr->isrr_len = start - cur_start;
829 LIST_INSERT_AFTER(isrr, new_isrr, isrr_list);
831 /* exit the FOREACH loop */
832 break;
838 * At this point, we inserted the new region (new_isrr) but
839 * it may be overlaping with next regions, so we need to clean
840 * this up and remove or crop next regions
842 LIST_FOREACH(isrr, &ied->ied_shared_regions, isrr_list) {
843 cur_start = isrr->isrr_start;
844 cur_end = isrr->isrr_start + isrr->isrr_len;
846 /* skip until we get beyond new_isrr */
847 if (cur_start <= start)
848 continue;
850 if (end >= cur_end) { /* overlap */
851 LIST_REMOVE(isrr, isrr_list);
852 free(isrr, M_EMULDATA);
853 /* isrr is now invalid */
854 isrr = new_isrr;
855 continue;
859 * Here end < cur_end, therefore we need to
860 * right-crop the current region
862 isrr->isrr_start = end;
863 isrr->isrr_len = cur_end - end;
864 break;
866 #ifdef DEBUG_IRIX
867 irix_isrr_debug(p);
868 #endif
869 irix_isrr_cleanup(p);
870 #ifdef DEBUG_IRIX
871 irix_isrr_debug(p);
872 #endif
873 return;
877 * Cleanup the region list by
878 * (1) removing regions with length 0, and
879 * (2) merging contiguous regions with the same status
881 static void
882 irix_isrr_cleanup(struct proc *p)
884 struct irix_emuldata *ied = (struct irix_emuldata *)p->p_emuldata;
885 struct irix_shared_regions_rec *isrr;
886 struct irix_shared_regions_rec *new_isrr;
888 isrr = LIST_FIRST(&ied->ied_shared_regions);
889 do {
890 new_isrr = LIST_NEXT(isrr, isrr_list);
892 if (isrr->isrr_len == 0) {
893 LIST_REMOVE(isrr, isrr_list);
894 free(isrr, M_EMULDATA);
895 isrr = new_isrr;
896 if (isrr == NULL)
897 break;
900 if (new_isrr == NULL)
901 break;
903 if (isrr->isrr_shared == new_isrr->isrr_shared) {
904 isrr->isrr_len += new_isrr->isrr_len;
905 new_isrr->isrr_len = 0;
908 isrr = new_isrr;
909 } while (1);
911 return;
915 #ifdef DEBUG_IRIX
916 static void
917 irix_isrr_debug(struct proc *p)
919 struct irix_emuldata *ied = (struct irix_emuldata *)p->p_emuldata;
920 struct irix_shared_regions_rec *isrr;
922 printf("isrr for pid %d\n", p->p_pid);
923 LIST_FOREACH(isrr, &ied->ied_shared_regions, isrr_list) {
924 printf(" addr = %p, len = %p, shared = %d\n",
925 (void *)isrr->isrr_start,
926 (void *)isrr->isrr_len,
927 isrr->isrr_shared);
930 #endif /* DEBUG_IRIX */