]>
Commit | Line | Data |
---|---|---|
fe8ab488 A |
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 */ | |
43 | extern lck_grp_t ipc_lck_grp; | |
44 | extern lck_attr_t ipc_lck_attr; | |
45 | ||
46 | extern void ipc_voucher_init(void); | |
47 | ||
48 | /* some shorthand for longer types */ | |
49 | typedef mach_voucher_attr_value_handle_t iv_value_handle_t; | |
50 | typedef mach_voucher_attr_value_reference_t iv_value_refs_t; | |
51 | ||
52 | typedef natural_t iv_refs_t; | |
53 | ||
54 | typedef natural_t iv_index_t; | |
55 | #define IV_UNUSED_VALINDEX ((iv_index_t) 0) | |
56 | #define IV_UNUSED_KEYINDEX ((iv_index_t) ~0) | |
57 | ||
58 | typedef 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 | */ | |
70 | struct 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 | ||
116 | struct 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 | }; | |
129 | typedef struct ivac_entry_s ivac_entry; | |
130 | typedef 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 | ||
142 | struct 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 | }; | |
153 | typedef ipc_voucher_attr_control_t iv_attr_control_t; | |
154 | ||
155 | #define IVAC_NULL IPC_VOUCHER_ATTR_CONTROL_NULL | |
156 | ||
157 | extern 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 | ||
175 | extern void ivac_dealloc(ipc_voucher_attr_control_t ivac); | |
176 | ||
177 | static inline void | |
178 | ivac_reference(ipc_voucher_attr_control_t ivac) | |
179 | { | |
180 | (void)hw_atomic_add(&ivac->ivac_refs, 1); | |
181 | } | |
182 | ||
183 | static inline void | |
184 | ivac_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 | */ | |
209 | typedef 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 | ||
215 | typedef 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) | |
226 | typedef 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; | |
233 | typedef ipc_voucher_attr_recipe_data_t *ipc_voucher_attr_recipe_t; | |
234 | typedef mach_msg_type_number_t ipc_voucher_attr_recipe_size_t; | |
235 | ||
236 | typedef uint8_t *ipc_voucher_attr_raw_recipe_t; | |
237 | typedef ipc_voucher_attr_raw_recipe_t ipc_voucher_attr_raw_recipe_array_t; | |
238 | typedef mach_msg_type_number_t ipc_voucher_attr_raw_recipe_size_t; | |
239 | typedef 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 | ||
253 | typedef 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 | ||
258 | typedef 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 | ||
268 | typedef 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 | ||
276 | typedef 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 | ||
286 | typedef void (*ipc_voucher_attr_manager_release_t)(ipc_voucher_attr_manager_t); | |
287 | ||
288 | struct 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 */ | |
299 | extern uintptr_t unsafe_convert_port_to_voucher( | |
300 | ipc_port_t port); | |
301 | ||
302 | /* Convert from a port to a voucher */ | |
303 | extern ipc_voucher_t convert_port_to_voucher( | |
304 | ipc_port_t port); | |
305 | ||
306 | /* Convert from a port name to an ipc_voucher */ | |
307 | extern ipc_voucher_t convert_port_name_to_voucher( | |
308 | mach_port_name_t name); | |
309 | ||
310 | /* add a reference to the specified voucher */ | |
311 | extern void ipc_voucher_reference( | |
312 | ipc_voucher_t voucher); | |
313 | ||
314 | /* drop the voucher reference picked up above */ | |
315 | extern void ipc_voucher_release( | |
316 | ipc_voucher_t voucher); | |
317 | ||
318 | /* deliver voucher notifications */ | |
319 | extern void ipc_voucher_notify( | |
320 | mach_msg_header_t *msg); | |
321 | ||
322 | /* Convert from a voucher to a port */ | |
323 | extern ipc_port_t convert_voucher_to_port( | |
324 | ipc_voucher_t voucher); | |
325 | ||
326 | /* convert from a voucher attribute control to a port */ | |
327 | extern 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 */ | |
331 | extern void ipc_voucher_attr_control_reference( | |
332 | ipc_voucher_attr_control_t control); | |
333 | ||
334 | /* drop the reference picked up above */ | |
335 | extern void ipc_voucher_attr_control_release( | |
336 | ipc_voucher_attr_control_t control); | |
337 | ||
338 | /* deliver voucher control notifications */ | |
339 | extern void ipc_voucher_attr_control_notify( | |
340 | mach_msg_header_t *msg); | |
341 | ||
342 | /* convert from a port to a voucher attribute control */ | |
343 | extern 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 | */ | |
349 | extern kern_return_t | |
350 | ipc_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 | ||
355 | extern kern_return_t | |
356 | ipc_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 | ||
362 | extern kern_return_t | |
363 | ipc_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 | ||
370 | extern kern_return_t | |
371 | ipc_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_ */ |