]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. | |
7 | * | |
8 | * This file contains Original Code and/or Modifications of Original Code | |
9 | * as defined in and that are subject to the Apple Public Source License | |
10 | * Version 2.0 (the 'License'). You may not use this file except in | |
11 | * compliance with the License. Please obtain a copy of the License at | |
12 | * http://www.opensource.apple.com/apsl/ and read it before using this | |
13 | * file. | |
14 | * | |
15 | * The Original Code and all software distributed under the License are | |
16 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
17 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
18 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
19 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
20 | * Please see the License for the specific language governing rights and | |
21 | * limitations under the License. | |
22 | * | |
23 | * @APPLE_LICENSE_HEADER_END@ | |
24 | */ | |
25 | /* | |
26 | * @OSF_COPYRIGHT@ | |
27 | */ | |
28 | /* | |
29 | * Mach Operating System | |
30 | * Copyright (c) 1991,1990,1989,1988 Carnegie Mellon University | |
31 | * All Rights Reserved. | |
32 | * | |
33 | * Permission to use, copy, modify and distribute this software and its | |
34 | * documentation is hereby granted, provided that both the copyright | |
35 | * notice and this permission notice appear in all copies of the | |
36 | * software, derivative works or modified versions, and any portions | |
37 | * thereof, and that both notices appear in supporting documentation. | |
38 | * | |
39 | * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" | |
40 | * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR | |
41 | * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. | |
42 | * | |
43 | * Carnegie Mellon requests users of this software to return to | |
44 | * | |
45 | * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU | |
46 | * School of Computer Science | |
47 | * Carnegie Mellon University | |
48 | * Pittsburgh PA 15213-3890 | |
49 | * | |
50 | * any improvements or extensions that they make and grant Carnegie Mellon | |
51 | * the rights to redistribute these changes. | |
52 | */ | |
53 | /* | |
54 | */ | |
55 | ||
56 | /* | |
57 | * kern/ipc_host.c | |
58 | * | |
59 | * Routines to implement host ports. | |
60 | */ | |
61 | #include <mach/message.h> | |
62 | #include <mach/mach_traps.h> | |
63 | #include <mach/etap_events.h> | |
64 | #include <mach/mach_host_server.h> | |
65 | #include <kern/host.h> | |
66 | #include <kern/processor.h> | |
67 | #include <kern/lock.h> | |
68 | #include <kern/task.h> | |
69 | #include <kern/thread.h> | |
70 | #include <kern/ipc_host.h> | |
71 | #include <kern/ipc_kobject.h> | |
72 | #include <kern/misc_protos.h> | |
73 | #include <kern/spl.h> | |
74 | #include <ipc/ipc_port.h> | |
75 | #include <ipc/ipc_space.h> | |
76 | ||
77 | /* | |
78 | * Forward declarations | |
79 | */ | |
80 | ||
81 | void | |
82 | ipc_processor_terminate( | |
83 | processor_t processor); | |
84 | ||
85 | void | |
86 | ipc_processor_disable( | |
87 | processor_t processor); | |
88 | ||
89 | boolean_t | |
90 | ref_pset_port_locked( | |
91 | ipc_port_t port, boolean_t matchn, processor_set_t *ppset); | |
92 | ||
93 | /* | |
94 | * ipc_host_init: set up various things. | |
95 | */ | |
96 | ||
97 | void ipc_host_init(void) | |
98 | { | |
99 | ipc_port_t port; | |
100 | int i; | |
101 | ||
102 | mutex_init(&realhost.lock, ETAP_MISC_MASTER); | |
103 | ||
104 | /* | |
105 | * Allocate and set up the two host ports. | |
106 | */ | |
107 | port = ipc_port_alloc_kernel(); | |
108 | if (port == IP_NULL) | |
109 | panic("ipc_host_init"); | |
110 | ||
111 | ipc_kobject_set(port, (ipc_kobject_t) &realhost, IKOT_HOST); | |
112 | realhost.host_self = port; | |
113 | ||
114 | port = ipc_port_alloc_kernel(); | |
115 | if (port == IP_NULL) | |
116 | panic("ipc_host_init"); | |
117 | ||
118 | ipc_kobject_set(port, (ipc_kobject_t) &realhost, IKOT_HOST_PRIV); | |
119 | realhost.host_priv_self = port; | |
120 | ||
121 | port = ipc_port_alloc_kernel(); | |
122 | if (port == IP_NULL) | |
123 | panic("ipc_host_init"); | |
124 | ||
125 | ipc_kobject_set(port, (ipc_kobject_t) &realhost, IKOT_HOST_SECURITY); | |
126 | realhost.host_security_self = port; | |
127 | ||
128 | realhost.io_master = IP_NULL; | |
129 | ||
130 | for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) { | |
131 | realhost.exc_actions[i].port = IP_NULL; | |
132 | }/* for */ | |
133 | ||
134 | /* | |
135 | * Set up ipc for default processor set. | |
136 | */ | |
137 | ipc_pset_init(&default_pset); | |
138 | ipc_pset_enable(&default_pset); | |
139 | ||
140 | /* | |
141 | * And for master processor | |
142 | */ | |
143 | ipc_processor_init(master_processor); | |
144 | ipc_processor_enable(master_processor); | |
145 | } | |
146 | ||
147 | /* | |
148 | * Routine: host_self_trap [mach trap] | |
149 | * Purpose: | |
150 | * Give the caller send rights for his own host port. | |
151 | * Conditions: | |
152 | * Nothing locked. | |
153 | * Returns: | |
154 | * MACH_PORT_NULL if there are any resource failures | |
155 | * or other errors. | |
156 | */ | |
157 | ||
158 | mach_port_name_t | |
159 | host_self_trap(void) | |
160 | { | |
161 | ipc_port_t sright; | |
162 | ||
163 | sright = ipc_port_copy_send(current_task()->itk_host); | |
164 | return ipc_port_copyout_send(sright, current_space()); | |
165 | } | |
166 | ||
167 | /* | |
168 | * ipc_processor_init: | |
169 | * | |
170 | * Initialize ipc access to processor by allocating port. | |
171 | */ | |
172 | ||
173 | void | |
174 | ipc_processor_init( | |
175 | processor_t processor) | |
176 | { | |
177 | ipc_port_t port; | |
178 | ||
179 | port = ipc_port_alloc_kernel(); | |
180 | if (port == IP_NULL) | |
181 | panic("ipc_processor_init"); | |
182 | processor->processor_self = port; | |
183 | } | |
184 | ||
185 | /* | |
186 | * ipc_processor_enable: | |
187 | * | |
188 | * Enable ipc control of processor by setting port object. | |
189 | */ | |
190 | void | |
191 | ipc_processor_enable( | |
192 | processor_t processor) | |
193 | { | |
194 | ipc_port_t myport; | |
195 | ||
196 | myport = processor->processor_self; | |
197 | ipc_kobject_set(myport, (ipc_kobject_t) processor, IKOT_PROCESSOR); | |
198 | } | |
199 | ||
200 | /* | |
201 | * ipc_processor_disable: | |
202 | * | |
203 | * Disable ipc control of processor by clearing port object. | |
204 | */ | |
205 | void | |
206 | ipc_processor_disable( | |
207 | processor_t processor) | |
208 | { | |
209 | ipc_port_t myport; | |
210 | ||
211 | myport = processor->processor_self; | |
212 | if (myport == IP_NULL) | |
213 | return; | |
214 | ipc_kobject_set(myport, IKO_NULL, IKOT_NONE); | |
215 | } | |
216 | ||
217 | /* | |
218 | * ipc_processor_terminate: | |
219 | * | |
220 | * Processor is off-line. Destroy ipc control port. | |
221 | */ | |
222 | void | |
223 | ipc_processor_terminate( | |
224 | processor_t processor) | |
225 | { | |
226 | ipc_port_t myport; | |
227 | spl_t s; | |
228 | ||
229 | s = splsched(); | |
230 | processor_lock(processor); | |
231 | myport = processor->processor_self; | |
232 | if (myport == IP_NULL) { | |
233 | processor_unlock(processor); | |
234 | splx(s); | |
235 | return; | |
236 | } | |
237 | ||
238 | processor->processor_self = IP_NULL; | |
239 | processor_unlock(processor); | |
240 | splx(s); | |
241 | ||
242 | ipc_port_dealloc_kernel(myport); | |
243 | } | |
244 | ||
245 | /* | |
246 | * ipc_pset_init: | |
247 | * | |
248 | * Initialize ipc control of a processor set by allocating its ports. | |
249 | */ | |
250 | ||
251 | void | |
252 | ipc_pset_init( | |
253 | processor_set_t pset) | |
254 | { | |
255 | ipc_port_t port; | |
256 | ||
257 | port = ipc_port_alloc_kernel(); | |
258 | if (port == IP_NULL) | |
259 | panic("ipc_pset_init"); | |
260 | pset->pset_self = port; | |
261 | ||
262 | port = ipc_port_alloc_kernel(); | |
263 | if (port == IP_NULL) | |
264 | panic("ipc_pset_init"); | |
265 | pset->pset_name_self = port; | |
266 | } | |
267 | ||
268 | /* | |
269 | * ipc_pset_enable: | |
270 | * | |
271 | * Enable ipc access to a processor set. | |
272 | */ | |
273 | void | |
274 | ipc_pset_enable( | |
275 | processor_set_t pset) | |
276 | { | |
277 | pset_lock(pset); | |
278 | if (pset->active) { | |
279 | ipc_kobject_set(pset->pset_self, | |
280 | (ipc_kobject_t) pset, IKOT_PSET); | |
281 | ipc_kobject_set(pset->pset_name_self, | |
282 | (ipc_kobject_t) pset, IKOT_PSET_NAME); | |
283 | pset->ref_count += 2; | |
284 | } | |
285 | pset_unlock(pset); | |
286 | } | |
287 | ||
288 | /* | |
289 | * ipc_pset_disable: | |
290 | * | |
291 | * Disable ipc access to a processor set by clearing the port objects. | |
292 | * Caller must hold pset lock and a reference to the pset. Ok to | |
293 | * just decrement pset reference count as a result. | |
294 | */ | |
295 | void | |
296 | ipc_pset_disable( | |
297 | processor_set_t pset) | |
298 | { | |
299 | ipc_kobject_set(pset->pset_self, IKO_NULL, IKOT_NONE); | |
300 | ipc_kobject_set(pset->pset_name_self, IKO_NULL, IKOT_NONE); | |
301 | pset->ref_count -= 2; | |
302 | } | |
303 | ||
304 | /* | |
305 | * ipc_pset_terminate: | |
306 | * | |
307 | * Processor set is dead. Deallocate the ipc control structures. | |
308 | */ | |
309 | void | |
310 | ipc_pset_terminate( | |
311 | processor_set_t pset) | |
312 | { | |
313 | ipc_port_dealloc_kernel(pset->pset_self); | |
314 | ipc_port_dealloc_kernel(pset->pset_name_self); | |
315 | } | |
316 | ||
317 | /* | |
318 | * processor_set_default, processor_set_default_priv: | |
319 | * | |
320 | * Return ports for manipulating default_processor set. MiG code | |
321 | * differentiates between these two routines. | |
322 | */ | |
323 | kern_return_t | |
324 | processor_set_default( | |
325 | host_t host, | |
326 | processor_set_t *pset) | |
327 | { | |
328 | if (host == HOST_NULL) | |
329 | return(KERN_INVALID_ARGUMENT); | |
330 | ||
331 | *pset = &default_pset; | |
332 | pset_reference(*pset); | |
333 | return(KERN_SUCCESS); | |
334 | } | |
335 | ||
336 | /* | |
337 | * Routine: convert_port_to_host | |
338 | * Purpose: | |
339 | * Convert from a port to a host. | |
340 | * Doesn't consume the port ref; the host produced may be null. | |
341 | * Conditions: | |
342 | * Nothing locked. | |
343 | */ | |
344 | ||
345 | host_t | |
346 | convert_port_to_host( | |
347 | ipc_port_t port) | |
348 | { | |
349 | host_t host = HOST_NULL; | |
350 | ||
351 | if (IP_VALID(port)) { | |
352 | ip_lock(port); | |
353 | if (ip_active(port) && | |
354 | ((ip_kotype(port) == IKOT_HOST) || | |
355 | (ip_kotype(port) == IKOT_HOST_PRIV) | |
356 | )) | |
357 | host = (host_t) port->ip_kobject; | |
358 | ip_unlock(port); | |
359 | } | |
360 | ||
361 | return host; | |
362 | } | |
363 | ||
364 | /* | |
365 | * Routine: convert_port_to_host_priv | |
366 | * Purpose: | |
367 | * Convert from a port to a host. | |
368 | * Doesn't consume the port ref; the host produced may be null. | |
369 | * Conditions: | |
370 | * Nothing locked. | |
371 | */ | |
372 | ||
373 | host_t | |
374 | convert_port_to_host_priv( | |
375 | ipc_port_t port) | |
376 | { | |
377 | host_t host = HOST_NULL; | |
378 | ||
379 | if (IP_VALID(port)) { | |
380 | ip_lock(port); | |
381 | if (ip_active(port) && | |
382 | (ip_kotype(port) == IKOT_HOST_PRIV)) | |
383 | host = (host_t) port->ip_kobject; | |
384 | ip_unlock(port); | |
385 | } | |
386 | ||
387 | return host; | |
388 | } | |
389 | ||
390 | /* | |
391 | * Routine: convert_port_to_processor | |
392 | * Purpose: | |
393 | * Convert from a port to a processor. | |
394 | * Doesn't consume the port ref; | |
395 | * the processor produced may be null. | |
396 | * Conditions: | |
397 | * Nothing locked. | |
398 | */ | |
399 | ||
400 | processor_t | |
401 | convert_port_to_processor( | |
402 | ipc_port_t port) | |
403 | { | |
404 | processor_t processor = PROCESSOR_NULL; | |
405 | ||
406 | if (IP_VALID(port)) { | |
407 | ip_lock(port); | |
408 | if (ip_active(port) && | |
409 | (ip_kotype(port) == IKOT_PROCESSOR)) | |
410 | processor = (processor_t) port->ip_kobject; | |
411 | ip_unlock(port); | |
412 | } | |
413 | ||
414 | return processor; | |
415 | } | |
416 | ||
417 | /* | |
418 | * Routine: convert_port_to_pset | |
419 | * Purpose: | |
420 | * Convert from a port to a pset. | |
421 | * Doesn't consume the port ref; produces a pset ref, | |
422 | * which may be null. | |
423 | * Conditions: | |
424 | * Nothing locked. | |
425 | */ | |
426 | ||
427 | processor_set_t | |
428 | convert_port_to_pset( | |
429 | ipc_port_t port) | |
430 | { | |
431 | boolean_t r; | |
432 | processor_set_t pset = PROCESSOR_SET_NULL; | |
433 | ||
434 | r = FALSE; | |
435 | while (!r && IP_VALID(port)) { | |
436 | ip_lock(port); | |
437 | r = ref_pset_port_locked(port, FALSE, &pset); | |
438 | /* port unlocked */ | |
439 | } | |
440 | return pset; | |
441 | } | |
442 | ||
443 | /* | |
444 | * Routine: convert_port_to_pset_name | |
445 | * Purpose: | |
446 | * Convert from a port to a pset. | |
447 | * Doesn't consume the port ref; produces a pset ref, | |
448 | * which may be null. | |
449 | * Conditions: | |
450 | * Nothing locked. | |
451 | */ | |
452 | ||
453 | processor_set_name_t | |
454 | convert_port_to_pset_name( | |
455 | ipc_port_t port) | |
456 | { | |
457 | boolean_t r; | |
458 | processor_set_t pset = PROCESSOR_SET_NULL; | |
459 | ||
460 | r = FALSE; | |
461 | while (!r && IP_VALID(port)) { | |
462 | ip_lock(port); | |
463 | r = ref_pset_port_locked(port, TRUE, &pset); | |
464 | /* port unlocked */ | |
465 | } | |
466 | return pset; | |
467 | } | |
468 | ||
469 | boolean_t | |
470 | ref_pset_port_locked(ipc_port_t port, boolean_t matchn, processor_set_t *ppset) | |
471 | { | |
472 | processor_set_t pset; | |
473 | ||
474 | pset = PROCESSOR_SET_NULL; | |
475 | if (ip_active(port) && | |
476 | ((ip_kotype(port) == IKOT_PSET) || | |
477 | (matchn && (ip_kotype(port) == IKOT_PSET_NAME)))) { | |
478 | pset = (processor_set_t) port->ip_kobject; | |
479 | if (!pset_lock_try(pset)) { | |
480 | ip_unlock(port); | |
481 | mutex_pause(); | |
482 | return (FALSE); | |
483 | } | |
484 | pset->ref_count++; | |
485 | pset_unlock(pset); | |
486 | } | |
487 | *ppset = pset; | |
488 | ip_unlock(port); | |
489 | return (TRUE); | |
490 | } | |
491 | ||
492 | /* | |
493 | * Routine: convert_host_to_port | |
494 | * Purpose: | |
495 | * Convert from a host to a port. | |
496 | * Produces a naked send right which may be invalid. | |
497 | * Conditions: | |
498 | * Nothing locked. | |
499 | */ | |
500 | ||
501 | ipc_port_t | |
502 | convert_host_to_port( | |
503 | host_t host) | |
504 | { | |
505 | ipc_port_t port; | |
506 | ||
507 | port = ipc_port_make_send(host->host_self); | |
508 | ||
509 | return port; | |
510 | } | |
511 | ||
512 | /* | |
513 | * Routine: convert_processor_to_port | |
514 | * Purpose: | |
515 | * Convert from a processor to a port. | |
516 | * Produces a naked send right which may be invalid. | |
517 | * Conditions: | |
518 | * Nothing locked. | |
519 | */ | |
520 | ||
521 | ipc_port_t | |
522 | convert_processor_to_port( | |
523 | processor_t processor) | |
524 | { | |
525 | ipc_port_t port; | |
526 | spl_t s; | |
527 | ||
528 | s = splsched(); | |
529 | processor_lock(processor); | |
530 | ||
531 | if (processor->processor_self != IP_NULL) | |
532 | port = ipc_port_make_send(processor->processor_self); | |
533 | else | |
534 | port = IP_NULL; | |
535 | ||
536 | processor_unlock(processor); | |
537 | splx(s); | |
538 | ||
539 | return port; | |
540 | } | |
541 | ||
542 | /* | |
543 | * Routine: convert_pset_to_port | |
544 | * Purpose: | |
545 | * Convert from a pset to a port. | |
546 | * Consumes a pset ref; produces a naked send right | |
547 | * which may be invalid. | |
548 | * Conditions: | |
549 | * Nothing locked. | |
550 | */ | |
551 | ||
552 | ipc_port_t | |
553 | convert_pset_to_port( | |
554 | processor_set_t pset) | |
555 | { | |
556 | ipc_port_t port; | |
557 | ||
558 | pset_lock(pset); | |
559 | if (pset->active) | |
560 | port = ipc_port_make_send(pset->pset_self); | |
561 | else | |
562 | port = IP_NULL; | |
563 | pset_unlock(pset); | |
564 | ||
565 | pset_deallocate(pset); | |
566 | return port; | |
567 | } | |
568 | ||
569 | /* | |
570 | * Routine: convert_pset_name_to_port | |
571 | * Purpose: | |
572 | * Convert from a pset to a port. | |
573 | * Consumes a pset ref; produces a naked send right | |
574 | * which may be invalid. | |
575 | * Conditions: | |
576 | * Nothing locked. | |
577 | */ | |
578 | ||
579 | ipc_port_t | |
580 | convert_pset_name_to_port( | |
581 | processor_set_name_t pset) | |
582 | { | |
583 | ipc_port_t port; | |
584 | ||
585 | pset_lock(pset); | |
586 | if (pset->active) | |
587 | port = ipc_port_make_send(pset->pset_name_self); | |
588 | else | |
589 | port = IP_NULL; | |
590 | pset_unlock(pset); | |
591 | ||
592 | pset_deallocate(pset); | |
593 | return port; | |
594 | } | |
595 | ||
596 | /* | |
597 | * Routine: convert_port_to_host_security | |
598 | * Purpose: | |
599 | * Convert from a port to a host security. | |
600 | * Doesn't consume the port ref; the port produced may be null. | |
601 | * Conditions: | |
602 | * Nothing locked. | |
603 | */ | |
604 | ||
605 | host_t | |
606 | convert_port_to_host_security( | |
607 | ipc_port_t port) | |
608 | { | |
609 | host_t host = HOST_NULL; | |
610 | ||
611 | if (IP_VALID(port)) { | |
612 | ip_lock(port); | |
613 | if (ip_active(port) && | |
614 | (ip_kotype(port) == IKOT_HOST_SECURITY)) | |
615 | host = (host_t) port->ip_kobject; | |
616 | ip_unlock(port); | |
617 | } | |
618 | ||
619 | return host; | |
620 | } | |
621 | ||
622 | /* | |
623 | * Routine: host_set_exception_ports [kernel call] | |
624 | * Purpose: | |
625 | * Sets the host exception port, flavor and | |
626 | * behavior for the exception types specified by the mask. | |
627 | * There will be one send right per exception per valid | |
628 | * port. | |
629 | * Conditions: | |
630 | * Nothing locked. If successful, consumes | |
631 | * the supplied send right. | |
632 | * Returns: | |
633 | * KERN_SUCCESS Changed the special port. | |
634 | * KERN_INVALID_ARGUMENT The host_priv is not valid, | |
635 | * Illegal mask bit set. | |
636 | * Illegal exception behavior | |
637 | */ | |
638 | kern_return_t | |
639 | host_set_exception_ports( | |
640 | host_priv_t host_priv, | |
641 | exception_mask_t exception_mask, | |
642 | ipc_port_t new_port, | |
643 | exception_behavior_t new_behavior, | |
644 | thread_state_flavor_t new_flavor) | |
645 | { | |
646 | register int i; | |
647 | ipc_port_t old_port[EXC_TYPES_COUNT]; | |
648 | ||
649 | if (host_priv == HOST_PRIV_NULL) { | |
650 | return KERN_INVALID_ARGUMENT; | |
651 | } | |
652 | ||
653 | assert(host_priv == &realhost); | |
654 | ||
655 | if (exception_mask & ~EXC_MASK_ALL) { | |
656 | return KERN_INVALID_ARGUMENT; | |
657 | } | |
658 | ||
659 | if (IP_VALID(new_port)) { | |
660 | switch (new_behavior) { | |
661 | case EXCEPTION_DEFAULT: | |
662 | case EXCEPTION_STATE: | |
663 | case EXCEPTION_STATE_IDENTITY: | |
664 | break; | |
665 | default: | |
666 | return KERN_INVALID_ARGUMENT; | |
667 | } | |
668 | } | |
669 | /* Cannot easily check "new_flavor", but that just means that | |
670 | * the flavor in the generated exception message might be garbage: | |
671 | * GIGO | |
672 | */ | |
673 | host_lock(host_priv); | |
674 | ||
675 | for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) { | |
676 | if (exception_mask & (1 << i)) { | |
677 | old_port[i] = host_priv->exc_actions[i].port; | |
678 | host_priv->exc_actions[i].port = | |
679 | ipc_port_copy_send(new_port); | |
680 | host_priv->exc_actions[i].behavior = new_behavior; | |
681 | host_priv->exc_actions[i].flavor = new_flavor; | |
682 | } else | |
683 | old_port[i] = IP_NULL; | |
684 | }/* for */ | |
685 | ||
686 | /* | |
687 | * Consume send rights without any lock held. | |
688 | */ | |
689 | host_unlock(host_priv); | |
690 | for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) | |
691 | if (IP_VALID(old_port[i])) | |
692 | ipc_port_release_send(old_port[i]); | |
693 | if (IP_VALID(new_port)) /* consume send right */ | |
694 | ipc_port_release_send(new_port); | |
695 | ||
696 | return KERN_SUCCESS; | |
697 | } | |
698 | ||
699 | /* | |
700 | * Routine: host_get_exception_ports [kernel call] | |
701 | * Purpose: | |
702 | * Clones a send right for each of the host's exception | |
703 | * ports specified in the mask and returns the behaviour | |
704 | * and flavor of said port. | |
705 | * | |
706 | * Returns upto [in} CountCnt elements. | |
707 | * | |
708 | * Conditions: | |
709 | * Nothing locked. | |
710 | * Returns: | |
711 | * KERN_SUCCESS Extracted a send right. | |
712 | * KERN_INVALID_ARGUMENT Invalid host_priv specified, | |
713 | * Invalid special port, | |
714 | * Illegal mask bit set. | |
715 | * KERN_FAILURE The thread is dead. | |
716 | */ | |
717 | kern_return_t | |
718 | host_get_exception_ports( | |
719 | host_priv_t host_priv, | |
720 | exception_mask_t exception_mask, | |
721 | exception_mask_array_t masks, | |
722 | mach_msg_type_number_t * CountCnt, | |
723 | exception_port_array_t ports, | |
724 | exception_behavior_array_t behaviors, | |
725 | thread_state_flavor_array_t flavors ) | |
726 | { | |
727 | register int i, | |
728 | j, | |
729 | count; | |
730 | ||
731 | if (host_priv == HOST_PRIV_NULL) | |
732 | return KERN_INVALID_ARGUMENT; | |
733 | ||
734 | if (exception_mask & ~EXC_MASK_ALL) { | |
735 | return KERN_INVALID_ARGUMENT; | |
736 | } | |
737 | ||
738 | assert (host_priv == &realhost); | |
739 | ||
740 | host_lock(host_priv); | |
741 | ||
742 | count = 0; | |
743 | ||
744 | for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) { | |
745 | if (exception_mask & (1 << i)) { | |
746 | for (j = 0; j < count; j++) { | |
747 | /* | |
748 | * search for an identical entry, if found | |
749 | * set corresponding mask for this exception. | |
750 | */ | |
751 | if (host_priv->exc_actions[i].port == ports[j] && | |
752 | host_priv->exc_actions[i].behavior == behaviors[j] | |
753 | && host_priv->exc_actions[i].flavor == flavors[j]) | |
754 | { | |
755 | masks[j] |= (1 << i); | |
756 | break; | |
757 | } | |
758 | }/* for */ | |
759 | if (j == count) { | |
760 | masks[j] = (1 << i); | |
761 | ports[j] = | |
762 | ipc_port_copy_send(host_priv->exc_actions[i].port); | |
763 | behaviors[j] = host_priv->exc_actions[i].behavior; | |
764 | flavors[j] = host_priv->exc_actions[i].flavor; | |
765 | count++; | |
766 | if (count > *CountCnt) { | |
767 | break; | |
768 | } | |
769 | } | |
770 | } | |
771 | }/* for */ | |
772 | host_unlock(host_priv); | |
773 | ||
774 | *CountCnt = count; | |
775 | return KERN_SUCCESS; | |
776 | } | |
777 | ||
778 | kern_return_t | |
779 | host_swap_exception_ports( | |
780 | host_priv_t host_priv, | |
781 | exception_mask_t exception_mask, | |
782 | ipc_port_t new_port, | |
783 | exception_behavior_t new_behavior, | |
784 | thread_state_flavor_t new_flavor, | |
785 | exception_mask_array_t masks, | |
786 | mach_msg_type_number_t * CountCnt, | |
787 | exception_port_array_t ports, | |
788 | exception_behavior_array_t behaviors, | |
789 | thread_state_flavor_array_t flavors ) | |
790 | { | |
791 | register int i, | |
792 | j, | |
793 | count; | |
794 | ipc_port_t old_port[EXC_TYPES_COUNT]; | |
795 | ||
796 | if (host_priv == HOST_PRIV_NULL) | |
797 | return KERN_INVALID_ARGUMENT; | |
798 | ||
799 | if (exception_mask & ~EXC_MASK_ALL) { | |
800 | return KERN_INVALID_ARGUMENT; | |
801 | } | |
802 | ||
803 | if (IP_VALID(new_port)) { | |
804 | switch (new_behavior) { | |
805 | case EXCEPTION_DEFAULT: | |
806 | case EXCEPTION_STATE: | |
807 | case EXCEPTION_STATE_IDENTITY: | |
808 | break; | |
809 | default: | |
810 | return KERN_INVALID_ARGUMENT; | |
811 | } | |
812 | } | |
813 | /* Cannot easily check "new_flavor", but that just means that | |
814 | * the flavor in the generated exception message might be garbage: | |
815 | * GIGO */ | |
816 | ||
817 | host_lock(host_priv); | |
818 | ||
819 | count = 0; | |
820 | ||
821 | for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) { | |
822 | if (exception_mask & (1 << i)) { | |
823 | for (j = 0; j < count; j++) { | |
824 | /* | |
825 | * search for an identical entry, if found | |
826 | * set corresponding mask for this exception. | |
827 | */ | |
828 | if (host_priv->exc_actions[i].port == ports[j] && | |
829 | host_priv->exc_actions[i].behavior == behaviors[j] | |
830 | && host_priv->exc_actions[i].flavor == flavors[j]) | |
831 | { | |
832 | masks[j] |= (1 << i); | |
833 | break; | |
834 | } | |
835 | }/* for */ | |
836 | if (j == count) { | |
837 | masks[j] = (1 << i); | |
838 | ports[j] = | |
839 | ipc_port_copy_send(host_priv->exc_actions[i].port); | |
840 | behaviors[j] = host_priv->exc_actions[i].behavior; | |
841 | flavors[j] = host_priv->exc_actions[i].flavor; | |
842 | count++; | |
843 | } | |
844 | old_port[i] = host_priv->exc_actions[i].port; | |
845 | host_priv->exc_actions[i].port = | |
846 | ipc_port_copy_send(new_port); | |
847 | host_priv->exc_actions[i].behavior = new_behavior; | |
848 | host_priv->exc_actions[i].flavor = new_flavor; | |
849 | if (count > *CountCnt) { | |
850 | break; | |
851 | } | |
852 | } else | |
853 | old_port[i] = IP_NULL; | |
854 | }/* for */ | |
855 | host_unlock(host_priv); | |
856 | ||
857 | /* | |
858 | * Consume send rights without any lock held. | |
859 | */ | |
860 | for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) | |
861 | if (IP_VALID(old_port[i])) | |
862 | ipc_port_release_send(old_port[i]); | |
863 | if (IP_VALID(new_port)) /* consume send right */ | |
864 | ipc_port_release_send(new_port); | |
865 | *CountCnt = count; | |
866 | ||
867 | return KERN_SUCCESS; | |
868 | } |