| 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/smr_types.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 | /* some shorthand for longer types */ |
| 49 | typedef mach_voucher_attr_value_handle_t iv_value_handle_t __kernel_ptr_semantics; |
| 50 | typedef mach_voucher_attr_value_reference_t iv_value_refs_t; |
| 51 | |
| 52 | typedef natural_t iv_index_t; |
| 53 | #define IV_UNUSED_VALINDEX ((iv_index_t) 0) |
| 54 | #define IV_UNUSED_KEYINDEX ((iv_index_t) ~0) |
| 55 | |
| 56 | typedef iv_index_t *iv_entry_t; |
| 57 | #define IVE_NULL ((iv_entry_t) 0) |
| 58 | |
| 59 | /* actual number of attribute managers supported by kernel */ |
| 60 | #if CONFIG_VOUCHER_DEPRECATED |
| 61 | #define MACH_VOUCHER_ATTR_KEY_NUM MACH_VOUCHER_ATTR_KEY_TEST |
| 62 | #else |
| 63 | #define MACH_VOUCHER_ATTR_KEY_NUM MACH_VOUCHER_ATTR_KEY_BANK |
| 64 | #endif /* CONFIG_VOUCHER_DEPRECATED */ |
| 65 | |
| 66 | /* |
| 67 | * IPC Voucher |
| 68 | * |
| 69 | * Vouchers are a reference counted immutable (once-created) set of |
| 70 | * indexes to particular resource manager attribute values |
| 71 | * (which themselves are reference counted). |
| 72 | */ |
| 73 | struct ipc_voucher { |
| 74 | os_ref_atomic_t iv_refs; /* reference count */ |
| 75 | iv_index_t iv_table[MACH_VOUCHER_ATTR_KEY_NUM]; |
| 76 | ipc_port_t iv_port; /* port representing the voucher */ |
| 77 | struct smrq_slink iv_hash_link; /* link on hash chain */ |
| 78 | }; |
| 79 | |
| 80 | #define IV_NULL IPC_VOUCHER_NULL |
| 81 | |
| 82 | |
| 83 | /* |
| 84 | * Voucher Attribute Cache Control Object |
| 85 | * |
| 86 | * This is where the Voucher system stores its caches/references to |
| 87 | * returned resource manager attribute values. Each value only appears |
| 88 | * once in the table. If a value is returned more than once by the |
| 89 | * resource manager, the voucher system will increase the reference |
| 90 | * on the previous value. |
| 91 | * |
| 92 | * The voucher itself contains one entry per key, that indexes into |
| 93 | * this table. |
| 94 | * |
| 95 | * A voucher that does not have an explicit index for a given key |
| 96 | * is assumed to have a reference on slot zero - which is where the |
| 97 | * voucher system stores the default value for the given attribute |
| 98 | * (specified at the time of resource manager registration). |
| 99 | * |
| 100 | * The ivace_releasing field limits the entry to a single concurrent |
| 101 | * return. Without it, a previous release's reply might still be |
| 102 | * working its way back to the voucher code, and a subsequent get- |
| 103 | * value could return the same value as was previously returned. If |
| 104 | * the resource manager already knew that, it would return a failure |
| 105 | * on the return, and all is well. We just treat the additional made |
| 106 | * references on the value as we normally would. However, if the resource |
| 107 | * manager accepted the return, and the get-value response raced the |
| 108 | * release's reply, the newly made references will look like an extension |
| 109 | * of the old value's cache lifetime, rather than a new one. Dropping |
| 110 | * that new lifetime's references to zero would result in a second |
| 111 | * release callback to the resource manager - this time with the wrong |
| 112 | * "made" reference count. We avoid the race with this flag. |
| 113 | */ |
| 114 | |
| 115 | struct ivac_entry_s { |
| 116 | iv_value_handle_t ivace_value; |
| 117 | iv_value_refs_t ivace_layered:1, /* layered effective entry */ |
| 118 | ivace_releasing:1, /* release in progress */ |
| 119 | ivace_free:1, /* on freelist */ |
| 120 | ivace_persist:1, /* Persist the entry, don't count made refs */ |
| 121 | ivace_refs:28; /* 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 << 28) - 1) |
| 138 | |
| 139 | #define IVAC_ENTRIES_MIN 512 |
| 140 | #define IVAC_ENTRIES_MAX 524288 |
| 141 | |
| 142 | struct ipc_voucher_attr_control { |
| 143 | boolean_t ivac_is_growing; /* is the table being grown */ |
| 144 | ivac_entry_t ivac_table; /* table of voucher attr value entries */ |
| 145 | iv_index_t ivac_table_size; /* size of the attr value table */ |
| 146 | iv_index_t ivac_init_table_size; /* size of the attr value table */ |
| 147 | iv_index_t ivac_freelist; /* index of the first free element */ |
| 148 | lck_spin_t ivac_lock_data; |
| 149 | iv_index_t ivac_key_index; |
| 150 | }; |
| 151 | typedef ipc_voucher_attr_control_t iv_attr_control_t; |
| 152 | |
| 153 | #define IVAC_NULL IPC_VOUCHER_ATTR_CONTROL_NULL |
| 154 | |
| 155 | extern void ipc_voucher_receive_postprocessing(ipc_kmsg_t kmsg, mach_msg_option_t option); |
| 156 | extern void ipc_voucher_send_preprocessing(ipc_kmsg_t kmsg); |
| 157 | extern ipc_voucher_t ipc_voucher_get_default_voucher(void); |
| 158 | extern void mach_init_activity_id(void); |
| 159 | #if CONFIG_VOUCHER_DEPRECATED |
| 160 | extern kern_return_t ipc_get_pthpriority_from_kmsg_voucher(ipc_kmsg_t kmsg, ipc_pthread_priority_value_t *qos); |
| 161 | #endif /* CONFIG_VOUCHER_DEPRECATED */ |
| 162 | |
| 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_grp(&(ivac)->ivac_lock_data, &ipc_lck_grp) |
| 169 | #define ivac_lock_try(ivac) \ |
| 170 | lck_spin_try_lock_grp(&(ivac)->ivac_lock_data, &ipc_lck_grp) |
| 171 | #define ivac_unlock(ivac) \ |
| 172 | lck_spin_unlock(&(ivac)->ivac_lock_data) |
| 173 | #define ivac_sleep(ivac) lck_spin_sleep_grp(&(ivac)->ivac_lock_data, \ |
| 174 | LCK_SLEEP_DEFAULT, \ |
| 175 | (event_t)(ivac), \ |
| 176 | THREAD_UNINT, &ipc_lck_grp) |
| 177 | #define ivac_wakeup(ivac) thread_wakeup((event_t)(ivac)) |
| 178 | |
| 179 | #define IVAM_NULL IPC_VOUCHER_ATTR_MANAGER_NULL |
| 180 | |
| 181 | #endif /* MACH_KERNEL_PRIVATE */ |
| 182 | |
| 183 | /* |
| 184 | * IPC voucher attribute recipe |
| 185 | * |
| 186 | * In-kernel recipe format with an ipc_voucher_t pointer for the previous |
| 187 | * voucher reference. |
| 188 | */ |
| 189 | #pragma pack(1) |
| 190 | typedef struct ipc_voucher_attr_recipe_data { |
| 191 | mach_voucher_attr_key_t key; |
| 192 | mach_voucher_attr_recipe_command_t command; |
| 193 | ipc_voucher_t previous_voucher; |
| 194 | mach_voucher_attr_content_size_t content_size; |
| 195 | uint8_t content[]; |
| 196 | } ipc_voucher_attr_recipe_data_t; |
| 197 | typedef ipc_voucher_attr_recipe_data_t *ipc_voucher_attr_recipe_t; |
| 198 | typedef mach_msg_type_number_t ipc_voucher_attr_recipe_size_t; |
| 199 | |
| 200 | typedef uint8_t *ipc_voucher_attr_raw_recipe_t; |
| 201 | typedef ipc_voucher_attr_raw_recipe_t ipc_voucher_attr_raw_recipe_array_t; |
| 202 | typedef mach_msg_type_number_t ipc_voucher_attr_raw_recipe_size_t; |
| 203 | typedef mach_msg_type_number_t ipc_voucher_attr_raw_recipe_array_size_t; |
| 204 | |
| 205 | #pragma pack() |
| 206 | |
| 207 | /* |
| 208 | * In-kernel Resource Manager Definition |
| 209 | * |
| 210 | * In-kernel resource managers are defined by a v-table like structure for |
| 211 | * the three callouts supported by a resource manager (and release function). |
| 212 | * |
| 213 | * There is a single in-kernel resource manager that represents all the |
| 214 | * outside kernel managers (and reflects the calls through MIG to user-space). |
| 215 | */ |
| 216 | |
| 217 | typedef kern_return_t (*ipc_voucher_attr_manager_release_value_t)(ipc_voucher_attr_manager_t, |
| 218 | mach_voucher_attr_key_t, |
| 219 | mach_voucher_attr_value_handle_t, |
| 220 | mach_voucher_attr_value_reference_t); |
| 221 | |
| 222 | typedef kern_return_t (*ipc_voucher_attr_manager_get_value_t)(ipc_voucher_attr_manager_t, |
| 223 | mach_voucher_attr_key_t, |
| 224 | mach_voucher_attr_recipe_command_t, |
| 225 | mach_voucher_attr_value_handle_array_t, |
| 226 | mach_voucher_attr_value_handle_array_size_t, |
| 227 | mach_voucher_attr_content_t, |
| 228 | mach_voucher_attr_content_size_t, |
| 229 | mach_voucher_attr_value_handle_t *, |
| 230 | mach_voucher_attr_value_flags_t *, |
| 231 | ipc_voucher_t *); |
| 232 | |
| 233 | typedef kern_return_t (*)(ipc_voucher_attr_manager_t, |
| 234 | mach_voucher_attr_key_t, |
| 235 | mach_voucher_attr_value_handle_array_t, |
| 236 | mach_voucher_attr_value_handle_array_size_t, |
| 237 | mach_voucher_attr_recipe_command_t *, |
| 238 | mach_voucher_attr_content_t, |
| 239 | mach_voucher_attr_content_size_t *); |
| 240 | |
| 241 | typedef kern_return_t (*ipc_voucher_attr_manager_command_t)(ipc_voucher_attr_manager_t, |
| 242 | mach_voucher_attr_key_t, |
| 243 | mach_voucher_attr_value_handle_array_t, |
| 244 | mach_voucher_attr_value_handle_array_size_t, |
| 245 | mach_voucher_attr_command_t, |
| 246 | mach_voucher_attr_content_t, |
| 247 | mach_voucher_attr_content_size_t, |
| 248 | mach_voucher_attr_content_t, |
| 249 | mach_voucher_attr_content_size_t *); |
| 250 | |
| 251 | typedef void (*ipc_voucher_attr_manager_release_t)(ipc_voucher_attr_manager_t); |
| 252 | |
| 253 | typedef uint32_t ipc_voucher_attr_manager_flags; |
| 254 | |
| 255 | struct ipc_voucher_attr_manager { |
| 256 | ipc_voucher_attr_manager_release_value_t ivam_release_value; |
| 257 | ipc_voucher_attr_manager_get_value_t ivam_get_value; |
| 258 | ipc_voucher_attr_manager_extract_content_t ; |
| 259 | ipc_voucher_attr_manager_command_t ivam_command; |
| 260 | ipc_voucher_attr_manager_flags ivam_flags; |
| 261 | }; |
| 262 | |
| 263 | #define IVAM_FLAGS_NONE 0 |
| 264 | #define IVAM_FLAGS_SUPPORT_SEND_PREPROCESS 0x1 |
| 265 | #define IVAM_FLAGS_SUPPORT_RECEIVE_POSTPROCESS 0x2 |
| 266 | |
| 267 | __BEGIN_DECLS |
| 268 | |
| 269 | /* DEBUG/TRACE Convert from a port to a voucher */ |
| 270 | extern uintptr_t unsafe_convert_port_to_voucher( |
| 271 | ipc_port_t port) __pure2; |
| 272 | |
| 273 | /* Convert from a port to a voucher */ |
| 274 | extern ipc_voucher_t convert_port_to_voucher( |
| 275 | ipc_port_t port); |
| 276 | |
| 277 | /* Convert from a port name to an ipc_voucher */ |
| 278 | extern ipc_voucher_t convert_port_name_to_voucher( |
| 279 | mach_port_name_t name); |
| 280 | |
| 281 | /* add a reference to the specified voucher */ |
| 282 | extern void ipc_voucher_reference( |
| 283 | ipc_voucher_t voucher); |
| 284 | |
| 285 | /* drop the voucher reference picked up above */ |
| 286 | extern void ipc_voucher_release( |
| 287 | ipc_voucher_t voucher); |
| 288 | |
| 289 | /* Convert from a voucher to a port */ |
| 290 | extern ipc_port_t convert_voucher_to_port( |
| 291 | ipc_voucher_t voucher); |
| 292 | |
| 293 | /* |
| 294 | * In-kernel equivalents to the user syscalls |
| 295 | */ |
| 296 | extern kern_return_t |
| 297 | ipc_create_mach_voucher( |
| 298 | ipc_voucher_attr_raw_recipe_array_t recipes, |
| 299 | ipc_voucher_attr_raw_recipe_array_size_t recipe_size, |
| 300 | ipc_voucher_t *new_voucher); |
| 301 | |
| 302 | extern kern_return_t |
| 303 | ipc_voucher_attr_control_create_mach_voucher( |
| 304 | ipc_voucher_attr_control_t control, |
| 305 | ipc_voucher_attr_raw_recipe_array_t recipes, |
| 306 | ipc_voucher_attr_raw_recipe_array_size_t recipe_size, |
| 307 | ipc_voucher_t *new_voucher); |
| 308 | |
| 309 | extern void |
| 310 | ipc_register_well_known_mach_voucher_attr_manager( |
| 311 | ipc_voucher_attr_manager_t manager, |
| 312 | mach_voucher_attr_value_handle_t default_value, |
| 313 | mach_voucher_attr_key_t key, |
| 314 | ipc_voucher_attr_control_t *control); |
| 315 | |
| 316 | extern kern_return_t |
| 317 | mach_voucher_attr_control_get_values( |
| 318 | ipc_voucher_attr_control_t control, |
| 319 | ipc_voucher_t voucher, |
| 320 | mach_voucher_attr_value_handle_t *out_values, |
| 321 | mach_msg_type_number_t *in_out_size); |
| 322 | |
| 323 | __END_DECLS |
| 324 | |
| 325 | #endif /* _IPC_IPC_VOUCHER_H_ */ |
| 326 | |