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