]> git.saurik.com Git - apple/xnu.git/blame - osfmk/atm/atm.c
xnu-6153.61.1.tar.gz
[apple/xnu.git] / osfmk / atm / atm.c
CommitLineData
fe8ab488
A
1/*
2 * Copyright (c) 2012-2013 Apple 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
29#include <atm/atm_internal.h>
30#include <mach/mach_types.h>
31#include <mach/kern_return.h>
32#include <ipc/ipc_port.h>
33#include <mach/mach_vm.h>
34#include <mach/vm_map.h>
35#include <vm/vm_map.h>
36#include <atm/atm_notification.h>
37#include <mach/host_priv.h>
38#include <mach/host_special_ports.h>
39#include <kern/host.h>
40#include <kern/kalloc.h>
3e170ce0 41#include <machine/commpage.h>
fe8ab488
A
42
43#define MAX_ATM_VALUES (2 * 4096)
44#define MAX_TRACE_BUFFER_SIZE (0x40000000) /* Restrict to 1GB per task */
fe8ab488
A
45
46#define ATM_VALUE_TO_HANDLE(x) (CAST_DOWN(atm_voucher_id_t, (x)))
47#define HANDLE_TO_ATM_VALUE(x) (CAST_DOWN(atm_value_t, (x)))
48
49#define ATM_MAX_HASH_TABLE_SIZE (256)
50#define AID_HASH_MASK (0xFF)
51#define AID_TO_HASH(x) ((x) & (AID_HASH_MASK))
52
53#define ATM_LIST_DEAD_MAX 15
54
55#define AID_ARRAY_COUNT_MAX (256)
56
57struct atm_value_hash atm_value_hash_table[ATM_MAX_HASH_TABLE_SIZE];
58extern int maxproc;
59
60/* Global flag to disable ATM. ATM get value and memory registration will return error. */
61boolean_t disable_atm = FALSE;
62
63#if DEVELOPMENT || DEBUG
64queue_head_t atm_descriptors_list;
65queue_head_t atm_values_list;
66#endif
67
68ipc_voucher_attr_control_t voucher_attr_control; /* communication channel from ATM to voucher system */
69static zone_t atm_value_zone, atm_descriptors_zone, atm_link_objects_zone;
70
5ba3f43e
A
71static aid_t get_aid(void);
72static mach_atm_subaid_t get_subaid(void);
3e170ce0 73static atm_value_t atm_value_alloc_init(aid_t);
fe8ab488 74static void atm_value_dealloc(atm_value_t atm_value);
5ba3f43e 75static void atm_hash_table_init(void);
3e170ce0 76static kern_return_t atm_value_hash_table_insert(atm_value_t new_atm_value);
fe8ab488 77static void atm_value_hash_table_delete(atm_value_t atm_value);
3e170ce0 78static atm_value_t get_atm_value_from_aid(aid_t aid) __unused;
3e170ce0 79static kern_return_t atm_listener_insert(atm_value_t atm_value, atm_task_descriptor_t task_descriptor, atm_guard_t guard);
fe8ab488 80static void atm_listener_delete_all(atm_value_t atm_value);
0a7de745 81static atm_task_descriptor_t atm_task_descriptor_alloc_init(mach_port_t trace_buffer, uint64_t buffer_size, __assert_only task_t task);
fe8ab488 82static void atm_task_descriptor_dealloc(atm_task_descriptor_t task_descriptor);
3e170ce0
A
83static kern_return_t atm_value_unregister(atm_value_t atm_value, atm_task_descriptor_t task_descriptor, atm_guard_t guard);
84static kern_return_t atm_value_register(atm_value_t atm_value, atm_task_descriptor_t task_descriptor, atm_guard_t guard);
85static kern_return_t atm_listener_delete(atm_value_t atm_value, atm_task_descriptor_t task_descriptor, atm_guard_t guard);
fe8ab488 86static void atm_link_dealloc(atm_link_object_t link_object);
fe8ab488
A
87
88kern_return_t
89atm_release_value(
90 ipc_voucher_attr_manager_t __assert_only manager,
91 mach_voucher_attr_key_t __assert_only key,
92 mach_voucher_attr_value_handle_t value,
93 mach_voucher_attr_value_reference_t sync);
94
95kern_return_t
96atm_get_value(
97 ipc_voucher_attr_manager_t __assert_only manager,
98 mach_voucher_attr_key_t __assert_only key,
99 mach_voucher_attr_recipe_command_t command,
100 mach_voucher_attr_value_handle_array_t prev_values,
101 mach_msg_type_number_t __assert_only prev_value_count,
102 mach_voucher_attr_content_t recipe,
103 mach_voucher_attr_content_size_t recipe_size,
104 mach_voucher_attr_value_handle_t *out_value,
490019cf 105 mach_voucher_attr_value_flags_t *out_flags,
fe8ab488
A
106 ipc_voucher_t *out_value_voucher);
107
108kern_return_t
109atm_extract_content(
110 ipc_voucher_attr_manager_t __assert_only manager,
111 mach_voucher_attr_key_t __assert_only key,
112 mach_voucher_attr_value_handle_array_t values,
113 mach_msg_type_number_t value_count,
114 mach_voucher_attr_recipe_command_t *out_command,
115 mach_voucher_attr_content_t out_recipe,
116 mach_voucher_attr_content_size_t *in_out_recipe_size);
117
118kern_return_t
119atm_command(
120 ipc_voucher_attr_manager_t __assert_only manager,
121 mach_voucher_attr_key_t __assert_only key,
122 mach_voucher_attr_value_handle_array_t values,
123 mach_msg_type_number_t value_count,
124 mach_voucher_attr_command_t command,
125 mach_voucher_attr_content_t in_content,
126 mach_voucher_attr_content_size_t in_content_size,
127 mach_voucher_attr_content_t out_content,
128 mach_voucher_attr_content_size_t *in_out_content_size);
129
130void
131atm_release(ipc_voucher_attr_manager_t __assert_only manager);
132
133/*
134 * communication channel from voucher system to ATM
135 */
cb323159 136const struct ipc_voucher_attr_manager atm_manager = {
fe8ab488
A
137 .ivam_release_value = atm_release_value,
138 .ivam_get_value = atm_get_value,
139 .ivam_extract_content = atm_extract_content,
0a7de745 140 .ivam_command = atm_command,
fe8ab488 141 .ivam_release = atm_release,
490019cf 142 .ivam_flags = IVAM_FLAGS_NONE,
fe8ab488
A
143};
144
145#if DEVELOPMENT || DEBUG
146decl_lck_mtx_data(, atm_descriptors_list_lock);
147decl_lck_mtx_data(, atm_values_list_lock);
148
0a7de745
A
149lck_grp_t atm_dev_lock_grp;
150lck_attr_t atm_dev_lock_attr;
151lck_grp_attr_t atm_dev_lock_grp_attr;
fe8ab488
A
152#endif
153
154extern vm_map_t kernel_map;
155/*
156 * Global aid. Incremented on each get_aid.
157 */
158aid_t global_aid;
159
3e170ce0
A
160/*
161 * Global subaid. Incremented on each get_subaid.
162 */
163mach_atm_subaid_t global_subaid;
164
fe8ab488
A
165/*
166 * Lock group attributes for atm sub system.
167 */
0a7de745
A
168lck_grp_t atm_lock_grp;
169lck_attr_t atm_lock_attr;
170lck_grp_attr_t atm_lock_grp_attr;
fe8ab488 171
3e170ce0
A
172/*
173 * Global that is set by diagnosticd and readable by userspace
174 * via the commpage.
175 */
176static uint32_t atm_diagnostic_config;
fe8ab488
A
177
178/*
179 * Routine: atm_init
180 * Purpose: Initialize the atm subsystem.
181 * Returns: None.
182 */
183void
184atm_init()
185{
186 kern_return_t kr = KERN_SUCCESS;
187 char temp_buf[20];
188
189 /* Disable atm if disable_atm present in device-tree properties or in boot-args */
0a7de745 190 if ((PE_get_default("kern.disable_atm", temp_buf, sizeof(temp_buf))) ||
fe8ab488
A
191 (PE_parse_boot_argn("-disable_atm", temp_buf, sizeof(temp_buf)))) {
192 disable_atm = TRUE;
193 }
194
3e170ce0 195 if (!PE_parse_boot_argn("atm_diagnostic_config", &atm_diagnostic_config, sizeof(atm_diagnostic_config))) {
0a7de745 196 if (!PE_get_default("kern.atm_diagnostic_config", &atm_diagnostic_config, sizeof(atm_diagnostic_config))) {
3e170ce0
A
197 atm_diagnostic_config = 0;
198 }
199 }
200
fe8ab488
A
201 /* setup zones for descriptors, values and link objects */
202 atm_value_zone = zinit(sizeof(struct atm_value),
0a7de745
A
203 MAX_ATM_VALUES * sizeof(struct atm_value),
204 sizeof(struct atm_value),
205 "atm_values");
fe8ab488
A
206
207 atm_descriptors_zone = zinit(sizeof(struct atm_task_descriptor),
0a7de745
A
208 MAX_ATM_VALUES * sizeof(struct atm_task_descriptor),
209 sizeof(struct atm_task_descriptor),
210 "atm_task_descriptors");
fe8ab488
A
211
212 atm_link_objects_zone = zinit(sizeof(struct atm_link_object),
0a7de745
A
213 MAX_ATM_VALUES * sizeof(struct atm_link_object),
214 sizeof(struct atm_link_object),
215 "atm_link_objects");
fe8ab488
A
216
217 /* Initialize atm lock group and lock attributes. */
218 lck_grp_attr_setdefault(&atm_lock_grp_attr);
219 lck_grp_init(&atm_lock_grp, "atm_lock", &atm_lock_grp_attr);
220 lck_attr_setdefault(&atm_lock_attr);
221
222 global_aid = 1;
3e170ce0 223 global_subaid = 1;
fe8ab488
A
224 atm_hash_table_init();
225
226#if DEVELOPMENT || DEBUG
227 /* Initialize global atm development lock group and lock attributes. */
228 lck_grp_attr_setdefault(&atm_dev_lock_grp_attr);
229 lck_grp_init(&atm_dev_lock_grp, "atm_dev_lock", &atm_dev_lock_grp_attr);
230 lck_attr_setdefault(&atm_dev_lock_attr);
231
232 lck_mtx_init(&atm_descriptors_list_lock, &atm_dev_lock_grp, &atm_dev_lock_attr);
233 lck_mtx_init(&atm_values_list_lock, &atm_dev_lock_grp, &atm_dev_lock_attr);
234
235 queue_init(&atm_descriptors_list);
236 queue_init(&atm_values_list);
237#endif
238
239 /* Register the atm manager with the Vouchers sub system. */
240 kr = ipc_register_well_known_mach_voucher_attr_manager(
0a7de745
A
241 &atm_manager,
242 0,
243 MACH_VOUCHER_ATTR_KEY_ATM,
244 &voucher_attr_control);
245 if (kr != KERN_SUCCESS) {
fe8ab488 246 panic("ATM subsystem initialization failed");
0a7de745 247 }
fe8ab488
A
248
249 kprintf("ATM subsystem is initialized\n");
0a7de745 250 return;
fe8ab488
A
251}
252
253
254/*
255 * ATM Resource Manager Routines.
256 */
257
258
259/*
260 * Routine: atm_release_value
261 * Purpose: Release a value, if sync matches the sync count in value.
262 * Returns: KERN_SUCCESS: on Successful deletion.
263 * KERN_FAILURE: if sync value does not matches.
264 */
265kern_return_t
266atm_release_value(
0a7de745
A
267 ipc_voucher_attr_manager_t __assert_only manager,
268 mach_voucher_attr_key_t __assert_only key,
269 mach_voucher_attr_value_handle_t value,
270 mach_voucher_attr_value_reference_t sync)
fe8ab488
A
271{
272 atm_value_t atm_value = ATM_VALUE_NULL;
273
274 assert(MACH_VOUCHER_ATTR_KEY_ATM == key);
275 assert(manager == &atm_manager);
276
277 atm_value = HANDLE_TO_ATM_VALUE(value);
278 if (atm_value == VAM_DEFAULT_VALUE) {
279 /* Return success for default value */
280 return KERN_SUCCESS;
281 }
282
283 if (atm_value->sync != sync) {
284 return KERN_FAILURE;
285 }
286
287 /* Deallocate the atm value. */
288 atm_value_hash_table_delete(atm_value);
289 atm_value_dealloc(atm_value);
290 return KERN_SUCCESS;
291}
292
293
294/*
295 * Routine: atm_get_value
296 */
297kern_return_t
298atm_get_value(
0a7de745
A
299 ipc_voucher_attr_manager_t __assert_only manager,
300 mach_voucher_attr_key_t __assert_only key,
301 mach_voucher_attr_recipe_command_t command,
302 mach_voucher_attr_value_handle_array_t prev_values,
303 mach_msg_type_number_t __assert_only prev_value_count,
fe8ab488
A
304 mach_voucher_attr_content_t __unused recipe,
305 mach_voucher_attr_content_size_t __unused recipe_size,
306 mach_voucher_attr_value_handle_t *out_value,
490019cf 307 mach_voucher_attr_value_flags_t *out_flags,
0a7de745 308 ipc_voucher_t *out_value_voucher)
fe8ab488
A
309{
310 atm_value_t atm_value = ATM_VALUE_NULL;
311 mach_voucher_attr_value_handle_t atm_handle;
312 atm_task_descriptor_t task_descriptor = ATM_TASK_DESCRIPTOR_NULL;
313 task_t task;
3e170ce0
A
314 aid_t aid;
315 atm_guard_t guard;
fe8ab488
A
316 natural_t i;
317 kern_return_t kr = KERN_SUCCESS;
318
319 assert(MACH_VOUCHER_ATTR_KEY_ATM == key);
320 assert(manager == &atm_manager);
321
322 /* never an out voucher */
323 *out_value_voucher = IPC_VOUCHER_NULL;
490019cf 324 *out_flags = MACH_VOUCHER_ATTR_VALUE_FLAGS_NONE;
fe8ab488 325
0a7de745 326 if (disable_atm || (atm_get_diagnostic_config() & ATM_TRACE_DISABLE)) {
fe8ab488 327 return KERN_NOT_SUPPORTED;
0a7de745 328 }
fe8ab488
A
329
330 switch (command) {
fe8ab488
A
331 case MACH_VOUCHER_ATTR_ATM_REGISTER:
332
333 for (i = 0; i < prev_value_count; i++) {
334 atm_handle = prev_values[i];
335 atm_value = HANDLE_TO_ATM_VALUE(atm_handle);
336
0a7de745 337 if (atm_value == VAM_DEFAULT_VALUE) {
fe8ab488 338 continue;
0a7de745 339 }
fe8ab488 340
3e170ce0
A
341 if (recipe_size != sizeof(atm_guard_t)) {
342 kr = KERN_INVALID_ARGUMENT;
343 break;
344 }
345 memcpy(&guard, recipe, sizeof(atm_guard_t));
346
fe8ab488
A
347 task = current_task();
348 task_descriptor = task->atm_context;
0a7de745 349
3e170ce0
A
350 kr = atm_value_register(atm_value, task_descriptor, guard);
351 if (kr != KERN_SUCCESS) {
04b8595b 352 break;
fe8ab488
A
353 }
354
355 /* Increment sync value. */
3e170ce0 356 atm_sync_reference_internal(atm_value);
fe8ab488
A
357
358 *out_value = atm_handle;
359 return kr;
360 }
361
362 *out_value = ATM_VALUE_TO_HANDLE(VAM_DEFAULT_VALUE);
363 break;
364
365 case MACH_VOUCHER_ATTR_ATM_CREATE:
366
3e170ce0
A
367 /* Handle the old case where aid value is created in kernel */
368 if (recipe_size == 0) {
369 aid = get_aid();
370 } else if (recipe_size == sizeof(aid_t)) {
371 memcpy(&aid, recipe, sizeof(aid_t));
372 } else {
373 kr = KERN_INVALID_ARGUMENT;
374 break;
375 }
0a7de745 376
fe8ab488 377 /* Allocate a new atm value. */
3e170ce0 378 atm_value = atm_value_alloc_init(aid);
fe8ab488 379 if (atm_value == ATM_VALUE_NULL) {
3e170ce0
A
380 kr = KERN_RESOURCE_SHORTAGE;
381 break;
382 }
0a7de745 383redrive:
3e170ce0
A
384 kr = atm_value_hash_table_insert(atm_value);
385 if (kr != KERN_SUCCESS) {
386 if (recipe_size == 0) {
387 atm_value->aid = get_aid();
388 goto redrive;
389 }
390 atm_value_dealloc(atm_value);
391 break;
fe8ab488
A
392 }
393
394 *out_value = ATM_VALUE_TO_HANDLE(atm_value);
395 break;
396
397 case MACH_VOUCHER_ATTR_ATM_NULL:
398 default:
399 kr = KERN_INVALID_ARGUMENT;
400 break;
401 }
402
403 return kr;
404}
405
406
407/*
408 * Routine: atm_extract_content
409 * Purpose: Extract a set of aid from an array of voucher values.
410 * Returns: KERN_SUCCESS: on Success.
411 * KERN_FAILURE: one of the value is not present in the hash.
412 * KERN_NO_SPACE: insufficeint buffer provided to fill an array of aid.
413 */
414kern_return_t
415atm_extract_content(
416 ipc_voucher_attr_manager_t __assert_only manager,
417 mach_voucher_attr_key_t __assert_only key,
418 mach_voucher_attr_value_handle_array_t values,
0a7de745 419 mach_msg_type_number_t value_count,
fe8ab488
A
420 mach_voucher_attr_recipe_command_t *out_command,
421 mach_voucher_attr_content_t out_recipe,
422 mach_voucher_attr_content_size_t *in_out_recipe_size)
423{
424 atm_value_t atm_value;
425 mach_voucher_attr_value_handle_t atm_handle;
426 natural_t i;
427
428 assert(MACH_VOUCHER_ATTR_KEY_ATM == key);
429 assert(manager == &atm_manager);
430
0a7de745 431 for (i = 0; i < value_count && *in_out_recipe_size > 0; i++) {
fe8ab488
A
432 atm_handle = values[i];
433 atm_value = HANDLE_TO_ATM_VALUE(atm_handle);
0a7de745 434 if (atm_value == VAM_DEFAULT_VALUE) {
fe8ab488 435 continue;
0a7de745 436 }
fe8ab488 437
0a7de745 438 if ((sizeof(aid_t)) > *in_out_recipe_size) {
fe8ab488
A
439 *in_out_recipe_size = 0;
440 return KERN_NO_SPACE;
441 }
442
443 memcpy(&out_recipe[0], &atm_value->aid, sizeof(aid_t));
444 *out_command = MACH_VOUCHER_ATTR_ATM_NULL;
445 *in_out_recipe_size = sizeof(aid_t);
446 return KERN_SUCCESS;
447 }
448
449 *in_out_recipe_size = 0;
450 return KERN_SUCCESS;
451}
452
453/*
454 * Routine: atm_command
455 * Purpose: Execute a command against a set of ATM values.
456 * Returns: KERN_SUCCESS: On successful execution of command.
0a7de745 457 * KERN_FAILURE: On failure.
fe8ab488
A
458 */
459kern_return_t
460atm_command(
0a7de745
A
461 ipc_voucher_attr_manager_t __assert_only manager,
462 mach_voucher_attr_key_t __assert_only key,
463 mach_voucher_attr_value_handle_array_t values,
464 mach_msg_type_number_t value_count,
465 mach_voucher_attr_command_t command,
466 mach_voucher_attr_content_t in_content,
fe8ab488 467 mach_voucher_attr_content_size_t in_content_size,
0a7de745 468 mach_voucher_attr_content_t out_content,
fe8ab488
A
469 mach_voucher_attr_content_size_t *out_content_size)
470{
471 assert(MACH_VOUCHER_ATTR_KEY_ATM == key);
472 assert(manager == &atm_manager);
473 atm_value_t atm_value = ATM_VALUE_NULL;
474 natural_t i = 0;
fe8ab488 475 mach_atm_subaid_t *subaid_array = NULL;
3e170ce0 476 mach_atm_subaid_t next_subaid = 0;
fe8ab488
A
477 uint32_t aid_array_count = 0;
478 atm_task_descriptor_t task_descriptor = ATM_TASK_DESCRIPTOR_NULL;
479 task_t task;
fe8ab488 480 kern_return_t kr = KERN_SUCCESS;
3e170ce0 481 atm_guard_t guard;
0a7de745 482
fe8ab488
A
483 switch (command) {
484 case ATM_ACTION_COLLECT:
0a7de745 485 /* Fall through */
fe8ab488 486
e8c3f781
A
487 case ATM_ACTION_LOGFAIL:
488 return KERN_NOT_SUPPORTED;
fe8ab488
A
489
490 case ATM_FIND_MIN_SUB_AID:
0a7de745 491 if ((in_content_size / sizeof(aid_t)) > (*out_content_size / sizeof(mach_atm_subaid_t))) {
fe8ab488 492 return KERN_FAILURE;
0a7de745 493 }
fe8ab488
A
494
495 aid_array_count = in_content_size / sizeof(aid_t);
0a7de745 496 if (aid_array_count > AID_ARRAY_COUNT_MAX) {
fe8ab488 497 return KERN_FAILURE;
0a7de745 498 }
fe8ab488 499
3e170ce0
A
500 subaid_array = (mach_atm_subaid_t *) (void *) out_content;
501 for (i = 0; i < aid_array_count; i++) {
502 subaid_array[i] = ATM_SUBAID32_MAX;
fe8ab488
A
503 }
504
fe8ab488
A
505 *out_content_size = aid_array_count * sizeof(mach_atm_subaid_t);
506
fe8ab488
A
507 kr = KERN_SUCCESS;
508
509 break;
510
511 case ATM_ACTION_UNREGISTER:
512 /* find the first non-default atm_value */
513 for (i = 0; i < value_count; i++) {
514 atm_value = HANDLE_TO_ATM_VALUE(values[i]);
0a7de745 515 if (atm_value != VAM_DEFAULT_VALUE) {
fe8ab488 516 break;
0a7de745 517 }
fe8ab488
A
518 }
519
520 /* if we are not able to find any atm values
521 * in stack then this call was made in error
522 */
523 if (atm_value == NULL) {
524 return KERN_FAILURE;
525 }
0a7de745 526 if (in_content == NULL || in_content_size != sizeof(atm_guard_t)) {
fe8ab488
A
527 return KERN_INVALID_ARGUMENT;
528 }
529
3e170ce0 530 memcpy(&guard, in_content, sizeof(atm_guard_t));
fe8ab488
A
531 task = current_task();
532 task_descriptor = task->atm_context;
533
3e170ce0 534 kr = atm_value_unregister(atm_value, task_descriptor, guard);
fe8ab488
A
535
536 break;
537
3e170ce0
A
538 case ATM_ACTION_REGISTER:
539 for (i = 0; i < value_count; i++) {
540 atm_value = HANDLE_TO_ATM_VALUE(values[i]);
0a7de745 541 if (atm_value != VAM_DEFAULT_VALUE) {
3e170ce0 542 break;
0a7de745 543 }
3e170ce0
A
544 }
545 /* if we are not able to find any atm values
546 * in stack then this call was made in error
547 */
548 if (atm_value == NULL) {
549 return KERN_FAILURE;
550 }
0a7de745 551 if (in_content == NULL || in_content_size != sizeof(atm_guard_t)) {
3e170ce0
A
552 return KERN_INVALID_ARGUMENT;
553 }
554
555 memcpy(&guard, in_content, sizeof(atm_guard_t));
556 task = current_task();
557 task_descriptor = task->atm_context;
558
559 kr = atm_value_register(atm_value, task_descriptor, guard);
560
561 break;
562
563 case ATM_ACTION_GETSUBAID:
0a7de745 564 if (out_content == NULL || *out_content_size != sizeof(mach_atm_subaid_t)) {
3e170ce0 565 return KERN_FAILURE;
0a7de745 566 }
3e170ce0
A
567
568 next_subaid = get_subaid();
569 memcpy(out_content, &next_subaid, sizeof(mach_atm_subaid_t));
570 break;
571
fe8ab488
A
572 default:
573 kr = KERN_INVALID_ARGUMENT;
574 break;
575 }
576
577 return kr;
578}
579
580
581void
582atm_release(
0a7de745 583 ipc_voucher_attr_manager_t __assert_only manager)
fe8ab488
A
584{
585 assert(manager == &atm_manager);
586}
587
588
fe8ab488
A
589/*
590 * Routine: atm_value_alloc_init
591 * Purpose: Allocates an atm value struct and initialize it.
592 * Returns: atm_value_t: On Success with a sync count on atm_value.
593 * ATM_VALUE_NULL: On failure.
594 */
595static atm_value_t
3e170ce0 596atm_value_alloc_init(aid_t aid)
fe8ab488
A
597{
598 atm_value_t new_atm_value = ATM_VALUE_NULL;
599
600 new_atm_value = (atm_value_t) zalloc(atm_value_zone);
0a7de745 601 if (new_atm_value == ATM_VALUE_NULL) {
fe8ab488 602 panic("Ran out of ATM values structure.\n\n");
0a7de745 603 }
fe8ab488 604
3e170ce0 605 new_atm_value->aid = aid;
fe8ab488
A
606 queue_init(&new_atm_value->listeners);
607 new_atm_value->sync = 1;
608 new_atm_value->listener_count = 0;
cb323159 609 os_ref_init(&new_atm_value->reference_count, NULL);
fe8ab488
A
610 lck_mtx_init(&new_atm_value->listener_lock, &atm_lock_grp, &atm_lock_attr);
611
612#if DEVELOPMENT || DEBUG
613 lck_mtx_lock(&atm_values_list_lock);
614 queue_enter(&atm_values_list, new_atm_value, atm_value_t, value_elt);
615 lck_mtx_unlock(&atm_values_list_lock);
616#endif
617 return new_atm_value;
618}
619
620
621/*
622 * Routine: get_aid
623 * Purpose: Increment the global aid counter and return it.
624 * Returns: aid
625 */
626static aid_t
627get_aid()
628{
629 aid_t aid;
630 aid = (aid_t)OSIncrementAtomic64((SInt64 *)&global_aid);
631 return aid;
632}
633
634
3e170ce0
A
635/*
636 * Routine: get_subaid
637 * Purpose: Increment the global subaid counter and return it.
638 * Returns: subaid
639 */
640static mach_atm_subaid_t
641get_subaid()
642{
643 mach_atm_subaid_t next_subaid;
644 next_subaid = (mach_atm_subaid_t)OSIncrementAtomic64((SInt64 *)&global_subaid);
645 return next_subaid;
646}
647
648
fe8ab488
A
649/*
650 * Routine: atm_value_dealloc
651 * Purpose: Drops the reference on atm value and deallocates.
652 * Deletes all the listeners on deallocation.
653 * Returns: None.
654 */
655static void
656atm_value_dealloc(atm_value_t atm_value)
657{
cb323159
A
658 if (os_ref_release(&atm_value->reference_count) == 0) {
659 /* Free up the atm value and also remove all the listeners. */
660 atm_listener_delete_all(atm_value);
fe8ab488 661
cb323159 662 lck_mtx_destroy(&atm_value->listener_lock, &atm_lock_grp);
fe8ab488
A
663
664#if DEVELOPMENT || DEBUG
cb323159
A
665 lck_mtx_lock(&atm_values_list_lock);
666 queue_remove(&atm_values_list, atm_value, atm_value_t, value_elt);
667 lck_mtx_unlock(&atm_values_list_lock);
fe8ab488 668#endif
cb323159
A
669 zfree(atm_value_zone, atm_value);
670 }
fe8ab488
A
671}
672
673
674/*
675 * Routine: atm_hash_table_init
676 * Purpose: Initialize the atm aid hash table.
677 * Returns: None.
678 */
679static void
680atm_hash_table_init()
681{
682 int i;
683
684 for (i = 0; i < ATM_MAX_HASH_TABLE_SIZE; i++) {
685 queue_init(&atm_value_hash_table[i].hash_list);
686 lck_mtx_init(&atm_value_hash_table[i].hash_list_lock, &atm_lock_grp, &atm_lock_attr);
687 }
688}
689
690
691/*
692 * Routine: atm_value_hash_table_insert
693 * Purpose: Insert an atm value in the hash table.
3e170ce0
A
694 * Returns: KERN_SUCCESS on success.
695 * KERN_NAME_EXISTS if atm value already in the hash table.
fe8ab488 696 */
3e170ce0 697static kern_return_t
fe8ab488
A
698atm_value_hash_table_insert(atm_value_t new_atm_value)
699{
700 int hash_index;
701 atm_value_hash_t hash_list_head;
702 aid_t aid = new_atm_value->aid;
3e170ce0 703 atm_value_t next;
fe8ab488
A
704
705 hash_index = AID_TO_HASH(aid);
706 hash_list_head = &atm_value_hash_table[hash_index];
707
3e170ce0 708 /* Lock the atm list and search for the aid. */
fe8ab488 709 lck_mtx_lock(&hash_list_head->hash_list_lock);
3e170ce0
A
710
711 queue_iterate(&hash_list_head->hash_list, next, atm_value_t, vid_hash_elt) {
712 if (next->aid == aid) {
713 /*
714 * aid found. return error.
715 */
716 lck_mtx_unlock(&hash_list_head->hash_list_lock);
0a7de745 717 return KERN_NAME_EXISTS;
3e170ce0
A
718 }
719 }
720
721 /* Enter the aid in hash and return success. */
fe8ab488
A
722 queue_enter(&hash_list_head->hash_list, new_atm_value, atm_value_t, vid_hash_elt);
723 lck_mtx_unlock(&hash_list_head->hash_list_lock);
3e170ce0 724 return KERN_SUCCESS;
fe8ab488
A
725}
726
727
728/*
729 * Routine: atm_value_hash_table_delete
730 * Purpose: Delete the atm value from the hash table.
731 * Returns: None.
732 */
733static void
734atm_value_hash_table_delete(atm_value_t atm_value)
735{
736 int hash_index;
737 atm_value_hash_t hash_list_head;
738 aid_t aid = atm_value->aid;
739
740 hash_index = AID_TO_HASH(aid);
741 hash_list_head = &atm_value_hash_table[hash_index];
742
743 lck_mtx_lock(&hash_list_head->hash_list_lock);
744 queue_remove(&hash_list_head->hash_list, atm_value, atm_value_t, vid_hash_elt);
745 lck_mtx_unlock(&hash_list_head->hash_list_lock);
746}
747
748
749/*
750 * Routine: get_atm_value_from_aid
751 * Purpose: Search a given aid in atm value hash table and
752 * return the atm value stucture.
753 * Returns: atm value structure if aid found.
754 * ATM_VALUE_NULL: If aid not found in atm value hash table.
755 */
756static atm_value_t
757get_atm_value_from_aid(aid_t aid)
758{
759 int hash_index;
760 atm_value_hash_t hash_list_head;
761 atm_value_t next;
762
763 hash_index = AID_TO_HASH(aid);
764 hash_list_head = &atm_value_hash_table[hash_index];
765
766 /* Lock the atm list and search for the aid. */
767 lck_mtx_lock(&hash_list_head->hash_list_lock);
768
769 queue_iterate(&hash_list_head->hash_list, next, atm_value_t, vid_hash_elt) {
770 if (next->aid == aid) {
771 /*
772 * Aid found. Incerease ref count and return
773 * the atm value structure.
774 */
cb323159 775 os_ref_retain(&next->reference_count);
fe8ab488 776 lck_mtx_unlock(&hash_list_head->hash_list_lock);
0a7de745 777 return next;
fe8ab488
A
778 }
779 }
780 lck_mtx_unlock(&hash_list_head->hash_list_lock);
781 return ATM_VALUE_NULL;
782}
783
784
fe8ab488
A
785/*
786 * Routine: atm_listener_insert
787 * Purpose: Insert a listener to an atm value.
788 * Returns: KERN_SUCCESS on success.
789 * KERN_FAILURE if the task is already present as a listener.
790 */
791static kern_return_t
792atm_listener_insert(
0a7de745
A
793 atm_value_t atm_value,
794 atm_task_descriptor_t task_descriptor,
795 atm_guard_t guard)
fe8ab488
A
796{
797 atm_link_object_t new_link_object;
3e170ce0
A
798 atm_link_object_t next, elem;
799 int32_t freed_count = 0, dead_but_not_freed = 0, listener_count;
800 boolean_t element_found = FALSE;
801 queue_head_t free_listeners;
fe8ab488
A
802
803 new_link_object = (atm_link_object_t) zalloc(atm_link_objects_zone);
804 new_link_object->descriptor = task_descriptor;
cb323159 805 os_ref_init(&new_link_object->reference_count, NULL);
3e170ce0 806 new_link_object->guard = guard;
fe8ab488
A
807
808 /* Get a reference on the task descriptor */
cb323159 809 os_ref_retain(&task_descriptor->reference_count);
3e170ce0
A
810 queue_init(&free_listeners);
811 listener_count = atm_value->listener_count;
fe8ab488 812
3e170ce0 813 /* Check if the task is already on the listener list */
fe8ab488 814 lck_mtx_lock(&atm_value->listener_lock);
3e170ce0
A
815
816 next = (atm_link_object_t)(void *) queue_first(&atm_value->listeners);
817 while (!queue_end(&atm_value->listeners, (queue_entry_t)next)) {
818 elem = next;
819 next = (atm_link_object_t)(void *) queue_next(&next->listeners_element);
820
821 /* Check for dead tasks */
822 if (elem->descriptor->flags == ATM_TASK_DEAD) {
823 if ((dead_but_not_freed > ATM_LIST_DEAD_MAX) || elem->guard == 0) {
824 queue_remove(&atm_value->listeners, elem, atm_link_object_t, listeners_element);
825 queue_enter(&free_listeners, elem, atm_link_object_t, listeners_element);
826 atm_listener_count_decr_internal(atm_value);
827 freed_count++;
828 } else {
829 dead_but_not_freed++;
830 }
831 continue;
832 }
833
0a7de745 834 if (element_found) {
3e170ce0 835 continue;
0a7de745 836 }
3e170ce0
A
837
838 if (elem->descriptor == task_descriptor) {
839 /* Increment reference count on Link object. */
cb323159 840 os_ref_retain(&elem->reference_count);
3e170ce0
A
841
842 /* Replace the guard with the new one, the old guard is anyways on unregister path. */
843 elem->guard = guard;
844 element_found = TRUE;
04b8595b 845 KERNEL_DEBUG_CONSTANT((ATM_CODE(ATM_GETVALUE_INFO, (ATM_VALUE_REPLACED))) | DBG_FUNC_NONE,
0a7de745 846 VM_KERNEL_ADDRPERM(atm_value), atm_value->aid, guard, 0, 0);
fe8ab488
A
847 }
848 }
fe8ab488 849
3e170ce0
A
850 if (element_found) {
851 lck_mtx_unlock(&atm_value->listener_lock);
852 /* Drop the extra reference on task descriptor taken by this function. */
853 atm_task_descriptor_dealloc(task_descriptor);
854 zfree(atm_link_objects_zone, new_link_object);
855 } else {
856 KERNEL_DEBUG_CONSTANT((ATM_CODE(ATM_GETVALUE_INFO, (ATM_VALUE_ADDED))) | DBG_FUNC_NONE,
0a7de745 857 VM_KERNEL_ADDRPERM(atm_value), atm_value->aid, guard, 0, 0);
3e170ce0
A
858
859 queue_enter(&atm_value->listeners, new_link_object, atm_link_object_t, listeners_element);
860 atm_listener_count_incr_internal(atm_value);
861 lck_mtx_unlock(&atm_value->listener_lock);
862 }
863
864 /* Free the link objects */
0a7de745 865 while (!queue_empty(&free_listeners)) {
3e170ce0
A
866 queue_remove_first(&free_listeners, next, atm_link_object_t, listeners_element);
867
868 /* Deallocate the link object */
869 atm_link_dealloc(next);
870 }
871
872 KERNEL_DEBUG_CONSTANT((ATM_CODE(ATM_SUBAID_INFO, (ATM_LINK_LIST_TRIM))) | DBG_FUNC_NONE,
0a7de745 873 listener_count, freed_count, dead_but_not_freed, VM_KERNEL_ADDRPERM(atm_value), 1);
3e170ce0 874
fe8ab488
A
875 return KERN_SUCCESS;
876}
877
878
879/*
880 * Routine: atm_listener_delete_all
881 * Purpose: Deletes all the listeners for an atm value.
882 * Returns: None.
883 */
884static void
885atm_listener_delete_all(atm_value_t atm_value)
886{
887 atm_link_object_t next;
888
0a7de745 889 while (!queue_empty(&atm_value->listeners)) {
fe8ab488
A
890 queue_remove_first(&atm_value->listeners, next, atm_link_object_t, listeners_element);
891
3e170ce0 892 /* Deallocate the link object */
fe8ab488
A
893 atm_link_dealloc(next);
894 }
895}
896
897
898/*
899 * Routine: atm_listener_delete
900 * Purpose: Deletes a listerner for an atm value.
901 * Returns: KERN_SUCCESS on successful unregister.
3e170ce0 902 * KERN_INVALID_VALUE on finding a different guard.
fe8ab488
A
903 * KERN_FAILURE on failure.
904 */
905static kern_return_t
906atm_listener_delete(
907 atm_value_t atm_value,
908 atm_task_descriptor_t task_descriptor,
3e170ce0 909 atm_guard_t guard)
fe8ab488
A
910{
911 queue_head_t free_listeners;
912 atm_link_object_t next, elem;
fe8ab488
A
913 kern_return_t kr = KERN_FAILURE;
914
915 queue_init(&free_listeners);
916
917 lck_mtx_lock(&atm_value->listener_lock);
918
919 next = (atm_link_object_t)(void *) queue_first(&atm_value->listeners);
920 while (!queue_end(&atm_value->listeners, (queue_entry_t)next)) {
921 elem = next;
922 next = (atm_link_object_t)(void *) queue_next(&next->listeners_element);
923
924 if (elem->descriptor == task_descriptor) {
3e170ce0 925 if (elem->guard == guard) {
04b8595b 926 KERNEL_DEBUG_CONSTANT((ATM_CODE(ATM_UNREGISTER_INFO,
0a7de745 927 (ATM_VALUE_UNREGISTERED))) | DBG_FUNC_NONE,
cb323159 928 VM_KERNEL_ADDRPERM(atm_value), atm_value->aid, guard, os_ref_get_count(&elem->reference_count), 0);
3e170ce0 929 elem->guard = 0;
fe8ab488 930 kr = KERN_SUCCESS;
fe8ab488 931 } else {
04b8595b 932 KERNEL_DEBUG_CONSTANT((ATM_CODE(ATM_UNREGISTER_INFO,
0a7de745 933 (ATM_VALUE_DIFF_MAILBOX))) | DBG_FUNC_NONE,
cb323159 934 VM_KERNEL_ADDRPERM(atm_value), atm_value->aid, elem->guard, os_ref_get_count(&elem->reference_count), 0);
fe8ab488 935 kr = KERN_INVALID_VALUE;
fe8ab488 936 }
cb323159 937 if (os_ref_release(&elem->reference_count) == 0) {
3e170ce0
A
938 queue_remove(&atm_value->listeners, elem, atm_link_object_t, listeners_element);
939 queue_enter(&free_listeners, elem, atm_link_object_t, listeners_element);
940 atm_listener_count_decr_internal(atm_value);
941 }
942 break;
fe8ab488
A
943 }
944 }
945 lck_mtx_unlock(&atm_value->listener_lock);
946
0a7de745 947 while (!queue_empty(&free_listeners)) {
fe8ab488 948 queue_remove_first(&free_listeners, next, atm_link_object_t, listeners_element);
0a7de745 949
3e170ce0 950 /* Deallocate the link object */
fe8ab488
A
951 atm_link_dealloc(next);
952 }
953 return kr;
954}
955
956
957/*
958 * Routine: atm_descriptor_alloc_init
959 * Purpose: Allocate an atm task descriptor and initialize it and takes a reference.
960 * Returns: atm task descriptor: On success.
961 * NULL: on error.
962 */
963static atm_task_descriptor_t
964atm_task_descriptor_alloc_init(
0a7de745
A
965 mach_port_t trace_buffer,
966 uint64_t buffer_size,
967 task_t __assert_only task)
fe8ab488
A
968{
969 atm_task_descriptor_t new_task_descriptor;
970
971 new_task_descriptor = (atm_task_descriptor_t) zalloc(atm_descriptors_zone);
972
973 new_task_descriptor->trace_buffer = trace_buffer;
974 new_task_descriptor->trace_buffer_size = buffer_size;
cb323159 975 os_ref_init(&new_task_descriptor->reference_count, NULL);
fe8ab488
A
976 new_task_descriptor->flags = 0;
977 lck_mtx_init(&new_task_descriptor->lock, &atm_lock_grp, &atm_lock_attr);
978
979#if DEVELOPMENT || DEBUG
980 new_task_descriptor->task = task;
981 lck_mtx_lock(&atm_descriptors_list_lock);
982 queue_enter(&atm_descriptors_list, new_task_descriptor, atm_task_descriptor_t, descriptor_elt);
983 lck_mtx_unlock(&atm_descriptors_list_lock);
984#endif
985
986 return new_task_descriptor;
987}
988
989
fe8ab488
A
990/*
991 * Routine: atm_task_descriptor_dealloc
992 * Prupose: Drops the reference on atm descriptor.
993 * Returns: None.
994 */
995static void
996atm_task_descriptor_dealloc(atm_task_descriptor_t task_descriptor)
997{
cb323159 998 if (os_ref_release(&task_descriptor->reference_count) == 0) {
fe8ab488 999#if DEVELOPMENT || DEBUG
cb323159
A
1000 lck_mtx_lock(&atm_descriptors_list_lock);
1001 queue_remove(&atm_descriptors_list, task_descriptor, atm_task_descriptor_t, descriptor_elt);
1002 lck_mtx_unlock(&atm_descriptors_list_lock);
fe8ab488 1003#endif
cb323159
A
1004 /* release the send right for the named memory entry */
1005 ipc_port_release_send(task_descriptor->trace_buffer);
1006 lck_mtx_destroy(&task_descriptor->lock, &atm_lock_grp);
1007 zfree(atm_descriptors_zone, task_descriptor);
1008 }
fe8ab488
A
1009}
1010
1011
1012/*
1013 * Routine: atm_link_dealloc
1014 * Prupose: Drops the reference on link object.
1015 * Returns: None.
1016 */
1017static void
1018atm_link_dealloc(atm_link_object_t link_object)
1019{
fe8ab488
A
1020 /* Drop the reference on atm task descriptor. */
1021 atm_task_descriptor_dealloc(link_object->descriptor);
1022 zfree(atm_link_objects_zone, link_object);
1023}
1024
1025
1026/*
1027 * Routine: atm_register_trace_memory
1028 * Purpose: Registers trace memory for a task.
1029 * Returns: KERN_SUCCESS: on Success.
1030 * KERN_FAILURE: on Error.
1031 */
1032kern_return_t
1033atm_register_trace_memory(
0a7de745
A
1034 task_t task,
1035 uint64_t trace_buffer_address,
1036 uint64_t buffer_size)
fe8ab488
A
1037{
1038 atm_task_descriptor_t task_descriptor;
1039 mach_port_t trace_buffer = MACH_PORT_NULL;
fe8ab488
A
1040 kern_return_t kr = KERN_SUCCESS;
1041
0a7de745 1042 if (disable_atm || (atm_get_diagnostic_config() & ATM_TRACE_DISABLE)) {
fe8ab488 1043 return KERN_NOT_SUPPORTED;
0a7de745 1044 }
fe8ab488 1045
0a7de745 1046 if (task != current_task()) {
fe8ab488 1047 return KERN_INVALID_ARGUMENT;
0a7de745 1048 }
fe8ab488
A
1049
1050 if (task->atm_context != NULL
1051 || (void *)trace_buffer_address == NULL
1052 || buffer_size == 0
1053 || (buffer_size & PAGE_MASK) != 0
3e170ce0 1054 || buffer_size > MAX_TRACE_BUFFER_SIZE) {
fe8ab488
A
1055 return KERN_INVALID_ARGUMENT;
1056 }
1057
1058 vm_map_t map = current_map();
1059 memory_object_size_t mo_size = (memory_object_size_t) buffer_size;
1060 kr = mach_make_memory_entry_64(map,
0a7de745
A
1061 &mo_size,
1062 (mach_vm_offset_t)trace_buffer_address,
1063 VM_PROT_READ,
1064 &trace_buffer,
1065 NULL);
1066 if (kr != KERN_SUCCESS) {
fe8ab488 1067 return kr;
0a7de745 1068 }
fe8ab488 1069
3e170ce0 1070 task_descriptor = atm_task_descriptor_alloc_init(trace_buffer, buffer_size, task);
fe8ab488
A
1071 if (task_descriptor == ATM_TASK_DESCRIPTOR_NULL) {
1072 ipc_port_release_send(trace_buffer);
fe8ab488
A
1073 return KERN_NO_SPACE;
1074 }
1075
1076 task_lock(task);
1077 if (task->atm_context == NULL) {
1078 task->atm_context = task_descriptor;
1079 kr = KERN_SUCCESS;
1080 } else {
1081 kr = KERN_FAILURE;
1082 }
1083 task_unlock(task);
1084
1085 if (kr != KERN_SUCCESS) {
1086 /* undo the mapping and allocations since we failed to hook descriptor to task */
1087 atm_task_descriptor_dealloc(task_descriptor);
1088 }
1089 return KERN_SUCCESS;
1090}
1091
fe8ab488 1092/*
3e170ce0
A
1093 * Routine: atm_set_diagnostic_config
1094 * Purpose: Set global atm_diagnostic_config and update the commpage to reflect
1095 * the new value.
1096 * Returns: Error if ATM is disabled.
fe8ab488 1097 */
3e170ce0
A
1098extern uint32_t atm_diagnostic_config; /* Proxied to commpage for fast user access */
1099kern_return_t
1100atm_set_diagnostic_config(uint32_t diagnostic_config)
fe8ab488 1101{
0a7de745 1102 if (disable_atm) {
3e170ce0 1103 return KERN_NOT_SUPPORTED;
0a7de745 1104 }
fe8ab488 1105
3e170ce0
A
1106 atm_diagnostic_config = diagnostic_config;
1107 commpage_update_atm_diagnostic_config(atm_diagnostic_config);
fe8ab488 1108
3e170ce0 1109 return KERN_SUCCESS;
fe8ab488
A
1110}
1111
1112
1113/*
3e170ce0
A
1114 * Routine: atm_get_diagnostic_config
1115 * Purpose: Get global atm_diagnostic_config.
1116 * Returns: Diagnostic value
fe8ab488 1117 */
3e170ce0
A
1118uint32_t
1119atm_get_diagnostic_config(void)
fe8ab488 1120{
3e170ce0 1121 return atm_diagnostic_config;
fe8ab488
A
1122}
1123
1124
1125/*
1126 * Routine: atm_value_unregister
1127 * Purpose: Unregisters a process from an activity id.
1128 * Returns: KERN_SUCCESS on successful unregister.
3e170ce0 1129 * KERN_INVALID_VALUE on finding a diff guard.
fe8ab488
A
1130 * KERN_FAILURE on failure.
1131 */
1132static kern_return_t
1133atm_value_unregister(
1134 atm_value_t atm_value,
1135 atm_task_descriptor_t task_descriptor,
3e170ce0 1136 atm_guard_t guard)
fe8ab488
A
1137{
1138 kern_return_t kr;
1139
0a7de745 1140 if (task_descriptor == ATM_TASK_DESCRIPTOR_NULL) {
3e170ce0 1141 return KERN_INVALID_TASK;
0a7de745
A
1142 }
1143
3e170ce0 1144 kr = atm_listener_delete(atm_value, task_descriptor, guard);
fe8ab488
A
1145 return kr;
1146}
1147
3e170ce0
A
1148
1149/*
1150 * Routine: atm_value_register
1151 * Purpose: Registers a process for an activity id.
1152 * Returns: KERN_SUCCESS on successful register.
1153 * KERN_INVALID_TASK on finding a null task atm context.
1154 * KERN_FAILURE on failure.
1155 */
1156static kern_return_t
1157atm_value_register(
1158 atm_value_t atm_value,
1159 atm_task_descriptor_t task_descriptor,
1160 atm_guard_t guard)
1161{
1162 kern_return_t kr;
1163
0a7de745 1164 if (task_descriptor == ATM_TASK_DESCRIPTOR_NULL) {
3e170ce0 1165 return KERN_INVALID_TASK;
0a7de745 1166 }
3e170ce0
A
1167
1168 kr = atm_listener_insert(atm_value, task_descriptor, guard);
1169 return kr;
1170}
1171
1172
fe8ab488
A
1173void
1174atm_task_descriptor_destroy(atm_task_descriptor_t task_descriptor)
1175{
1176 /* Mark the task dead in the task descriptor to make task descriptor eligible for cleanup. */
1177 lck_mtx_lock(&task_descriptor->lock);
1178 task_descriptor->flags = ATM_TASK_DEAD;
1179 lck_mtx_unlock(&task_descriptor->lock);
1180
1181 atm_task_descriptor_dealloc(task_descriptor);
1182}