| 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 | |