1 /* $NetBSD: irix_prctl.c,v 1.49 2009/03/18 16:00:16 cegger Exp $ */
4 * Copyright (c) 2001-2002 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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>
42 #include <sys/malloc.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
;
70 struct lwp
*isc_parent_lwp
;
71 struct irix_share_group
*isc_share_group
;
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
,
80 static void irix_isrr_debug(struct proc
*);
82 static void irix_isrr_cleanup(struct proc
*);
85 irix_sys_prctl(struct lwp
*l
, const struct irix_sys_prctl_args
*uap
, register_t
*retval
)
88 syscallarg(unsigned) option;
89 syscallarg(void *) arg1;
91 struct proc
*p
= l
->l_proc
;
92 unsigned int option
= SCARG(uap
, option
);
95 printf("irix_sys_prctl(): option = %d\n", option
);
99 case IRIX_PR_GETSHMASK
: { /* Get shared resources */
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 */
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
;
127 case IRIX_PR_LASTSHEXIT
: /* "Last sproc exit" */
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
;
137 ied
= (struct irix_emuldata
*)p
->p_emuldata
;
138 if ((isg
= ied
->ied_share_group
) == NULL
) {
144 rw_enter(&isg
->isg_lock
, RW_READER
);
145 LIST_FOREACH(iedp
, &isg
->isg_head
, ied_sglist
)
147 rw_exit(&isg
->isg_lock
);
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;
162 case IRIX_PR_ISBLOCKED
: { /* Is process blocked? */
163 pid_t pid
= (pid_t
)(uintptr_t)SCARG(uap
, arg1
);
164 struct irix_emuldata
*ied
;
170 if ((target
= pfind(pid
)) == NULL
)
173 if (irix_check_exec(target
) == 0)
176 if (kauth_authorize_process(l
->l_cred
, KAUTH_PROCESS_CANSEE
,
177 target
, KAUTH_ARG(KAUTH_REQ_PROCESS_CANSEE_ENTRY
), NULL
,
181 ied
= (struct irix_emuldata
*)(target
->p_emuldata
);
182 *retval
= (ied
->ied_procblk_count
< 0);
188 printf("Warning: call to unimplemented prctl() command %d\n",
198 irix_sys_pidsprocsp(struct lwp
*l
, const struct irix_sys_pidsprocsp_args
*uap
, register_t
*retval
)
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;
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
)
220 syscallarg(void *) entry;
221 syscallarg(unsigned) inh;
222 syscallarg(void *) arg;
223 syscallarg(void *) sp;
224 syscallarg(irix_size_t) len;
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
)
235 syscallarg(void *) entry;
236 syscallarg(unsigned) inh;
237 syscallarg(void *) arg;
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
);
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
;
251 struct exec_vmcmd vmc
;
254 struct irix_sproc_child_args
*isc
;
255 struct irix_emuldata
*ied
;
256 struct irix_emuldata
*iedp
;
257 struct irix_share_group
*isg
= NULL
;
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
);
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
);
296 rw_exit(&isg
->isg_lock
);
298 ied
->ied_share_group
= isg
;
302 * Setting up child stack
304 if (inh
& IRIX_PR_SADDR
) {
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
;
325 printf("irix_sproc(): new stack addr=0x%08lx, len=0x%08lx\n",
326 (u_long
)sp
, (u_long
)len
);
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
));
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
)
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
);
356 isc
->isc_entry
= entry
;
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)
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);
381 retval
[0] = (register_t
)p2
->p_pid
;
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
;
398 struct irix_emuldata
*ied
;
399 struct irix_emuldata
*parent_ied
;
402 printf("irix_sproc_child()\n");
405 * Handle shared VM space. The process private arena is not shared
407 if (inh
& IRIX_PR_SADDR
) {
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
;
428 /* If this is a private region, skip */
429 if (isrr
->isrr_shared
== IRIX_ISRR_PRIVATE
)
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);
437 printf("irix_sproc_child(): error %d\n", error
);
439 isc
->isc_child_done
= 1;
440 wakeup(&isc
->isc_child_done
);
441 mutex_enter(proc_lock
);
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
);
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
) {
464 kauth_cred_hold(parent
->p_cred
);
465 p2
->p_cred
= parent
->p_cred
;
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
);
519 irix_sys_procblk(struct lwp
*l
, const struct irix_sys_procblk_args
*uap
, register_t
*retval
)
523 syscallarg(pid_t) pid;
524 syscallarg(int) count;
526 int cmd
= SCARG(uap
, cmd
);
527 struct irix_emuldata
*ied
;
528 struct irix_emuldata
*iedp
;
529 struct irix_share_group
*isg
;
533 int error
, last_error
;
534 struct irix_sys_procblk_args cup
;
536 /* Find the process */
537 if ((target
= pfind(SCARG(uap
, pid
))) == NULL
)
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)
546 /* Is it an IRIX process? */
547 if (irix_check_exec(target
) == 0)
550 ied
= (struct irix_emuldata
*)(target
->p_emuldata
);
551 oldcount
= ied
->ied_procblk_count
;
554 case IRIX_PROCBLK_BLOCK
:
555 ied
->ied_procblk_count
--;
558 case IRIX_PROCBLK_UNBLOCK
:
559 ied
->ied_procblk_count
++;
562 case IRIX_PROCBLK_COUNT
:
563 if (SCARG(uap
, count
) > IRIX_PR_MAXBLOCKCNT
||
564 SCARG(uap
, count
) < IRIX_PR_MINBLOCKCNT
)
566 ied
->ied_procblk_count
= SCARG(uap
, count
);
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
);
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
) {
588 /* Recall procblk for this process */
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
);
597 rw_exit(&isg
->isg_lock
);
602 printf("Warning: unimplemented IRIX procblk command %d\n", cmd
);
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
);
622 irix_prda_init(struct proc
*p
)
625 struct exec_vmcmd evc
;
626 struct irix_prda
*ip
;
627 struct irix_prda_sys ips
;
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
;
637 l
= LIST_FIRST(&p
->p_lwps
);
640 if ((error
= (*evc
.ev_proc
)(l
, &evc
)) != 0)
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
));
658 /* Remeber the PRDA is private */
659 irix_isrr_insert((vaddr_t
)IRIX_PRDA
, sizeof(ips
), IRIX_ISRR_PRIVATE
, p
);
665 irix_vm_fault(struct proc
*p
, vaddr_t vaddr
, vm_prot_t access_type
)
668 struct irix_emuldata
*ied
;
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
);
681 rw_exit(&ied
->ied_share_group
->isg_lock
);
687 * Propagate changes to address space to other members of the share group
690 irix_vm_sync(struct proc
*p
)
693 struct irix_emuldata
*iedp
;
694 struct irix_emuldata
*ied
= (struct irix_emuldata
*)p
->p_emuldata
;
695 struct irix_shared_regions_rec
*isrr
;
701 LIST_FOREACH(iedp
, &ied
->ied_share_group
->isg_head
, ied_sglist
) {
702 if (iedp
->ied_shareaddr
!= 1 || iedp
->ied_p
== p
)
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
)
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
;
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);
736 mutex_enter(proc_lock
);
737 killproc(pp
, "failed to keep share group VM in sync");
738 mutex_exit(proc_lock
);
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
;
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.
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
;
772 start
= trunc_page(start
);
773 len
= round_page(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
);
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
)
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
);
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 */
815 irix_isrr_cleanup(p
);
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 */
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
)
850 if (end
>= cur_end
) { /* overlap */
851 LIST_REMOVE(isrr
, isrr_list
);
852 free(isrr
, M_EMULDATA
);
853 /* isrr is now invalid */
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
;
869 irix_isrr_cleanup(p
);
877 * Cleanup the region list by
878 * (1) removing regions with length 0, and
879 * (2) merging contiguous regions with the same status
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
);
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
);
900 if (new_isrr
== NULL
)
903 if (isrr
->isrr_shared
== new_isrr
->isrr_shared
) {
904 isrr
->isrr_len
+= new_isrr
->isrr_len
;
905 new_isrr
->isrr_len
= 0;
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
,
930 #endif /* DEBUG_IRIX */