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