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