1/*
2 * Copyright (c) 2000-2004 Apple Computer, 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#ifndef	_IPC_IPC_VOUCHER_H_
29#define	_IPC_IPC_VOUCHER_H_
30
31#include <mach/mach_types.h>
32#include <mach/mach_voucher_types.h>
33#include <mach/boolean.h>
34#include <ipc/ipc_types.h>
35
36#ifdef MACH_KERNEL_PRIVATE
37
38#include <kern/queue.h>
39#include <kern/locks.h>
40#include <kern/simple_lock.h>
41
42/* locking */
43extern lck_grp_t 	ipc_lck_grp;
44extern lck_attr_t 	ipc_lck_attr;
45
46extern void ipc_voucher_init(void);
47
48/* some shorthand for longer types */
49typedef mach_voucher_attr_value_handle_t        iv_value_handle_t;
50typedef mach_voucher_attr_value_reference_t     iv_value_refs_t;
51
52typedef natural_t		iv_refs_t;
53
54typedef natural_t 		iv_index_t;
55#define IV_UNUSED_VALINDEX	((iv_index_t) 0)
56#define IV_UNUSED_KEYINDEX 	((iv_index_t) ~0)
57
58typedef iv_index_t	 	*iv_entry_t;
59#define IVE_NULL		((iv_entry_t) 0)
60
61#define IV_ENTRIES_INLINE MACH_VOUCHER_ATTR_KEY_NUM_WELL_KNOWN
62
63/*
64 * IPC Voucher
65 *
66 * Vouchers are a reference counted immutable (once-created) set of
67 * indexes to particular resource manager attribute values
68 * (which themselves are reference counted).
69 */
70struct ipc_voucher {
71	iv_index_t		iv_hash;	/* checksum hash */
72	iv_index_t		iv_sum;		/* checksum of values */
73	iv_refs_t		iv_refs;	/* reference count */
74	iv_index_t		iv_table_size;	/* size of the voucher table */
75	iv_index_t		iv_inline_table[IV_ENTRIES_INLINE];
76	iv_entry_t		iv_table;	/* table of voucher attr entries */
77	ipc_port_t		iv_port;	/* port representing the voucher */
78	queue_chain_t		iv_hash_link;	/* link on hash chain */
79};
80
81#define IV_NULL 	IPC_VOUCHER_NULL
82
83
84/*
85 * Voucher Attribute Cache Control Object
86 *
87 * This is where the Voucher system stores its caches/references to
88 * returned resource manager attribute values.  Each value only appears
89 * once in the table.  If a value is returned more than once by the
90 * resource manager, the voucher system will increase the reference
91 * on the previous value.
92 *
93 * The voucher itself contains one entry per key, that indexes into
94 * this table.
95 *
96 * A voucher that does not have an explicit index for a given key
97 * is assumed to have a reference on slot zero - which is where the
98 * voucher system stores the default value for the given attribute
99 * (specified at the time of resource manager registration).
100 *
101 * The ivace_releasing field limits the entry to a single concurrent
102 * return. Without it, a previous release's reply might still be
103 * working its way back to the voucher code, and a subsequent get-
104 * value could return the same value as was previously returned.  If
105 * the resource manager already knew that, it would return a failure
106 * on the return, and all is well.  We just treat the additional made
107 * references on the value as we normally would.  However, if the resource
108 * manager accepted the return, and the get-value response raced the
109 * release's reply, the newly made references will look like an extension
110 * of the old value's cache lifetime, rather than a new one.  Dropping
111 * that new lifetime's references to zero would result in a second
112 * release callback to the resource manager - this time with the wrong
113 * "made" reference count.  We avoid the race with this flag.
114 */
115
116struct ivac_entry_s {
117	iv_value_handle_t       ivace_value;
118	iv_value_refs_t         ivace_layered:1,     /* layered effective entry */
119	                        ivace_releasing:1,   /* release in progress */
120				ivace_free:1,	     /* on freelist */
121	                        ivace_refs:29;       /* reference count */
122	union {
123		iv_value_refs_t ivaceu_made;         /* made count (non-layered) */
124		iv_index_t      ivaceu_layer;        /* next effective layer (layered) */
125	} ivace_u;
126	iv_index_t              ivace_next;          /* hash or freelist */
127	iv_index_t              ivace_index;         /* hash head (independent) */
128};
129typedef struct ivac_entry_s       ivac_entry;
130typedef ivac_entry              *ivac_entry_t;
131
132#define ivace_made              ivace_u.ivaceu_made
133#define ivace_layer             ivace_u.ivaceu_layer
134
135#define IVACE_NULL              ((ivac_entry_t) 0);
136
137#define IVACE_REFS_MAX          ((1 << 29) - 1)
138
139#define IVAC_ENTRIES_MIN        512
140#define IVAC_ENTRIES_MAX        524288
141
142struct ipc_voucher_attr_control {
143	iv_refs_t               ivac_refs;
144	boolean_t               ivac_is_growing;	/* is the table being grown */
145	ivac_entry_t            ivac_table;		/* table of voucher attr value entries */
146	iv_index_t              ivac_table_size;	/* size of the attr value table */
147	iv_index_t              ivac_init_table_size;	/* size of the attr value table */
148	iv_index_t              ivac_freelist;  	/* index of the first free element */
149	ipc_port_t              ivac_port;		/* port for accessing the cache control  */
150	lck_spin_t              ivac_lock_data;
151	iv_index_t              ivac_key_index;		/* key index for this value */
152};
153typedef ipc_voucher_attr_control_t iv_attr_control_t;
154
155#define IVAC_NULL                  IPC_VOUCHER_ATTR_CONTROL_NULL
156
157extern ipc_voucher_attr_control_t  ivac_alloc(iv_index_t);
158
159#define ivac_lock_init(ivac) \
160	lck_spin_init(&(ivac)->ivac_lock_data, &ipc_lck_grp, &ipc_lck_attr)
161#define ivac_lock_destroy(ivac) \
162	lck_spin_destroy(&(ivac)->ivac_lock_data, &ipc_lck_grp)
163#define	ivac_lock(ivac) \
164	lck_spin_lock(&(ivac)->ivac_lock_data)
165#define	ivac_lock_try(ivac) \
166	lck_spin_try_lock(&(ivac)->ivac_lock_data)
167#define	ivac_unlock(ivac) \
168	lck_spin_unlock(&(ivac)->ivac_lock_data)
169#define ivac_sleep(ivac) lck_spin_sleep(&(ivac)->ivac_lock_data,	\
170					LCK_SLEEP_DEFAULT,		\
171					(event_t)(ivac),		\
172					THREAD_UNINT)
173#define ivac_wakeup(ivac) thread_wakeup((event_t)(ivac))
174
175extern void ivac_dealloc(ipc_voucher_attr_control_t ivac);
176
177static inline void
178ivac_reference(ipc_voucher_attr_control_t ivac)
179{
180	(void)hw_atomic_add(&ivac->ivac_refs, 1);
181}
182
183static inline void
184ivac_release(ipc_voucher_attr_control_t ivac)
185{
186	iv_refs_t refs;
187
188	if (IVAC_NULL == ivac)
189		return;
190
191	refs = hw_atomic_sub(&ivac->ivac_refs, 1);
192	if (refs == 0)
193		ivac_dealloc(ivac);
194}
195
196#define IVAM_NULL IPC_VOUCHER_ATTR_MANAGER_NULL
197
198/*
199 * IPC voucher Resource Manager table element
200 *
201 * Information Associated with a specific registration of
202 * a voucher resource manager.
203 *
204 * NOTE: For now, this table is indexed directly by the key.  In the future,
205 * it will have to be growable and sparse by key.  When that is implemented
206 * the index will be independent from the key (but there will be a hash to
207 * find the index by key).
208 */
209typedef struct ipc_voucher_global_table_element {
210	ipc_voucher_attr_manager_t	ivgte_manager;
211	ipc_voucher_attr_control_t	ivgte_control;
212	mach_voucher_attr_key_t		ivgte_key;
213} ipc_voucher_global_table_element;
214
215typedef ipc_voucher_global_table_element *ipc_voucher_global_table_element_t;
216
217#endif /* MACH_KERNEL_PRIVATE */
218
219/*
220 * IPC voucher attribute recipe
221 *
222 * In-kernel recipe format with an ipc_voucher_t pointer for the previous
223 * voucher reference.
224 */
225#pragma pack(1)
226typedef struct ipc_voucher_attr_recipe_data {
227	mach_voucher_attr_key_t	                key;
228	mach_voucher_attr_recipe_command_t      command;
229	ipc_voucher_t		                previous_voucher;
230	mach_voucher_attr_content_size_t	content_size;
231	uint8_t				        content[];
232} ipc_voucher_attr_recipe_data_t;
233typedef ipc_voucher_attr_recipe_data_t *ipc_voucher_attr_recipe_t;
234typedef mach_msg_type_number_t ipc_voucher_attr_recipe_size_t;
235
236typedef uint8_t *ipc_voucher_attr_raw_recipe_t;
237typedef ipc_voucher_attr_raw_recipe_t ipc_voucher_attr_raw_recipe_array_t;
238typedef mach_msg_type_number_t ipc_voucher_attr_raw_recipe_size_t;
239typedef mach_msg_type_number_t ipc_voucher_attr_raw_recipe_array_size_t;
240
241#pragma pack()
242
243/*
244 * In-kernel Resource Manager Definition
245 *
246 * In-kernel resource managers are defined by a v-table like structure for
247 * the three callouts supported by a resource manager (and release function).
248 *
249 * There is a single in-kernel resource manager that represents all the
250 * outside kernel managers (and reflects the calls through MIG to user-space).
251 */
252
253typedef kern_return_t (*ipc_voucher_attr_manager_release_value_t)(ipc_voucher_attr_manager_t,
254								  mach_voucher_attr_key_t,
255								  mach_voucher_attr_value_handle_t,
256								  mach_voucher_attr_value_reference_t);
257
258typedef kern_return_t (*ipc_voucher_attr_manager_get_value_t)(ipc_voucher_attr_manager_t,
259							      mach_voucher_attr_key_t,
260							      mach_voucher_attr_recipe_command_t,
261							      mach_voucher_attr_value_handle_array_t,
262							      mach_voucher_attr_value_handle_array_size_t,
263							      mach_voucher_attr_content_t,
264							      mach_voucher_attr_content_size_t,
265							      mach_voucher_attr_value_handle_t *,
266							      ipc_voucher_t *);
267
268typedef kern_return_t (*ipc_voucher_attr_manager_extract_content_t)(ipc_voucher_attr_manager_t,
269								    mach_voucher_attr_key_t,
270								    mach_voucher_attr_value_handle_array_t,
271								    mach_voucher_attr_value_handle_array_size_t,
272								    mach_voucher_attr_recipe_command_t *,
273								    mach_voucher_attr_content_t,
274								    mach_voucher_attr_content_size_t *);
275
276typedef kern_return_t (*ipc_voucher_attr_manager_command_t)(ipc_voucher_attr_manager_t,
277							    mach_voucher_attr_key_t,
278							    mach_voucher_attr_value_handle_array_t,
279							    mach_voucher_attr_value_handle_array_size_t,
280							    mach_voucher_attr_command_t,
281							    mach_voucher_attr_content_t,
282							    mach_voucher_attr_content_size_t,
283							    mach_voucher_attr_content_t,
284							    mach_voucher_attr_content_size_t *);
285
286typedef void (*ipc_voucher_attr_manager_release_t)(ipc_voucher_attr_manager_t);
287
288struct ipc_voucher_attr_manager {
289	ipc_voucher_attr_manager_release_value_t	ivam_release_value;
290	ipc_voucher_attr_manager_get_value_t		ivam_get_value;
291	ipc_voucher_attr_manager_extract_content_t	ivam_extract_content;
292	ipc_voucher_attr_manager_command_t		ivam_command;
293	ipc_voucher_attr_manager_release_t		ivam_release;
294};
295
296__BEGIN_DECLS
297
298/* DEBUG/TRACE Convert from a port to a voucher */
299extern uintptr_t unsafe_convert_port_to_voucher(
300	ipc_port_t		port);
301
302/* Convert from a port to a voucher */
303extern ipc_voucher_t convert_port_to_voucher(
304	ipc_port_t		port);
305
306/* Convert from a port name to an ipc_voucher */
307extern ipc_voucher_t convert_port_name_to_voucher(
308	mach_port_name_t	name);
309
310/* add a reference to the specified voucher */
311extern void ipc_voucher_reference(
312	ipc_voucher_t		voucher);
313
314/* drop the voucher reference picked up above */
315extern void ipc_voucher_release(
316	ipc_voucher_t		voucher);
317
318/* deliver voucher notifications */
319extern void ipc_voucher_notify(
320	mach_msg_header_t 	*msg);
321
322/* Convert from a voucher to a port */
323extern ipc_port_t convert_voucher_to_port(
324	ipc_voucher_t		voucher);
325
326/* convert from a voucher attribute control to a port */
327extern ipc_port_t convert_voucher_attr_control_to_port(
328	ipc_voucher_attr_control_t	control);
329
330/* add a reference to the specified voucher */
331extern void ipc_voucher_attr_control_reference(
332	ipc_voucher_attr_control_t	control);
333
334/* drop the reference picked up above */
335extern void ipc_voucher_attr_control_release(
336	ipc_voucher_attr_control_t	control);
337
338/* deliver voucher control notifications */
339extern void ipc_voucher_attr_control_notify(
340	mach_msg_header_t 	*msg);
341
342/* convert from a port to a voucher attribute control */
343extern ipc_voucher_attr_control_t convert_port_to_voucher_attr_control(
344	ipc_port_t 		port);
345
346/*
347 * In-kernel equivalents to the user syscalls
348 */
349extern kern_return_t
350ipc_create_mach_voucher(
351	ipc_voucher_attr_raw_recipe_array_t	 	recipes,
352	ipc_voucher_attr_raw_recipe_array_size_t	recipe_size,
353	ipc_voucher_t 					*new_voucher);
354
355extern kern_return_t
356ipc_voucher_attr_control_create_mach_voucher(
357	ipc_voucher_attr_control_t			control,
358	ipc_voucher_attr_raw_recipe_array_t 		recipes,
359	ipc_voucher_attr_raw_recipe_array_size_t	recipe_size,
360	ipc_voucher_t 					*new_voucher);
361
362extern kern_return_t
363ipc_register_well_known_mach_voucher_attr_manager(
364	ipc_voucher_attr_manager_t 		manager,
365	mach_voucher_attr_value_handle_t 	default_value,
366        mach_voucher_attr_key_t 		key,
367	ipc_voucher_attr_control_t 		*control);
368
369
370extern kern_return_t
371ipc_register_mach_voucher_attr_manager(
372	ipc_voucher_attr_manager_t 		manager,
373	mach_voucher_attr_value_handle_t 	default_value,
374        mach_voucher_attr_key_t 		*key,
375	ipc_voucher_attr_control_t 		*control);
376
377__END_DECLS
378
379#endif	/* _IPC_IPC_VOUCHER_H_ */
380