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 | #include <os/refcnt.h> |
36 | |
37 | #ifdef MACH_KERNEL_PRIVATE |
38 | |
39 | #include <kern/queue.h> |
40 | #include <kern/locks.h> |
41 | #include <kern/simple_lock.h> |
42 | #include <voucher/ipc_pthread_priority_types.h> |
43 | |
44 | /* locking */ |
45 | extern lck_grp_t ipc_lck_grp; |
46 | extern lck_attr_t ipc_lck_attr; |
47 | |
48 | extern void ipc_voucher_init(void); |
49 | |
50 | /* some shorthand for longer types */ |
51 | typedef mach_voucher_attr_value_handle_t iv_value_handle_t; |
52 | typedef mach_voucher_attr_value_reference_t iv_value_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 | os_refcnt_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_persist:1, /* Persist the entry, don't count made refs */ |
122 | ivace_refs:28; /* reference count */ |
123 | union { |
124 | iv_value_refs_t ivaceu_made; /* made count (non-layered) */ |
125 | iv_index_t ivaceu_layer; /* next effective layer (layered) */ |
126 | } ivace_u; |
127 | iv_index_t ivace_next; /* hash or freelist */ |
128 | iv_index_t ivace_index; /* hash head (independent) */ |
129 | }; |
130 | typedef struct ivac_entry_s ivac_entry; |
131 | typedef ivac_entry *ivac_entry_t; |
132 | |
133 | #define ivace_made ivace_u.ivaceu_made |
134 | #define ivace_layer ivace_u.ivaceu_layer |
135 | |
136 | #define IVACE_NULL ((ivac_entry_t) 0); |
137 | |
138 | #define IVACE_REFS_MAX ((1 << 28) - 1) |
139 | |
140 | #define IVAC_ENTRIES_MIN 512 |
141 | #define IVAC_ENTRIES_MAX 524288 |
142 | |
143 | struct ipc_voucher_attr_control { |
144 | os_refcnt_t ivac_refs; |
145 | boolean_t ivac_is_growing; /* is the table being grown */ |
146 | ivac_entry_t ivac_table; /* table of voucher attr value entries */ |
147 | iv_index_t ivac_table_size; /* size of the attr value table */ |
148 | iv_index_t ivac_init_table_size; /* size of the attr value table */ |
149 | iv_index_t ivac_freelist; /* index of the first free element */ |
150 | ipc_port_t ivac_port; /* port for accessing the cache control */ |
151 | lck_spin_t ivac_lock_data; |
152 | iv_index_t ivac_key_index; /* key index for this value */ |
153 | }; |
154 | typedef ipc_voucher_attr_control_t iv_attr_control_t; |
155 | |
156 | #define IVAC_NULL IPC_VOUCHER_ATTR_CONTROL_NULL |
157 | |
158 | extern ipc_voucher_attr_control_t ivac_alloc(iv_index_t); |
159 | extern void ipc_voucher_receive_postprocessing(ipc_kmsg_t kmsg, mach_msg_option_t option); |
160 | extern void ipc_voucher_send_preprocessing(ipc_kmsg_t kmsg); |
161 | extern void mach_init_activity_id(void); |
162 | extern kern_return_t ipc_get_pthpriority_from_kmsg_voucher(ipc_kmsg_t kmsg, ipc_pthread_priority_value_t *qos); |
163 | #define ivac_lock_init(ivac) \ |
164 | lck_spin_init(&(ivac)->ivac_lock_data, &ipc_lck_grp, &ipc_lck_attr) |
165 | #define ivac_lock_destroy(ivac) \ |
166 | lck_spin_destroy(&(ivac)->ivac_lock_data, &ipc_lck_grp) |
167 | #define ivac_lock(ivac) \ |
168 | lck_spin_lock(&(ivac)->ivac_lock_data) |
169 | #define ivac_lock_try(ivac) \ |
170 | lck_spin_try_lock(&(ivac)->ivac_lock_data) |
171 | #define ivac_unlock(ivac) \ |
172 | lck_spin_unlock(&(ivac)->ivac_lock_data) |
173 | #define ivac_sleep(ivac) lck_spin_sleep(&(ivac)->ivac_lock_data, \ |
174 | LCK_SLEEP_DEFAULT, \ |
175 | (event_t)(ivac), \ |
176 | THREAD_UNINT) |
177 | #define ivac_wakeup(ivac) thread_wakeup((event_t)(ivac)) |
178 | |
179 | extern void ivac_dealloc(ipc_voucher_attr_control_t ivac); |
180 | |
181 | static inline void |
182 | ivac_reference(ipc_voucher_attr_control_t ivac) |
183 | { |
184 | if (ivac == IVAC_NULL) |
185 | return; |
186 | os_ref_retain(&ivac->ivac_refs); |
187 | } |
188 | |
189 | static inline void |
190 | ivac_release(ipc_voucher_attr_control_t ivac) |
191 | { |
192 | if (IVAC_NULL == ivac) |
193 | return; |
194 | |
195 | if (os_ref_release(&ivac->ivac_refs) == 0) { |
196 | ivac_dealloc(ivac); |
197 | } |
198 | } |
199 | |
200 | #define IVAM_NULL IPC_VOUCHER_ATTR_MANAGER_NULL |
201 | |
202 | /* |
203 | * IPC voucher Resource Manager table element |
204 | * |
205 | * Information Associated with a specific registration of |
206 | * a voucher resource manager. |
207 | * |
208 | * NOTE: For now, this table is indexed directly by the key. In the future, |
209 | * it will have to be growable and sparse by key. When that is implemented |
210 | * the index will be independent from the key (but there will be a hash to |
211 | * find the index by key). |
212 | */ |
213 | typedef struct ipc_voucher_global_table_element { |
214 | ipc_voucher_attr_manager_t ivgte_manager; |
215 | ipc_voucher_attr_control_t ivgte_control; |
216 | mach_voucher_attr_key_t ivgte_key; |
217 | } ipc_voucher_global_table_element; |
218 | |
219 | typedef ipc_voucher_global_table_element *ipc_voucher_global_table_element_t; |
220 | |
221 | #endif /* MACH_KERNEL_PRIVATE */ |
222 | |
223 | /* |
224 | * IPC voucher attribute recipe |
225 | * |
226 | * In-kernel recipe format with an ipc_voucher_t pointer for the previous |
227 | * voucher reference. |
228 | */ |
229 | #pragma pack(1) |
230 | typedef struct ipc_voucher_attr_recipe_data { |
231 | mach_voucher_attr_key_t key; |
232 | mach_voucher_attr_recipe_command_t command; |
233 | ipc_voucher_t previous_voucher; |
234 | mach_voucher_attr_content_size_t content_size; |
235 | uint8_t content[]; |
236 | } ipc_voucher_attr_recipe_data_t; |
237 | typedef ipc_voucher_attr_recipe_data_t *ipc_voucher_attr_recipe_t; |
238 | typedef mach_msg_type_number_t ipc_voucher_attr_recipe_size_t; |
239 | |
240 | typedef uint8_t *ipc_voucher_attr_raw_recipe_t; |
241 | typedef ipc_voucher_attr_raw_recipe_t ipc_voucher_attr_raw_recipe_array_t; |
242 | typedef mach_msg_type_number_t ipc_voucher_attr_raw_recipe_size_t; |
243 | typedef mach_msg_type_number_t ipc_voucher_attr_raw_recipe_array_size_t; |
244 | |
245 | #pragma pack() |
246 | |
247 | /* |
248 | * In-kernel Resource Manager Definition |
249 | * |
250 | * In-kernel resource managers are defined by a v-table like structure for |
251 | * the three callouts supported by a resource manager (and release function). |
252 | * |
253 | * There is a single in-kernel resource manager that represents all the |
254 | * outside kernel managers (and reflects the calls through MIG to user-space). |
255 | */ |
256 | |
257 | typedef kern_return_t (*ipc_voucher_attr_manager_release_value_t)(ipc_voucher_attr_manager_t, |
258 | mach_voucher_attr_key_t, |
259 | mach_voucher_attr_value_handle_t, |
260 | mach_voucher_attr_value_reference_t); |
261 | |
262 | typedef kern_return_t (*ipc_voucher_attr_manager_get_value_t)(ipc_voucher_attr_manager_t, |
263 | mach_voucher_attr_key_t, |
264 | mach_voucher_attr_recipe_command_t, |
265 | mach_voucher_attr_value_handle_array_t, |
266 | mach_voucher_attr_value_handle_array_size_t, |
267 | mach_voucher_attr_content_t, |
268 | mach_voucher_attr_content_size_t, |
269 | mach_voucher_attr_value_handle_t *, |
270 | mach_voucher_attr_value_flags_t *, |
271 | ipc_voucher_t *); |
272 | |
273 | typedef kern_return_t (*)(ipc_voucher_attr_manager_t, |
274 | mach_voucher_attr_key_t, |
275 | mach_voucher_attr_value_handle_array_t, |
276 | mach_voucher_attr_value_handle_array_size_t, |
277 | mach_voucher_attr_recipe_command_t *, |
278 | mach_voucher_attr_content_t, |
279 | mach_voucher_attr_content_size_t *); |
280 | |
281 | typedef kern_return_t (*ipc_voucher_attr_manager_command_t)(ipc_voucher_attr_manager_t, |
282 | mach_voucher_attr_key_t, |
283 | mach_voucher_attr_value_handle_array_t, |
284 | mach_voucher_attr_value_handle_array_size_t, |
285 | mach_voucher_attr_command_t, |
286 | mach_voucher_attr_content_t, |
287 | mach_voucher_attr_content_size_t, |
288 | mach_voucher_attr_content_t, |
289 | mach_voucher_attr_content_size_t *); |
290 | |
291 | typedef void (*ipc_voucher_attr_manager_release_t)(ipc_voucher_attr_manager_t); |
292 | |
293 | typedef uint32_t ipc_voucher_attr_manager_flags; |
294 | |
295 | struct ipc_voucher_attr_manager { |
296 | ipc_voucher_attr_manager_release_value_t ivam_release_value; |
297 | ipc_voucher_attr_manager_get_value_t ivam_get_value; |
298 | ipc_voucher_attr_manager_extract_content_t ; |
299 | ipc_voucher_attr_manager_command_t ivam_command; |
300 | ipc_voucher_attr_manager_release_t ivam_release; |
301 | ipc_voucher_attr_manager_flags ivam_flags; |
302 | }; |
303 | |
304 | #define IVAM_FLAGS_NONE 0 |
305 | #define IVAM_FLAGS_SUPPORT_SEND_PREPROCESS 0x1 |
306 | #define IVAM_FLAGS_SUPPORT_RECEIVE_POSTPROCESS 0x2 |
307 | |
308 | __BEGIN_DECLS |
309 | |
310 | /* DEBUG/TRACE Convert from a port to a voucher */ |
311 | extern uintptr_t unsafe_convert_port_to_voucher( |
312 | ipc_port_t port); |
313 | |
314 | /* Convert from a port to a voucher */ |
315 | extern ipc_voucher_t convert_port_to_voucher( |
316 | ipc_port_t port); |
317 | |
318 | /* Convert from a port name to an ipc_voucher */ |
319 | extern ipc_voucher_t convert_port_name_to_voucher( |
320 | mach_port_name_t name); |
321 | |
322 | /* add a reference to the specified voucher */ |
323 | extern void ipc_voucher_reference( |
324 | ipc_voucher_t voucher); |
325 | |
326 | /* drop the voucher reference picked up above */ |
327 | extern void ipc_voucher_release( |
328 | ipc_voucher_t voucher); |
329 | |
330 | /* deliver voucher notifications */ |
331 | extern void ipc_voucher_notify( |
332 | mach_msg_header_t *msg); |
333 | |
334 | /* Convert from a voucher to a port */ |
335 | extern ipc_port_t convert_voucher_to_port( |
336 | ipc_voucher_t voucher); |
337 | |
338 | /* convert from a voucher attribute control to a port */ |
339 | extern ipc_port_t convert_voucher_attr_control_to_port( |
340 | ipc_voucher_attr_control_t control); |
341 | |
342 | /* add a reference to the specified voucher */ |
343 | extern void ipc_voucher_attr_control_reference( |
344 | ipc_voucher_attr_control_t control); |
345 | |
346 | /* drop the reference picked up above */ |
347 | extern void ipc_voucher_attr_control_release( |
348 | ipc_voucher_attr_control_t control); |
349 | |
350 | /* deliver voucher control notifications */ |
351 | extern void ipc_voucher_attr_control_notify( |
352 | mach_msg_header_t *msg); |
353 | |
354 | /* convert from a port to a voucher attribute control */ |
355 | extern ipc_voucher_attr_control_t convert_port_to_voucher_attr_control( |
356 | ipc_port_t port); |
357 | |
358 | /* |
359 | * In-kernel equivalents to the user syscalls |
360 | */ |
361 | extern kern_return_t |
362 | ipc_create_mach_voucher( |
363 | ipc_voucher_attr_raw_recipe_array_t recipes, |
364 | ipc_voucher_attr_raw_recipe_array_size_t recipe_size, |
365 | ipc_voucher_t *new_voucher); |
366 | |
367 | extern kern_return_t |
368 | ipc_voucher_attr_control_create_mach_voucher( |
369 | ipc_voucher_attr_control_t control, |
370 | ipc_voucher_attr_raw_recipe_array_t recipes, |
371 | ipc_voucher_attr_raw_recipe_array_size_t recipe_size, |
372 | ipc_voucher_t *new_voucher); |
373 | |
374 | extern kern_return_t |
375 | ipc_register_well_known_mach_voucher_attr_manager( |
376 | ipc_voucher_attr_manager_t manager, |
377 | mach_voucher_attr_value_handle_t default_value, |
378 | mach_voucher_attr_key_t key, |
379 | ipc_voucher_attr_control_t *control); |
380 | |
381 | |
382 | extern kern_return_t |
383 | ipc_register_mach_voucher_attr_manager( |
384 | ipc_voucher_attr_manager_t manager, |
385 | mach_voucher_attr_value_handle_t default_value, |
386 | mach_voucher_attr_key_t *key, |
387 | ipc_voucher_attr_control_t *control); |
388 | |
389 | __END_DECLS |
390 | |
391 | #endif /* _IPC_IPC_VOUCHER_H_ */ |
392 | |