1 /* $NetBSD: mach_port.c,v 1.56 2005/02/26 23:10:20 perry Exp $ */
2
3 /*-
4 * Copyright (c) 2002-2003 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 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 #include "opt_compat_darwin.h"
40
41 #include <sys/cdefs.h>
42 __KERNEL_RCSID(0, "$NetBSD: mach_port.c,v 1.56 2005/02/26 23:10:20 perry Exp $");
43
44 #include <sys/types.h>
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/signal.h>
48 #include <sys/pool.h>
49 #include <sys/queue.h>
50 #include <sys/malloc.h>
51 #include <sys/proc.h>
52
53 #include <compat/mach/mach_types.h>
54 #include <compat/mach/mach_message.h>
55 #include <compat/mach/mach_port.h>
56 #include <compat/mach/mach_iokit.h>
57 #include <compat/mach/mach_clock.h>
58 #include <compat/mach/mach_exec.h>
59 #include <compat/mach/mach_errno.h>
60 #include <compat/mach/mach_notify.h>
61 #include <compat/mach/mach_services.h>
62 #include <compat/mach/mach_syscallargs.h>
63
64 #ifdef COMPAT_DARWIN
65 #include <compat/darwin/darwin_exec.h>
66 #endif
67
68 /* Right and port pools, list of all rights and its lock */
69 static struct pool mach_port_pool;
70 static struct pool mach_right_pool;
71
72 struct mach_port *mach_bootstrap_port;
73 struct mach_port *mach_clock_port;
74 struct mach_port *mach_io_master_port;
75 struct mach_port *mach_saved_bootstrap_port;
76
77 int
78 mach_sys_reply_port(l, v, retval)
79 struct lwp *l;
80 void *v;
81 register_t *retval;
82 {
83 struct mach_right *mr;
84
85 mr = mach_right_get(mach_port_get(), l, MACH_PORT_TYPE_RECEIVE, 0);
86 *retval = (register_t)mr->mr_name;
87
88 return 0;
89 }
90
91 int
92 mach_sys_thread_self_trap(l, v, retval)
93 struct lwp *l;
94 void *v;
95 register_t *retval;
96 {
97 struct mach_lwp_emuldata *mle;
98 struct mach_right *mr;
99
100 mle = l->l_emuldata;
101 mr = mach_right_get(mle->mle_kernel, l, MACH_PORT_TYPE_SEND, 0);
102 *retval = (register_t)mr->mr_name;
103
104 return 0;
105 }
106
107
108 int
109 mach_sys_task_self_trap(l, v, retval)
110 struct lwp *l;
111 void *v;
112 register_t *retval;
113 {
114 struct mach_emuldata *med;
115 struct mach_right *mr;
116
117 med = (struct mach_emuldata *)l->l_proc->p_emuldata;
118 mr = mach_right_get(med->med_kernel, l, MACH_PORT_TYPE_SEND, 0);
119 *retval = (register_t)mr->mr_name;
120
121 return 0;
122 }
123
124
125 int
126 mach_sys_host_self_trap(l, v, retval)
127 struct lwp *l;
128 void *v;
129 register_t *retval;
130 {
131 struct mach_emuldata *med;
132 struct mach_right *mr;
133
134 med = (struct mach_emuldata *)l->l_proc->p_emuldata;
135 mr = mach_right_get(med->med_host, l, MACH_PORT_TYPE_SEND, 0);
136 *retval = (register_t)mr->mr_name;
137
138 return 0;
139 }
140
141 int
142 mach_port_deallocate(args)
143 struct mach_trap_args *args;
144 {
145 mach_port_deallocate_request_t *req = args->smsg;
146 mach_port_deallocate_reply_t *rep = args->rmsg;
147 size_t *msglen = args->rsize;
148 struct lwp *l = args->l;
149 mach_port_t mn;
150 struct mach_right *mr;
151
152 mn = req->req_name;
153 if ((mr = mach_right_check(mn, l, MACH_PORT_TYPE_REF_RIGHTS)) != NULL)
154 mach_right_put(mr, MACH_PORT_TYPE_REF_RIGHTS);
155
156 *msglen = sizeof(*rep);
157 mach_set_header(rep, req, *msglen);
158
159 rep->rep_retval = 0;
160
161 mach_set_trailer(rep, *msglen);
162
163 return 0;
164 }
165
166 int
167 mach_port_destroy(args)
168 struct mach_trap_args *args;
169 {
170 mach_port_destroy_request_t *req = args->smsg;
171 mach_port_destroy_reply_t *rep = args->rmsg;
172 size_t *msglen = args->rsize;
173 struct lwp *l = args->l;
174 mach_port_t mn;
175 struct mach_right *mr;
176
177 #ifdef DEBUG_MACH
178 printf("mach_port_destroy mn = %x\n", req->req_name);
179 #endif
180 mn = req->req_name;
181 if ((mr = mach_right_check(mn,
182 l, MACH_PORT_TYPE_ALL_RIGHTS)) != NULL) {
183 MACH_PORT_UNREF(mr->mr_port);
184 mr->mr_port = NULL;
185 mach_right_put(mr, MACH_PORT_TYPE_ALL_RIGHTS);
186 }
187
188 *msglen = sizeof(*rep);
189 mach_set_header(rep, req, *msglen);
190
191 rep->rep_retval = 0;
192
193 mach_set_trailer(rep, *msglen);
194
195 return 0;
196 }
197
198 int
199 mach_port_allocate(args)
200 struct mach_trap_args *args;
201 {
202 mach_port_allocate_request_t *req = args->smsg;
203 mach_port_allocate_reply_t *rep = args->rmsg;
204 size_t *msglen = args->rsize;
205 struct lwp *l = args->l;
206 struct mach_right *mr;
207 struct mach_port *mp;
208
209 switch (req->req_right) {
210 case MACH_PORT_RIGHT_RECEIVE:
211 mp = mach_port_get();
212 mr = mach_right_get(mp, l, MACH_PORT_TYPE_RECEIVE, 0);
213 break;
214
215 case MACH_PORT_RIGHT_DEAD_NAME:
216 mr = mach_right_get(NULL, l, MACH_PORT_TYPE_DEAD_NAME, 0);
217 break;
218
219 case MACH_PORT_RIGHT_PORT_SET:
220 mr = mach_right_get(NULL, l, MACH_PORT_TYPE_PORT_SET, 0);
221 break;
222
223 default:
224 uprintf("mach_port_allocate: unknown right %x\n",
225 req->req_right);
226 return mach_msg_error(args, EINVAL);
227 break;
228 }
229
230 *msglen = sizeof(*rep);
231 mach_set_header(rep, req, *msglen);
232
233 rep->rep_retval = 0;
234 rep->rep_name = (mach_port_name_t)mr->mr_name;
235
236 mach_set_trailer(rep, *msglen);
237
238 return 0;
239 }
240
241 int
242 mach_port_insert_right(args)
243 struct mach_trap_args *args;
244 {
245 mach_port_insert_right_request_t *req = args->smsg;
246 mach_port_insert_right_reply_t *rep = args->rmsg;
247 size_t *msglen = args->rsize;
248 struct lwp *l = args->l;
249 mach_port_t name;
250 mach_port_t right;
251 struct mach_right *mr;
252 struct mach_right *nmr;
253
254 name = req->req_name;
255 right = req->req_poly.name;
256 nmr = NULL;
257
258 mr = mach_right_check(right, l, MACH_PORT_TYPE_ALL_RIGHTS);
259 if (mr == NULL)
260 return mach_msg_error(args, EPERM);
261
262 switch (req->req_poly.disposition) {
263 case MACH_MSG_TYPE_MAKE_SEND:
264 case MACH_MSG_TYPE_MOVE_SEND:
265 case MACH_MSG_TYPE_COPY_SEND:
266 nmr = mach_right_get(mr->mr_port,
267 l, MACH_PORT_TYPE_SEND, name);
268 break;
269
270 case MACH_MSG_TYPE_MAKE_SEND_ONCE:
271 case MACH_MSG_TYPE_MOVE_SEND_ONCE:
272 nmr = mach_right_get(mr->mr_port,
273 l, MACH_PORT_TYPE_SEND_ONCE, name);
274 break;
275
276 case MACH_MSG_TYPE_MOVE_RECEIVE:
277 nmr = mach_right_get(mr->mr_port,
278 l, MACH_PORT_TYPE_RECEIVE, name);
279 break;
280
281 default:
282 uprintf("mach_port_insert_right: unknown right %x\n",
283 req->req_poly.disposition);
284 break;
285 }
286
287 *msglen = sizeof(*rep);
288 mach_set_header(rep, req, *msglen);
289
290 rep->rep_retval = 0;
291
292 mach_set_trailer(rep, *msglen);
293
294 return 0;
295 }
296
297 int
298 mach_port_type(args)
299 struct mach_trap_args *args;
300 {
301 mach_port_type_request_t *req = args->smsg;
302 mach_port_type_reply_t *rep = args->rmsg;
303 size_t *msglen = args->rsize;
304 struct lwp *l = args->l;
305 mach_port_t mn;
306 struct mach_right *mr;
307
308 mn = req->req_name;
309 if ((mr = mach_right_check(mn, l, MACH_PORT_TYPE_ALL_RIGHTS)) == NULL)
310 return mach_msg_error(args, EPERM);
311
312 *msglen = sizeof(*rep);
313 mach_set_header(rep, req, *msglen);
314
315 rep->rep_retval = 0;
316 rep->rep_ptype = mr->mr_type;
317
318 mach_set_trailer(rep, *msglen);
319
320 return 0;
321 }
322
323 int
324 mach_port_set_attributes(args)
325 struct mach_trap_args *args;
326 {
327 mach_port_set_attributes_request_t *req = args->smsg;
328 mach_port_set_attributes_reply_t *rep = args->rmsg;
329 size_t *msglen = args->rsize;
330 int end_offset;
331
332 /* Sanity check req->req_count */
333 end_offset = req->req_count;
334 if (MACH_REQMSG_OVERFLOW(args, req->req_port_info[end_offset]))
335 return mach_msg_error(args, EINVAL);
336
337 switch(req->req_flavor) {
338 case MACH_PORT_LIMITS_INFO:
339 case MACH_PORT_RECEIVE_STATUS:
340 case MACH_PORT_DNREQUESTS_SIZE:
341 break;
342 default:
343 uprintf("mach_port_set_attributes: unknown flavor %d\n",
344 req->req_flavor);
345 break;
346 }
347
348 *msglen = sizeof(*rep);
349 mach_set_header(rep, req, *msglen);
350
351 rep->rep_retval = 0;
352
353 mach_set_trailer(rep, *msglen);
354
355 return 0;
356 }
357
358 int
359 mach_port_get_attributes(args)
360 struct mach_trap_args *args;
361 {
362 mach_port_get_attributes_request_t *req = args->smsg;
363 mach_port_get_attributes_reply_t *rep = args->rmsg;
364 size_t *msglen = args->rsize;
365 struct lwp *l = args->l;
366 mach_port_t mn;
367 struct mach_right *mr;
368
369 /* Sanity check req_count */
370 if (req->req_count > 10)
371 return mach_msg_error(args, EINVAL);
372
373 mn = req->req_msgh.msgh_remote_port;
374 if ((mr = mach_right_check(mn, l, MACH_PORT_TYPE_ALL_RIGHTS)) == NULL)
375 return mach_msg_error(args, EPERM);
376
377 switch (req->req_flavor) {
378 case MACH_PORT_LIMITS_INFO: {
379 struct mach_port_limits *mpl;
380
381 if (req->req_count < (sizeof(*mpl) / sizeof(rep->rep_info[0])))
382 return mach_msg_error(args, EINVAL);
383
384 mpl = (struct mach_port_limits *)&rep->rep_info[0];
385 mpl->mpl_qlimit = MACH_PORT_QLIMIT_DEFAULT; /* XXX fake limit */
386
387 rep->rep_count = sizeof(*mpl);
388
389 break;
390 }
391
392 case MACH_PORT_RECEIVE_STATUS: {
393 struct mach_port_status *mps;
394 struct mach_port *mp;
395
396 if (req->req_count < (sizeof(*mps) / sizeof(rep->rep_info[0])))
397 return mach_msg_error(args, EINVAL);
398
399 mps = (struct mach_port_status *)&rep->rep_info[0];
400 memset(mps, 0, sizeof(*mps));
401
402 if (mr->mr_sethead != NULL)
403 mps->mps_pset = mr->mr_sethead->mr_name;
404 mps->mps_seqno = 0; /* XXX */
405 mps->mps_qlimit = MACH_PORT_QLIMIT_DEFAULT; /* XXX fake limit */
406 if ((mp = mr->mr_port) != NULL) {
407 mps->mps_mscount = mp->mp_refcount; /* XXX */
408 mps->mps_msgcount = mp->mp_count;
409 } else {
410 mps->mps_mscount = 0;
411 mps->mps_msgcount = 0;
412 }
413 mps->mps_sorights = 0; /* XXX */
414 mps->mps_srights = 0; /* XXX */
415 if (mr->mr_notify_destroyed != NULL)
416 mps->mps_pdrequest = 1;
417 if (mr->mr_notify_no_senders != NULL)
418 mps->mps_nsrequest = 1;
419 mps->mps_flags = 0; /* XXX */
420
421 rep->rep_count = sizeof(*mps);
422 break;
423 }
424
425 default:
426 printf("mach_port_get_attributes: unknown flavor %d\n",
427 req->req_flavor);
428 return mach_msg_error(args, EINVAL);
429
430 break;
431 };
432
433 *msglen = sizeof(*rep) - 10 + rep->rep_count;
434 mach_set_header(rep, req, *msglen);
435
436 rep->rep_retval = 0;
437
438 mach_set_trailer(rep, *msglen);
439
440 return 0;
441 }
442
443 /* XXX insert a recv right into a port set without removing it from another */
444 int
445 mach_port_insert_member(args)
446 struct mach_trap_args *args;
447 {
448 mach_port_insert_member_request_t *req = args->smsg;
449 mach_port_insert_member_reply_t *rep = args->rmsg;
450 size_t *msglen = args->rsize;
451
452 uprintf("Unimplemented mach_port_insert_member\n");
453
454 *msglen = sizeof(*rep);
455 mach_set_header(rep, req, *msglen);
456
457 rep->rep_retval = 0;
458
459 mach_set_trailer(rep, *msglen);
460
461 return 0;
462 }
463
464 int
465 mach_port_move_member(args)
466 struct mach_trap_args *args;
467 {
468 mach_port_move_member_request_t *req = args->smsg;
469 mach_port_move_member_reply_t *rep = args->rmsg;
470 size_t *msglen = args->rsize;
471 struct lwp *l = args->l;
472 struct mach_emuldata *med = l->l_proc->p_emuldata;
473 mach_port_t member = req->req_member;
474 mach_port_t after = req->req_after;
475 struct mach_right *mrr;
476 struct mach_right *mrs;
477
478 mrr = mach_right_check(member, l, MACH_PORT_TYPE_RECEIVE);
479 if (mrr == NULL)
480 return mach_msg_error(args, EPERM);
481
482 mrs = mach_right_check(after, l, MACH_PORT_TYPE_PORT_SET);
483 if (mrs == NULL)
484 return mach_msg_error(args, EPERM);
485
486 lockmgr(&med->med_rightlock, LK_EXCLUSIVE, NULL);
487
488 /* Remove it from an existing port set */
489 if (mrr->mr_sethead != mrr)
490 LIST_REMOVE(mrr, mr_setlist);
491
492 /* Insert it into the new port set */
493 LIST_INSERT_HEAD(&mrs->mr_set, mrr, mr_setlist);
494 mrr->mr_sethead = mrs;
495
496 lockmgr(&med->med_rightlock, LK_RELEASE, NULL);
497
498 *msglen = sizeof(*rep);
499 mach_set_header(rep, req, *msglen);
500
501 rep->rep_retval = 0;
502
503 mach_set_trailer(rep, *msglen);
504
505 return 0;
506 }
507
508 int
509 mach_port_request_notification(args)
510 struct mach_trap_args *args;
511 {
512 mach_port_request_notification_request_t *req = args->smsg;
513 mach_port_request_notification_reply_t *rep = args->rmsg;
514 struct lwp *l = args->l;
515 size_t *msglen = args->rsize;
516 mach_port_t mn;
517 struct mach_right *nmr;
518 struct mach_right *tmr;
519 struct mach_right *oldnmr;
520 mach_port_t oldmn;
521
522 #ifdef DEBUG_MACH
523 printf("mach_port_request_notification, notify = %08x, target = %08x\n",
524 req->req_notify.name, mn = req->req_name);
525 #endif
526 mn = req->req_notify.name;
527 if ((nmr = mach_right_check(mn, l, MACH_PORT_TYPE_ALL_RIGHTS)) == NULL)
528 return mach_msg_error(args, EINVAL);
529
530 mn = req->req_name;
531 if ((tmr = mach_right_check(mn, l, MACH_PORT_TYPE_ALL_RIGHTS)) == NULL)
532 return mach_msg_error(args, EINVAL);
533
534 #ifdef DEBUG_MACH
535 if (nmr->mr_port == NULL) {
536 printf("Notification right without a port\n");
537 printf("mr->mr_port = %p, mr = %08x\n", nmr->mr_port, nmr->mr_name);
538 return mach_msg_error(args, EINVAL);
539 }
540 #endif
541
542
543 oldnmr = NULL;
544 switch(req->req_msgid) {
545 case MACH_NOTIFY_DESTROYED_MSGID:
546 oldnmr = tmr->mr_notify_destroyed;
547 tmr->mr_notify_destroyed = mach_right_get(nmr->mr_port,
548 l, MACH_PORT_TYPE_SEND_ONCE, req->req_notify.name);
549 break;
550
551 case MACH_NOTIFY_NO_SENDERS_MSGID:
552 oldnmr = tmr->mr_notify_no_senders;
553 tmr->mr_notify_no_senders = mach_right_get(nmr->mr_port,
554 l, MACH_PORT_TYPE_SEND_ONCE, req->req_notify.name);
555 tmr->mr_notify_no_senders->mr_port->mp_datatype =
556 MACH_MP_NOTIFY_SYNC;
557 (int)tmr->mr_notify_no_senders->mr_port->mp_data =
558 req->req_count;
559 break;
560
561 case MACH_NOTIFY_DEAD_NAME_MSGID:
562 oldnmr = tmr->mr_notify_dead_name;
563 tmr->mr_notify_dead_name = mach_right_get(nmr->mr_port,
564 l, MACH_PORT_TYPE_SEND_ONCE, req->req_notify.name);
565 break;
566
567 case MACH_NOTIFY_SEND_ONCE_MSGID:
568 case MACH_NOTIFY_DELETED_MSGID:
569 default:
570 #ifdef DEBUG_MACH
571 printf("unsupported notify request %d\n", req->req_msgid);
572 return mach_msg_error(args, EINVAL);
573 #endif
574 break;
575 }
576
577 if (oldnmr != NULL) {
578 oldnmr->mr_refcount++;
579 oldmn = oldnmr->mr_name;
580 } else {
581 oldmn = (mach_port_t)MACH_PORT_NULL;
582 }
583
584 *msglen = sizeof(*rep);
585 mach_set_header(rep, req, *msglen);
586 mach_add_port_desc(rep, oldmn);
587 mach_set_trailer(rep, *msglen);
588
589 return 0;
590 }
591
592 int
593 mach_port_get_refs(args)
594 struct mach_trap_args *args;
595 {
596 mach_port_get_refs_request_t *req = args->smsg;
597 mach_port_get_refs_reply_t *rep = args->rmsg;
598 size_t *msglen = args->rsize;
599 struct lwp *l = args->l;
600 mach_port_t mn;
601 struct mach_right *mr;
602 mach_port_right_t right = req->req_right;
603
604 mn = req->req_name;
605 if ((mr = mach_right_check(mn, l, right)) == NULL)
606 return mach_msg_error(args, EINVAL);
607
608 *msglen = sizeof(*rep);
609 mach_set_header(rep, req, *msglen);
610
611 rep->rep_retval = 0;
612 rep->rep_refs = mr->mr_refcount;
613
614 mach_set_trailer(rep, *msglen);
615
616 return 0;
617 }
618
619 int
620 mach_port_mod_refs(args)
621 struct mach_trap_args *args;
622 {
623 mach_port_mod_refs_request_t *req = args->smsg;
624 mach_port_mod_refs_reply_t *rep = args->rmsg;
625 size_t *msglen = args->rsize;
626 #if 0
627 struct lwp *l = args->l;
628 mach_port_t mn;
629 struct mach_right *mr;
630 mach_port_right_t right = req->req_right;
631
632 mn = req->req_name;
633 if ((mr = mach_right_check(mn, l, right)) == NULL)
634 return mach_msg_error(args, EINVAL);
635
636 /*
637 * Changing the refcount is likely to cause crashes,
638 * as we will free a right which might still be referenced
639 * within the kernel. Add a user refcount field?
640 */
641 mr->mr_refcount += req->req_delta;
642 if (mr->mr_refcount <= 0)
643 mach_right_put(mr, right);
644 #endif
645
646 *msglen = sizeof(*rep);
647 mach_set_header(rep, req, *msglen);
648
649 rep->rep_retval = 0;
650
651 mach_set_trailer(rep, *msglen);
652
653 return 0;
654 }
655
656 void
657 mach_port_init(void)
658 {
659 pool_init(&mach_port_pool, sizeof (struct mach_port),
660 0, 0, 0, "mach_port_pool", NULL);
661 pool_init(&mach_right_pool, sizeof (struct mach_right),
662 0, 0, 0, "mach_right_pool", NULL);
663
664 mach_bootstrap_port = mach_port_get();
665 mach_clock_port = mach_port_get();
666 mach_io_master_port = mach_port_get();
667
668 mach_bootstrap_port->mp_flags |= MACH_MP_INKERNEL;
669 mach_clock_port->mp_flags |= MACH_MP_INKERNEL;
670 mach_io_master_port->mp_flags |= MACH_MP_INKERNEL;
671
672 mach_saved_bootstrap_port = mach_bootstrap_port;
673
674 return;
675 }
676
677 struct mach_port *
678 mach_port_get(void)
679 {
680 struct mach_port *mp;
681
682 mp = (struct mach_port *)pool_get(&mach_port_pool, PR_WAITOK);
683 bzero(mp, sizeof(*mp));
684 mp->mp_recv = NULL;
685 mp->mp_count = 0;
686 mp->mp_flags = 0;
687 mp->mp_datatype = MACH_MP_NONE;
688 mp->mp_data = NULL;
689 TAILQ_INIT(&mp->mp_msglist);
690 lockinit(&mp->mp_msglock, PZERO|PCATCH, "mach_port", 0, 0);
691
692 return mp;
693 }
694
695 void
696 mach_port_put(mp)
697 struct mach_port *mp;
698 {
699 struct mach_message *mm;
700
701 #ifdef DIAGNOSTIC
702 if (mp->mp_refcount > 0) {
703 uprintf("mach_port_put: trying to free a referenced port\n");
704 return;
705 }
706 #endif
707
708 lockmgr(&mp->mp_msglock, LK_EXCLUSIVE, NULL);
709 while ((mm = TAILQ_FIRST(&mp->mp_msglist)) != NULL)
710 mach_message_put_exclocked(mm);
711 lockmgr(&mp->mp_msglock, LK_RELEASE, NULL);
712 lockmgr(&mp->mp_msglock, LK_DRAIN, NULL);
713
714 if (mp->mp_flags & MACH_MP_DATA_ALLOCATED)
715 free(mp->mp_data, M_EMULDATA);
716
717 pool_put(&mach_port_pool, mp);
718
719 return;
720 }
721
722 struct mach_right *
723 mach_right_get(mp, l, type, hint)
724 struct mach_port *mp;
725 struct lwp *l;
726 int type;
727 mach_port_t hint;
728 {
729 struct mach_right *mr;
730 struct mach_emuldata *med;
731 int rights;
732
733 #ifdef DEBUG_MACH
734 if (type == 0)
735 uprintf("mach_right_get: right = 0\n");
736 #endif
737 med = (struct mach_emuldata *)l->l_proc->p_emuldata;
738
739 if (mp != NULL)
740 MACH_PORT_REF(mp);
741
742 /* Send and receive right must return an existing right */
743 rights = (MACH_PORT_TYPE_SEND | MACH_PORT_TYPE_RECEIVE);
744 if (type & rights) {
745 lockmgr(&med->med_rightlock, LK_SHARED, NULL);
746 LIST_FOREACH(mr, &med->med_right, mr_list) {
747 if ((mr->mr_port == mp) && (mr->mr_type & rights))
748 break;
749 }
750 lockmgr(&med->med_rightlock, LK_RELEASE, NULL);
751
752 if (mr != NULL) {
753 mr->mr_type |= type;
754 if (type & MACH_PORT_TYPE_SEND)
755 mr->mr_refcount++;
756 goto rcvck;
757 }
758 }
759
760 mr = pool_get(&mach_right_pool, PR_WAITOK);
761
762 mr->mr_port = mp;
763 mr->mr_lwp = l;
764 mr->mr_type = type;
765 mr->mr_sethead = mr;
766 mr->mr_refcount = 1;
767 mr->mr_notify_destroyed = NULL;
768 mr->mr_notify_dead_name = NULL;
769 mr->mr_notify_no_senders = NULL;
770
771 LIST_INIT(&mr->mr_set);
772
773 /* Insert the right in the right lists */
774 if (type & MACH_PORT_TYPE_ALL_RIGHTS) {
775 lockmgr(&med->med_rightlock, LK_EXCLUSIVE, NULL);
776 mr->mr_name = mach_right_newname(l, hint);
777 #ifdef DEBUG_MACH_RIGHT
778 printf("mach_right_get: insert right %x(%x)\n",
779 mr->mr_name, mr->mr_type);
780 #endif
781 LIST_INSERT_HEAD(&med->med_right, mr, mr_list);
782 lockmgr(&med->med_rightlock, LK_RELEASE, NULL);
783 }
784
785 rcvck:
786 if (type & MACH_PORT_TYPE_RECEIVE) {
787 /*
788 * Destroy the former receive right on this port, and
789 * register the new right.
790 */
791 if (mr->mr_port->mp_recv != NULL)
792 mach_right_put(mr->mr_port->mp_recv,
793 MACH_PORT_TYPE_RECEIVE);
794 mr->mr_port->mp_recv = mr;
795 }
796 return mr;
797 }
798
799 void
800 mach_right_put(mr, right)
801 struct mach_right *mr;
802 int right;
803 {
804 struct mach_emuldata *med = mr->mr_lwp->l_proc->p_emuldata;
805
806 lockmgr(&med->med_rightlock, LK_EXCLUSIVE, NULL);
807 mach_right_put_exclocked(mr, right);
808 lockmgr(&med->med_rightlock, LK_RELEASE, NULL);
809
810 return;
811 }
812
813 void
814 mach_right_put_shlocked(mr, right)
815 struct mach_right *mr;
816 int right;
817 {
818 struct mach_emuldata *med = mr->mr_lwp->l_proc->p_emuldata;
819
820 lockmgr(&med->med_rightlock, LK_UPGRADE, NULL);
821 mach_right_put_exclocked(mr, right);
822 lockmgr(&med->med_rightlock, LK_DOWNGRADE, NULL);
823
824 return;
825 }
826
827 void
828 mach_right_put_exclocked(mr, right)
829 struct mach_right *mr;
830 int right;
831 {
832 struct mach_right *cmr;
833 struct mach_emuldata *med;
834 int lright;
835 int kill_right;
836
837 med = mr->mr_lwp->l_proc->p_emuldata;
838
839 #ifdef DEBUG_MACH_RIGHT
840 printf("mach_right_put: mr = %p\n", mr);
841 printf("right %x(%x) refcount %d, deallocate %x\n",
842 mr->mr_name, mr->mr_type, mr->mr_refcount, right);
843 if ((mr->mr_type & right) == 0)
844 printf("mach_right_put: dropping nonexistant right %x on %x\n",
845 right, mr->mr_name);
846 LIST_FOREACH(cmr, &med->med_right, mr_list)
847 if (cmr == mr)
848 break;
849 if (cmr == NULL) {
850 printf("mach_right_put: dropping already dropped right %x\n",
851 mr->mr_name);
852 return;
853 }
854 #endif
855 kill_right = 0;
856
857 /* When receive right is deallocated, the port should die */
858 lright = (right & MACH_PORT_TYPE_RECEIVE);
859 #ifdef DEBUG_MACH_RIGHT
860 printf("mr->mr_type = %x, lright = %x, right = %x, refcount = %d\n",
861 mr->mr_type, lright, right, mr->mr_refcount);
862 #endif
863 if (mr->mr_type & lright) {
864 if (mr->mr_refcount <= 0) {
865 mr->mr_type &= ~MACH_PORT_TYPE_RECEIVE;
866 kill_right = 1;
867 } else {
868 mr->mr_type &= ~MACH_PORT_TYPE_RECEIVE;
869 mr->mr_type |= MACH_PORT_TYPE_DEAD_NAME;
870 mach_notify_port_dead_name(mr->mr_lwp, mr);
871 }
872 if (mr->mr_port != NULL) {
873 /* There is no more receiver */
874 #ifdef DIAGNOSTIC
875 if (mr->mr_port->mp_recv != mr)
876 printf("several receiver on a single port\n");
877 #endif
878 mr->mr_port->mp_recv = NULL;
879
880 MACH_PORT_UNREF(mr->mr_port);
881 mr->mr_port = NULL;
882 }
883 }
884
885 /* send, send_once and dead_name */
886 lright = (right & MACH_PORT_TYPE_REF_RIGHTS);
887 if (mr->mr_type & lright) {
888 mr->mr_refcount--;
889
890 mach_notify_port_no_senders(mr->mr_lwp, mr);
891
892 if (mr->mr_refcount <= 0) {
893 mr->mr_type &= ~MACH_PORT_TYPE_REF_RIGHTS;
894 if ((mr->mr_type & MACH_PORT_TYPE_RECEIVE) == 0)
895 kill_right = 1;
896 }
897 }
898
899 lright = (right & MACH_PORT_TYPE_PORT_SET);
900 if ((mr->mr_type & lright) || (kill_right == 1)) {
901 while ((cmr = LIST_FIRST(&mr->mr_set)) != NULL) {
902 LIST_REMOVE(cmr, mr_setlist);
903 cmr->mr_sethead = cmr;
904 }
905 mr->mr_type &= ~MACH_PORT_TYPE_PORT_SET;
906 if ((mr->mr_type & MACH_PORT_TYPE_RECEIVE) == 0)
907 kill_right = 1;
908 }
909
910 /* Should we kill it? */
911 if (kill_right == 1) {
912 #ifdef DEBUG_MACH_RIGHT
913 printf("mach_right_put: kill name %x\n", mr->mr_name);
914 #endif
915 /* If the right is used for an IO notification, remove it */
916 mach_iokit_cleanup_notify(mr);
917
918 mach_notify_port_destroyed(mr->mr_lwp, mr);
919 LIST_REMOVE(mr, mr_list);
920 pool_put(&mach_right_pool, mr);
921 }
922 return;
923 }
924
925 /*
926 * Check that a process has a given right.
927 */
928 struct mach_right *
929 mach_right_check(mn, l, type)
930 mach_port_t mn;
931 struct lwp *l;
932 int type;
933 {
934 struct mach_right *cmr;
935 struct mach_emuldata *med;
936
937 if ((mn == 0) || (mn == -1) || (l == NULL))
938 return NULL;
939
940 med = (struct mach_emuldata *)l->l_proc->p_emuldata;
941
942 lockmgr(&med->med_rightlock, LK_SHARED, NULL);
943
944 #ifdef DEBUG_MACH_RIGHT
945 printf("mach_right_check: type = %x, mn = %x\n", type, mn);
946 #endif
947 LIST_FOREACH(cmr, &med->med_right, mr_list) {
948 #ifdef DEBUG_MACH_RIGHT
949 printf("cmr = %p, cmr->mr_name = %x, cmr->mr_type = %x\n",
950 cmr, cmr->mr_name, cmr->mr_type);
951 #endif
952 if (cmr->mr_name != mn)
953 continue;
954 if (type & cmr->mr_type)
955 break;
956 }
957
958 lockmgr(&med->med_rightlock, LK_RELEASE, NULL);
959
960 return cmr;
961 }
962
963
964 /*
965 * Find an usnused port name in a given lwp.
966 * Right lists should be locked.
967 */
968 mach_port_t
969 mach_right_newname(l, hint)
970 struct lwp *l;
971 mach_port_t hint;
972 {
973 struct mach_emuldata *med;
974 struct mach_right *mr;
975 mach_port_t newname = -1;
976
977 med = l->l_proc->p_emuldata;
978
979 if (hint == 0)
980 hint = med->med_nextright;
981
982 while (newname == -1) {
983 LIST_FOREACH(mr, &med->med_right, mr_list)
984 if (mr->mr_name == hint)
985 break;
986 if (mr == NULL)
987 newname = hint;
988 hint++;
989 }
990
991 med->med_nextright = hint;
992
993 return newname;
994 }
995
996 #ifdef DEBUG_MACH
997 void
998 mach_debug_port(void)
999 {
1000 struct mach_emuldata *med;
1001 struct mach_right *mr;
1002 struct mach_right *mrs;
1003 struct proc *p;
1004
1005 PROCLIST_FOREACH(p, &allproc) {
1006 if ((p->p_emul != &emul_mach) &&
1007 #ifdef COMPAT_DARWIN
1008 (p->p_emul != &emul_darwin) &&
1009 #endif
1010 1)
1011 continue;
1012
1013 med = p->p_emuldata;
1014 LIST_FOREACH(mr, &med->med_right, mr_list) {
1015 if ((mr->mr_type & MACH_PORT_TYPE_PORT_SET) == 0) {
1016 printf("pid %d: %p(%x)=>%p",
1017 p->p_pid, mr, mr->mr_type, mr->mr_port);
1018 if (mr->mr_port && mr->mr_port->mp_recv)
1019 printf("[%p]\n",
1020 mr->mr_port->mp_recv->mr_sethead);
1021 else
1022 printf("[NULL]\n");
1023
1024 continue;
1025 }
1026
1027 /* Port set... */
1028 printf("pid %d: set %p(%x) ",
1029 p->p_pid, mr, mr->mr_type);
1030 LIST_FOREACH(mrs, &mr->mr_set, mr_setlist) {
1031 printf("%p(%x)=>%p",
1032 mrs, mrs->mr_type, mrs->mr_port);
1033 if (mrs->mr_port && mrs->mr_port->mp_recv)
1034 printf("[%p]",
1035 mrs->mr_port->mp_recv->mr_sethead);
1036 else
1037 printf("[NULL]");
1038
1039 printf(" ");
1040 }
1041 printf("\n");
1042 }
1043 }
1044 return;
1045 }
1046
1047 #endif /* DEBUG_MACH */
Cache object: 5e5d571db4161a7239b45f0d51ecc45b
|