2 * Copyright (c) 2012-2019 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 #include <bank/bank_internal.h>
30 #include <bank/bank_types.h>
31 #include <mach/mach_types.h>
32 #include <mach/kern_return.h>
33 #include <ipc/ipc_port.h>
34 #include <mach/mach_vm.h>
35 #include <mach/vm_map.h>
36 #include <vm/vm_map.h>
37 #include <mach/host_priv.h>
38 #include <mach/host_special_ports.h>
39 #include <kern/host.h>
40 #include <kern/kalloc.h>
41 #include <kern/ledger.h>
42 #include <kern/coalition.h>
43 #include <kern/thread_group.h>
44 #include <sys/kdebug.h>
45 #include <IOKit/IOBSD.h>
46 #include <mach/mach_voucher_attr_control.h>
47 #include <kern/policy_internal.h>
49 static zone_t bank_task_zone
, bank_account_zone
;
50 #define MAX_BANK_TASK (CONFIG_TASK_MAX)
51 #define MAX_BANK_ACCOUNT (CONFIG_TASK_MAX + CONFIG_THREAD_MAX)
53 #define BANK_ELEMENT_TO_HANDLE(x) (CAST_DOWN(bank_handle_t, (x)))
54 #define HANDLE_TO_BANK_ELEMENT(x) (CAST_DOWN(bank_element_t, (x)))
56 /* Need macro since bank_element_t is 4 byte aligned on release kernel and direct type case gives compilation error */
57 #define CAST_TO_BANK_ELEMENT(x) ((bank_element_t)((void *)(x)))
58 #define CAST_TO_BANK_TASK(x) ((bank_task_t)((void *)(x)))
59 #define CAST_TO_BANK_ACCOUNT(x) ((bank_account_t)((void *)(x)))
61 ipc_voucher_attr_control_t bank_voucher_attr_control
; /* communication channel from ATM to voucher system */
63 extern struct persona
*system_persona
, *proxy_system_persona
;
64 uint32_t persona_get_id(struct persona
*persona
);
65 extern int unique_persona
;
67 #if DEVELOPMENT || DEBUG
68 queue_head_t bank_tasks_list
;
69 queue_head_t bank_accounts_list
;
72 static ledger_template_t bank_ledger_template
= NULL
;
73 struct _bank_ledger_indices bank_ledgers
= { .cpu_time
= -1, .energy
= -1 };
75 static bank_task_t
bank_task_alloc_init(task_t task
);
76 static bank_account_t
bank_account_alloc_init(bank_task_t bank_holder
, bank_task_t bank_merchant
,
77 bank_task_t bank_secureoriginator
, bank_task_t bank_proximateprocess
, struct thread_group
* banktg
, uint32_t persona_id
);
78 static bank_task_t
get_bank_task_context(task_t task
, boolean_t initialize
);
79 static void bank_task_dealloc(bank_task_t bank_task
, mach_voucher_attr_value_reference_t sync
);
80 static kern_return_t
bank_account_dealloc_with_sync(bank_account_t bank_account
, mach_voucher_attr_value_reference_t sync
);
81 static void bank_rollup_chit_to_tasks(ledger_t bill
, ledger_t bank_holder_ledger
, ledger_t bank_merchant_ledger
,
82 int bank_holder_pid
, int bank_merchant_pid
);
83 static ledger_t
bank_get_bank_task_ledger_with_ref(bank_task_t bank_task
);
84 static void bank_destroy_bank_task_ledger(bank_task_t bank_task
);
85 static void init_bank_ledgers(void);
86 static boolean_t
bank_task_is_propagate_entitled(task_t t
);
87 static boolean_t
bank_task_is_persona_modify_entitled(task_t t
);
88 static struct thread_group
*bank_get_bank_task_thread_group(bank_task_t bank_task __unused
);
89 static struct thread_group
*bank_get_bank_account_thread_group(bank_account_t bank_account __unused
);
90 static boolean_t
bank_verify_persona_id(uint32_t persona_id
);
92 static lck_spin_t g_bank_task_lock_data
; /* lock to protect task->bank_context transition */
94 static uint32_t disable_persona_propogate_check
= 0;
96 #define global_bank_task_lock_init() \
97 lck_spin_init(&g_bank_task_lock_data, &bank_lock_grp, &bank_lock_attr)
98 #define global_bank_task_lock_destroy() \
99 lck_spin_destroy(&g_bank_task_lock_data, &bank_lock_grp)
100 #define global_bank_task_lock() \
101 lck_spin_lock_grp(&g_bank_task_lock_data, &bank_lock_grp)
102 #define global_bank_task_lock_try() \
103 lck_spin_try_lock_grp(&g_bank_task_lock_data, &bank_lock_grp)
104 #define global_bank_task_unlock() \
105 lck_spin_unlock(&g_bank_task_lock_data)
107 extern uint64_t proc_uniqueid(void *p
);
108 extern int32_t proc_pid(void *p
);
109 extern int32_t proc_pidversion(void *p
);
110 extern uint32_t proc_persona_id(void *p
);
111 extern uint32_t proc_getuid(void *p
);
112 extern uint32_t proc_getgid(void *p
);
113 extern void proc_getexecutableuuid(void *p
, unsigned char *uuidbuf
, unsigned long size
);
114 extern int kauth_cred_issuser(void *cred
);
115 extern void* kauth_cred_get(void);
116 extern void* persona_lookup(uint32_t id
);
117 extern void persona_put(void* persona
);
121 ipc_voucher_attr_manager_t __assert_only manager
,
122 mach_voucher_attr_key_t __assert_only key
,
123 mach_voucher_attr_value_handle_t value
,
124 mach_voucher_attr_value_reference_t sync
);
128 ipc_voucher_attr_manager_t __assert_only manager
,
129 mach_voucher_attr_key_t __assert_only key
,
130 mach_voucher_attr_recipe_command_t command
,
131 mach_voucher_attr_value_handle_array_t prev_values
,
132 mach_msg_type_number_t __assert_only prev_value_count
,
133 mach_voucher_attr_content_t recipe
,
134 mach_voucher_attr_content_size_t recipe_size
,
135 mach_voucher_attr_value_handle_t
*out_value
,
136 mach_voucher_attr_value_flags_t
*out_flags
,
137 ipc_voucher_t
*out_value_voucher
);
140 bank_extract_content(
141 ipc_voucher_attr_manager_t __assert_only manager
,
142 mach_voucher_attr_key_t __assert_only key
,
143 mach_voucher_attr_value_handle_array_t values
,
144 mach_msg_type_number_t value_count
,
145 mach_voucher_attr_recipe_command_t
*out_command
,
146 mach_voucher_attr_content_t out_recipe
,
147 mach_voucher_attr_content_size_t
*in_out_recipe_size
);
151 ipc_voucher_attr_manager_t __assert_only manager
,
152 mach_voucher_attr_key_t __assert_only key
,
153 mach_voucher_attr_value_handle_array_t values
,
154 mach_msg_type_number_t value_count
,
155 mach_voucher_attr_command_t command
,
156 mach_voucher_attr_content_t in_content
,
157 mach_voucher_attr_content_size_t in_content_size
,
158 mach_voucher_attr_content_t out_content
,
159 mach_voucher_attr_content_size_t
*in_out_content_size
);
162 bank_release(ipc_voucher_attr_manager_t __assert_only manager
);
165 * communication channel from voucher system to ATM
167 const struct ipc_voucher_attr_manager bank_manager
= {
168 .ivam_release_value
= bank_release_value
,
169 .ivam_get_value
= bank_get_value
,
170 .ivam_extract_content
= bank_extract_content
,
171 .ivam_command
= bank_command
,
172 .ivam_release
= bank_release
,
173 .ivam_flags
= (IVAM_FLAGS_SUPPORT_SEND_PREPROCESS
| IVAM_FLAGS_SUPPORT_RECEIVE_POSTPROCESS
),
177 #if DEVELOPMENT || DEBUG
178 decl_lck_mtx_data(, bank_tasks_list_lock
);
179 decl_lck_mtx_data(, bank_accounts_list_lock
);
181 lck_grp_t bank_dev_lock_grp
;
182 lck_attr_t bank_dev_lock_attr
;
183 lck_grp_attr_t bank_dev_lock_grp_attr
;
187 * Lock group attributes for bank sub system.
189 lck_grp_t bank_lock_grp
;
190 lck_attr_t bank_lock_attr
;
191 lck_grp_attr_t bank_lock_grp_attr
;
195 * Purpose: Initialize the BANK subsystem.
201 kern_return_t kr
= KERN_SUCCESS
;
202 /* setup zones for bank_task and bank_account objects */
203 bank_task_zone
= zinit(sizeof(struct bank_task
),
204 MAX_BANK_TASK
* sizeof(struct bank_task
),
205 sizeof(struct bank_task
),
208 bank_account_zone
= zinit(sizeof(struct bank_account
),
209 MAX_BANK_ACCOUNT
* sizeof(struct bank_account
),
210 sizeof(struct bank_account
),
215 /* Initialize bank lock group and lock attributes. */
216 lck_grp_attr_setdefault(&bank_lock_grp_attr
);
217 lck_grp_init(&bank_lock_grp
, "bank_lock", &bank_lock_grp_attr
);
218 lck_attr_setdefault(&bank_lock_attr
);
219 global_bank_task_lock_init();
221 #if DEVELOPMENT || DEBUG
222 /* Initialize global bank development lock group and lock attributes. */
223 lck_grp_attr_setdefault(&bank_dev_lock_grp_attr
);
224 lck_grp_init(&bank_dev_lock_grp
, "bank_dev_lock", &bank_dev_lock_grp_attr
);
225 lck_attr_setdefault(&bank_dev_lock_attr
);
227 lck_mtx_init(&bank_tasks_list_lock
, &bank_dev_lock_grp
, &bank_dev_lock_attr
);
228 lck_mtx_init(&bank_accounts_list_lock
, &bank_dev_lock_grp
, &bank_dev_lock_attr
);
230 queue_init(&bank_tasks_list
);
231 queue_init(&bank_accounts_list
);
234 /* Register the bank manager with the Vouchers sub system. */
235 kr
= ipc_register_well_known_mach_voucher_attr_manager(
238 MACH_VOUCHER_ATTR_KEY_BANK
,
239 &bank_voucher_attr_control
);
240 if (kr
!= KERN_SUCCESS
) {
241 panic("BANK subsystem initialization failed");
245 #if DEVELOPMENT || DEBUG
246 uint32_t disable_persona_propogate_check_bootarg
= 0;
247 if (PE_parse_boot_argn("disable_persona_propogate_check", &disable_persona_propogate_check_bootarg
,
248 sizeof(disable_persona_propogate_check_bootarg
))) {
249 disable_persona_propogate_check
= (disable_persona_propogate_check_bootarg
!= 0) ? 1 : 0;
253 kprintf("BANK subsystem is initialized\n");
259 * BANK Resource Manager Routines.
264 * Routine: bank_release_value
265 * Purpose: Release a value, if sync matches the sync count in value.
266 * Returns: KERN_SUCCESS: on Successful deletion.
267 * KERN_FAILURE: if sync value does not matches.
271 ipc_voucher_attr_manager_t __assert_only manager
,
272 mach_voucher_attr_key_t __assert_only key
,
273 mach_voucher_attr_value_handle_t value
,
274 mach_voucher_attr_value_reference_t sync
)
276 bank_task_t bank_task
= BANK_TASK_NULL
;
277 bank_element_t bank_element
= BANK_ELEMENT_NULL
;
278 bank_account_t bank_account
= BANK_ACCOUNT_NULL
;
279 kern_return_t kr
= KERN_SUCCESS
;
281 assert(MACH_VOUCHER_ATTR_KEY_BANK
== key
);
282 assert(manager
== &bank_manager
);
285 bank_element
= HANDLE_TO_BANK_ELEMENT(value
);
286 /* Voucher system should never release the default or persistent value */
287 assert(bank_element
!= BANK_DEFAULT_VALUE
&& bank_element
!= BANK_DEFAULT_TASK_VALUE
);
289 if (bank_element
== BANK_DEFAULT_VALUE
|| bank_element
== BANK_DEFAULT_TASK_VALUE
) {
290 /* Return success for default and default task value */
295 if (bank_element
->be_type
== BANK_TASK
) {
296 bank_task
= CAST_TO_BANK_TASK(bank_element
);
298 /* Checking of the made ref with sync and clearing of voucher ref should be done under a lock */
299 lck_mtx_lock(&bank_task
->bt_acc_to_pay_lock
);
300 if (bank_task
->bt_made
!= sync
) {
301 lck_mtx_unlock(&bank_task
->bt_acc_to_pay_lock
);
305 bank_task_made_release_num(bank_task
, sync
);
306 assert(bank_task
->bt_voucher_ref
== 1);
307 bank_task
->bt_voucher_ref
= 0;
308 lck_mtx_unlock(&bank_task
->bt_acc_to_pay_lock
);
310 bank_task_dealloc(bank_task
, 1);
311 } else if (bank_element
->be_type
== BANK_ACCOUNT
) {
312 bank_account
= CAST_TO_BANK_ACCOUNT(bank_element
);
313 kr
= bank_account_dealloc_with_sync(bank_account
, sync
);
315 panic("Bogus bank type: %d passed in get_value\n", bank_element
->be_type
);
323 * Routine: bank_get_value
325 * This function uses the recipe to create a bank attribute for a voucher.
329 ipc_voucher_attr_manager_t __assert_only manager
,
330 mach_voucher_attr_key_t __assert_only key
,
331 mach_voucher_attr_recipe_command_t command
,
332 mach_voucher_attr_value_handle_array_t prev_values
,
333 mach_msg_type_number_t prev_value_count
,
334 mach_voucher_attr_content_t recipe
,
335 mach_voucher_attr_content_size_t recipe_size
,
336 mach_voucher_attr_value_handle_t
*out_value
,
337 mach_voucher_attr_value_flags_t
*out_flags
,
338 ipc_voucher_t
*out_value_voucher
)
340 bank_task_t bank_holder
= BANK_TASK_NULL
;
341 bank_task_t bank_merchant
= BANK_TASK_NULL
;
342 bank_task_t bank_secureoriginator
= BANK_TASK_NULL
;
343 bank_task_t bank_proximateprocess
= BANK_TASK_NULL
;
344 bank_element_t bank_element
= BANK_ELEMENT_NULL
;
345 bank_account_t bank_account
= BANK_ACCOUNT_NULL
;
346 bank_account_t old_bank_account
= BANK_ACCOUNT_NULL
;
347 mach_voucher_attr_value_handle_t bank_handle
;
349 kern_return_t kr
= KERN_SUCCESS
;
350 mach_msg_type_number_t i
;
351 struct thread_group
*thread_group
= NULL
;
352 struct thread_group
*cur_thread_group
= NULL
;
353 uint32_t persona_id
= proc_persona_id(NULL
);
355 assert(MACH_VOUCHER_ATTR_KEY_BANK
== key
);
356 assert(manager
== &bank_manager
);
358 /* never an out voucher */
359 *out_value_voucher
= IPC_VOUCHER_NULL
;
360 *out_flags
= MACH_VOUCHER_ATTR_VALUE_FLAGS_NONE
;
363 case MACH_VOUCHER_ATTR_BANK_CREATE
:
365 /* It returns the default task value. This value is replaced by
366 * an actual bank task reference, by using a recipe with
367 * MACH_VOUCHER_ATTR_SEND_PREPROCESS command.
369 *out_value
= BANK_ELEMENT_TO_HANDLE(BANK_DEFAULT_TASK_VALUE
);
370 *out_flags
= MACH_VOUCHER_ATTR_VALUE_FLAGS_PERSIST
;
373 case MACH_VOUCHER_ATTR_BANK_MODIFY_PERSONA
:
375 /* It creates a bank account attribute value with a new persona id
376 * and auto-redeems it on behalf of the bank_holder.
378 *out_value
= BANK_ELEMENT_TO_HANDLE(BANK_DEFAULT_VALUE
);
380 for (i
= 0; i
< prev_value_count
; i
++) {
381 bank_handle
= prev_values
[i
];
382 bank_element
= HANDLE_TO_BANK_ELEMENT(bank_handle
);
384 /* Expect a pre-processed attribute value */
385 if (bank_element
== BANK_DEFAULT_VALUE
|| bank_element
== BANK_DEFAULT_TASK_VALUE
) {
389 if (!bank_task_is_persona_modify_entitled(current_task())) {
390 return KERN_NO_ACCESS
;
393 struct persona_modify_info pmi
= {};
394 if (recipe_size
== sizeof(pmi
)) {
395 memcpy((void *)&pmi
, recipe
, sizeof(pmi
));
396 persona_id
= pmi
.persona_id
;
398 return KERN_INVALID_ARGUMENT
;
401 /* Verify if the persona id is valid */
402 if (!bank_verify_persona_id(persona_id
)) {
403 return KERN_INVALID_ARGUMENT
;
406 /* Update the persona id only if the bank element is a bank task.
407 * This ensures that the bank_holder can be trusted.
409 if (bank_element
->be_type
== BANK_TASK
) {
410 bank_holder
= CAST_TO_BANK_TASK(bank_element
);
411 /* Ensure that the requestor validated by userspace matches
414 if (pmi
.unique_pid
!= bank_holder
->bt_unique_pid
) {
415 return KERN_INVALID_CAPABILITY
;
417 bank_merchant
= bank_holder
;
418 bank_secureoriginator
= bank_holder
;
419 bank_proximateprocess
= bank_holder
;
420 thread_group
= bank_get_bank_task_thread_group(bank_holder
);
421 } else if (bank_element
->be_type
== BANK_ACCOUNT
) {
422 return KERN_INVALID_ARGUMENT
;
424 panic("Bogus bank type: %d passed in get_value\n", bank_element
->be_type
);
427 /* Change the persona-id to holder task's persona-id if the task is not spawned in system persona */
428 if (unique_persona
&&
429 bank_merchant
->bt_persona_id
!= persona_get_id(system_persona
) &&
430 bank_merchant
->bt_persona_id
!= persona_get_id(proxy_system_persona
)) {
431 persona_id
= bank_merchant
->bt_persona_id
;
434 if (bank_holder
->bt_persona_id
== persona_id
) {
435 lck_mtx_lock(&bank_holder
->bt_acc_to_pay_lock
);
436 bank_task_made_reference(bank_holder
);
437 if (bank_holder
->bt_voucher_ref
== 0) {
438 /* Take a ref for voucher system, if voucher system does not have a ref */
439 bank_task_reference(bank_holder
);
440 bank_holder
->bt_voucher_ref
= 1;
442 lck_mtx_unlock(&bank_holder
->bt_acc_to_pay_lock
);
444 *out_value
= BANK_ELEMENT_TO_HANDLE(bank_holder
);
448 bank_account
= bank_account_alloc_init(bank_holder
, bank_merchant
,
449 bank_secureoriginator
, bank_proximateprocess
,
450 thread_group
, persona_id
);
451 if (bank_account
== BANK_ACCOUNT_NULL
) {
452 return KERN_RESOURCE_SHORTAGE
;
455 *out_value
= BANK_ELEMENT_TO_HANDLE(bank_account
);
460 case MACH_VOUCHER_ATTR_AUTO_REDEEM
:
462 /* It creates a bank account with the bank_merchant set to the current task.
463 * A bank attribute voucher needs to be redeemed before it can be adopted by
466 for (i
= 0; i
< prev_value_count
; i
++) {
467 bank_handle
= prev_values
[i
];
468 bank_element
= HANDLE_TO_BANK_ELEMENT(bank_handle
);
470 /* Should not have received default task value from an IPC */
471 if (bank_element
== BANK_DEFAULT_VALUE
|| bank_element
== BANK_DEFAULT_TASK_VALUE
) {
475 task
= current_task();
476 if (bank_element
->be_type
== BANK_TASK
) {
477 bank_holder
= CAST_TO_BANK_TASK(bank_element
);
478 bank_secureoriginator
= bank_holder
;
479 bank_proximateprocess
= bank_holder
;
480 thread_group
= bank_get_bank_task_thread_group(bank_holder
);
481 persona_id
= bank_holder
->bt_persona_id
;
482 } else if (bank_element
->be_type
== BANK_ACCOUNT
) {
483 old_bank_account
= CAST_TO_BANK_ACCOUNT(bank_element
);
484 bank_holder
= old_bank_account
->ba_holder
;
485 bank_secureoriginator
= old_bank_account
->ba_secureoriginator
;
486 bank_proximateprocess
= old_bank_account
->ba_proximateprocess
;
487 thread_group
= bank_get_bank_account_thread_group(old_bank_account
);
488 persona_id
= old_bank_account
->ba_so_persona_id
;
490 panic("Bogus bank type: %d passed in get_value\n", bank_element
->be_type
);
493 bank_merchant
= get_bank_task_context(task
, FALSE
);
494 if (bank_merchant
== BANK_TASK_NULL
) {
495 return KERN_RESOURCE_SHORTAGE
;
498 cur_thread_group
= bank_get_bank_task_thread_group(bank_merchant
);
500 /* Change voucher thread group to current thread group for Apps */
501 if (task_is_app(task
)) {
502 thread_group
= cur_thread_group
;
505 /* Change the persona-id to current task persona-id if the task is not spawned in system persona */
506 if (unique_persona
&&
507 bank_merchant
->bt_persona_id
!= persona_get_id(system_persona
) &&
508 bank_merchant
->bt_persona_id
!= persona_get_id(proxy_system_persona
)) {
509 persona_id
= bank_merchant
->bt_persona_id
;
512 /* Check if trying to redeem for self task, return the default bank task */
513 if (bank_holder
== bank_merchant
&&
514 bank_holder
== bank_secureoriginator
&&
515 bank_holder
== bank_proximateprocess
&&
516 thread_group
== cur_thread_group
&&
517 persona_id
== bank_holder
->bt_persona_id
) {
518 *out_value
= BANK_ELEMENT_TO_HANDLE(BANK_DEFAULT_TASK_VALUE
);
519 *out_flags
= MACH_VOUCHER_ATTR_VALUE_FLAGS_PERSIST
;
523 bank_account
= bank_account_alloc_init(bank_holder
, bank_merchant
,
524 bank_secureoriginator
, bank_proximateprocess
,
525 thread_group
, persona_id
);
526 if (bank_account
== BANK_ACCOUNT_NULL
) {
527 return KERN_RESOURCE_SHORTAGE
;
530 *out_value
= BANK_ELEMENT_TO_HANDLE(bank_account
);
534 *out_value
= BANK_ELEMENT_TO_HANDLE(BANK_DEFAULT_VALUE
);
537 case MACH_VOUCHER_ATTR_SEND_PREPROCESS
:
539 for (i
= 0; i
< prev_value_count
; i
++) {
540 bank_handle
= prev_values
[i
];
541 bank_element
= HANDLE_TO_BANK_ELEMENT(bank_handle
);
543 if (bank_element
== BANK_DEFAULT_VALUE
) {
547 task
= current_task();
548 if (bank_element
== BANK_DEFAULT_TASK_VALUE
) {
549 bank_element
= CAST_TO_BANK_ELEMENT(get_bank_task_context(task
, FALSE
));
552 if (bank_element
->be_type
== BANK_TASK
) {
553 bank_holder
= CAST_TO_BANK_TASK(bank_element
);
554 bank_secureoriginator
= bank_holder
;
555 thread_group
= bank_get_bank_task_thread_group(bank_holder
);
556 persona_id
= bank_holder
->bt_persona_id
;
557 } else if (bank_element
->be_type
== BANK_ACCOUNT
) {
558 old_bank_account
= CAST_TO_BANK_ACCOUNT(bank_element
);
559 bank_holder
= old_bank_account
->ba_holder
;
560 bank_secureoriginator
= old_bank_account
->ba_secureoriginator
;
561 thread_group
= bank_get_bank_account_thread_group(old_bank_account
);
562 persona_id
= old_bank_account
->ba_so_persona_id
;
564 panic("Bogus bank type: %d passed in get_value\n", bank_element
->be_type
);
567 bank_merchant
= get_bank_task_context(task
, FALSE
);
568 if (bank_merchant
== BANK_TASK_NULL
) {
569 return KERN_RESOURCE_SHORTAGE
;
572 cur_thread_group
= bank_get_bank_task_thread_group(bank_merchant
);
575 * If the process doesn't have secure persona entitlement,
576 * then replace the secure originator to current task.
577 * Also update the persona_id to match that of the secure originator.
579 if (bank_merchant
->bt_hasentitlement
== 0) {
580 KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE
,
581 (BANK_CODE(BANK_ACCOUNT_INFO
, (BANK_SECURE_ORIGINATOR_CHANGED
))) | DBG_FUNC_NONE
,
582 bank_secureoriginator
->bt_pid
, bank_merchant
->bt_pid
, 0, 0, 0);
583 bank_secureoriginator
= bank_merchant
;
584 persona_id
= bank_merchant
->bt_persona_id
;
587 bank_proximateprocess
= bank_merchant
;
589 /* Check if trying to pre-process for self task, return the bank task */
590 if (bank_holder
== bank_merchant
&&
591 bank_holder
== bank_secureoriginator
&&
592 bank_holder
== bank_proximateprocess
&&
593 thread_group
== cur_thread_group
&&
594 persona_id
== bank_holder
->bt_persona_id
) {
595 lck_mtx_lock(&bank_holder
->bt_acc_to_pay_lock
);
596 bank_task_made_reference(bank_holder
);
597 if (bank_holder
->bt_voucher_ref
== 0) {
598 /* Take a ref for voucher system, if voucher system does not have a ref */
599 bank_task_reference(bank_holder
);
600 bank_holder
->bt_voucher_ref
= 1;
602 lck_mtx_unlock(&bank_holder
->bt_acc_to_pay_lock
);
604 *out_value
= BANK_ELEMENT_TO_HANDLE(bank_holder
);
607 bank_account
= bank_account_alloc_init(bank_holder
, bank_merchant
,
608 bank_secureoriginator
, bank_proximateprocess
,
609 thread_group
, persona_id
);
610 if (bank_account
== BANK_ACCOUNT_NULL
) {
611 return KERN_RESOURCE_SHORTAGE
;
614 *out_value
= BANK_ELEMENT_TO_HANDLE(bank_account
);
618 *out_value
= BANK_ELEMENT_TO_HANDLE(BANK_DEFAULT_VALUE
);
621 case MACH_VOUCHER_ATTR_REDEEM
:
622 /* This command expects that the bank attribute has been auto-redeemed
623 * and returns a reference to that bank account value.
625 for (i
= 0; i
< prev_value_count
; i
++) {
626 bank_handle
= prev_values
[i
];
627 bank_element
= HANDLE_TO_BANK_ELEMENT(bank_handle
);
629 if (bank_element
== BANK_DEFAULT_VALUE
) {
633 if (bank_element
== BANK_DEFAULT_TASK_VALUE
) {
634 *out_value
= BANK_ELEMENT_TO_HANDLE(BANK_DEFAULT_TASK_VALUE
);
635 *out_flags
= MACH_VOUCHER_ATTR_VALUE_FLAGS_PERSIST
;
639 task
= current_task();
640 if (bank_element
->be_type
== BANK_TASK
) {
641 bank_holder
= CAST_TO_BANK_TASK(bank_element
);
642 if (bank_holder
== get_bank_task_context(task
, FALSE
)) {
643 *out_value
= BANK_ELEMENT_TO_HANDLE(BANK_DEFAULT_TASK_VALUE
);
644 *out_flags
= MACH_VOUCHER_ATTR_VALUE_FLAGS_PERSIST
;
646 kr
= KERN_INVALID_CAPABILITY
;
649 } else if (bank_element
->be_type
== BANK_ACCOUNT
) {
650 bank_account
= CAST_TO_BANK_ACCOUNT(bank_element
);
651 bank_merchant
= bank_account
->ba_merchant
;
652 if (bank_merchant
!= get_bank_task_context(task
, FALSE
)) {
653 /* This error can be used to verify if the task can
656 kr
= KERN_INVALID_CAPABILITY
;
659 bank_account_made_reference(bank_account
);
660 *out_value
= BANK_ELEMENT_TO_HANDLE(bank_account
);
663 panic("Bogus bank type: %d passed in get_value\n", bank_element
->be_type
);
667 *out_value
= BANK_ELEMENT_TO_HANDLE(BANK_DEFAULT_VALUE
);
671 kr
= KERN_INVALID_ARGUMENT
;
680 * Routine: bank_extract_content
681 * Purpose: Extract a set of aid from an array of voucher values.
682 * Returns: KERN_SUCCESS: on Success.
683 * KERN_FAILURE: one of the value is not present in the hash.
684 * KERN_NO_SPACE: insufficeint buffer provided to fill an array of aid.
687 bank_extract_content(
688 ipc_voucher_attr_manager_t __assert_only manager
,
689 mach_voucher_attr_key_t __assert_only key
,
690 mach_voucher_attr_value_handle_array_t values
,
691 mach_msg_type_number_t value_count
,
692 mach_voucher_attr_recipe_command_t
*out_command
,
693 mach_voucher_attr_content_t out_recipe
,
694 mach_voucher_attr_content_size_t
*in_out_recipe_size
)
696 bank_task_t bank_task
= BANK_TASK_NULL
;
697 bank_element_t bank_element
= BANK_ELEMENT_NULL
;
698 bank_account_t bank_account
= BANK_ACCOUNT_NULL
;
699 mach_voucher_attr_value_handle_t bank_handle
;
700 char buf
[MACH_VOUCHER_BANK_CONTENT_SIZE
];
701 mach_msg_type_number_t i
;
703 assert(MACH_VOUCHER_ATTR_KEY_BANK
== key
);
704 assert(manager
== &bank_manager
);
706 for (i
= 0; i
< value_count
&& *in_out_recipe_size
> 0; i
++) {
707 bank_handle
= values
[i
];
708 bank_element
= HANDLE_TO_BANK_ELEMENT(bank_handle
);
709 if (bank_element
== BANK_DEFAULT_VALUE
) {
713 if (bank_element
== BANK_DEFAULT_TASK_VALUE
) {
714 bank_element
= CAST_TO_BANK_ELEMENT(get_bank_task_context(current_task(), FALSE
));
717 if (MACH_VOUCHER_BANK_CONTENT_SIZE
> *in_out_recipe_size
) {
718 *in_out_recipe_size
= 0;
719 return KERN_NO_SPACE
;
722 if (bank_element
->be_type
== BANK_TASK
) {
723 bank_task
= CAST_TO_BANK_TASK(bank_element
);
724 snprintf(buf
, MACH_VOUCHER_BANK_CONTENT_SIZE
,
725 " Bank Context for a pid %d\n", bank_task
->bt_pid
);
726 } else if (bank_element
->be_type
== BANK_ACCOUNT
) {
727 bank_account
= CAST_TO_BANK_ACCOUNT(bank_element
);
728 snprintf(buf
, MACH_VOUCHER_BANK_CONTENT_SIZE
,
729 " Bank Account linking holder pid %d with merchant pid %d, originator PID/persona: %d, %u and proximate PID/persona: %d, %u\n",
730 bank_account
->ba_holder
->bt_pid
,
731 bank_account
->ba_merchant
->bt_pid
,
732 bank_account
->ba_secureoriginator
->bt_pid
,
733 bank_account
->ba_so_persona_id
,
734 bank_account
->ba_proximateprocess
->bt_pid
,
735 bank_account
->ba_proximateprocess
->bt_persona_id
);
737 panic("Bogus bank type: %d passed in get_value\n", bank_element
->be_type
);
740 memcpy(&out_recipe
[0], buf
, strlen(buf
) + 1);
741 *out_command
= MACH_VOUCHER_ATTR_BANK_NULL
;
742 *in_out_recipe_size
= (mach_voucher_attr_content_size_t
)strlen(buf
) + 1;
750 * Routine: bank_command
751 * Purpose: Execute a command against a set of bank values.
752 * Returns: KERN_SUCCESS: On successful execution of command.
753 * KERN_FAILURE: On failure.
757 ipc_voucher_attr_manager_t __assert_only manager
,
758 mach_voucher_attr_key_t __assert_only key
,
759 mach_voucher_attr_value_handle_array_t __unused values
,
760 mach_msg_type_number_t __unused value_count
,
761 mach_voucher_attr_command_t __unused command
,
762 mach_voucher_attr_content_t __unused in_content
,
763 mach_voucher_attr_content_size_t __unused in_content_size
,
764 mach_voucher_attr_content_t __unused out_content
,
765 mach_voucher_attr_content_size_t __unused
*out_content_size
)
767 bank_task_t bank_task
= BANK_TASK_NULL
;
768 bank_task_t bank_secureoriginator
= BANK_TASK_NULL
;
769 bank_task_t bank_proximateprocess
= BANK_TASK_NULL
;
770 struct persona_token
*token
= NULL
;
771 bank_element_t bank_element
= BANK_ELEMENT_NULL
;
772 bank_account_t bank_account
= BANK_ACCOUNT_NULL
;
773 mach_voucher_attr_value_handle_t bank_handle
;
774 mach_msg_type_number_t i
;
778 assert(MACH_VOUCHER_ATTR_KEY_BANK
== key
);
779 assert(manager
== &bank_manager
);
782 case BANK_ORIGINATOR_PID
:
784 if ((sizeof(pid
)) > *out_content_size
) {
785 *out_content_size
= 0;
786 return KERN_NO_SPACE
;
789 for (i
= 0; i
< value_count
; i
++) {
790 bank_handle
= values
[i
];
791 bank_element
= HANDLE_TO_BANK_ELEMENT(bank_handle
);
792 if (bank_element
== BANK_DEFAULT_VALUE
) {
796 if (bank_element
== BANK_DEFAULT_TASK_VALUE
) {
797 bank_element
= CAST_TO_BANK_ELEMENT(get_bank_task_context(current_task(), FALSE
));
800 if (bank_element
->be_type
== BANK_TASK
) {
801 bank_task
= CAST_TO_BANK_TASK(bank_element
);
802 } else if (bank_element
->be_type
== BANK_ACCOUNT
) {
803 bank_account
= CAST_TO_BANK_ACCOUNT(bank_element
);
804 bank_task
= bank_account
->ba_holder
;
806 panic("Bogus bank type: %d passed in voucher_command\n", bank_element
->be_type
);
808 pid
= bank_task
->bt_pid
;
810 memcpy(&out_content
[0], &pid
, sizeof(pid
));
811 *out_content_size
= (mach_voucher_attr_content_size_t
)sizeof(pid
);
814 /* In the case of no value, return error KERN_INVALID_VALUE */
815 *out_content_size
= 0;
816 return KERN_INVALID_VALUE
;
818 case BANK_PERSONA_TOKEN
:
820 if ((sizeof(struct persona_token
)) > *out_content_size
) {
821 *out_content_size
= 0;
822 return KERN_NO_SPACE
;
824 for (i
= 0; i
< value_count
; i
++) {
825 bank_handle
= values
[i
];
826 bank_element
= HANDLE_TO_BANK_ELEMENT(bank_handle
);
827 if (bank_element
== BANK_DEFAULT_VALUE
) {
831 if (bank_element
== BANK_DEFAULT_TASK_VALUE
) {
832 bank_element
= CAST_TO_BANK_ELEMENT(get_bank_task_context(current_task(), FALSE
));
835 if (bank_element
->be_type
== BANK_TASK
) {
836 *out_content_size
= 0;
837 return KERN_INVALID_OBJECT
;
838 } else if (bank_element
->be_type
== BANK_ACCOUNT
) {
839 bank_account
= CAST_TO_BANK_ACCOUNT(bank_element
);
840 bank_secureoriginator
= bank_account
->ba_secureoriginator
;
841 bank_proximateprocess
= bank_account
->ba_proximateprocess
;
843 panic("Bogus bank type: %d passed in voucher_command\n", bank_element
->be_type
);
845 token
= (struct persona_token
*)(void *)&out_content
[0];
846 memcpy(&token
->originator
, &bank_secureoriginator
->bt_proc_persona
, sizeof(struct proc_persona_info
));
847 memcpy(&token
->proximate
, &bank_proximateprocess
->bt_proc_persona
, sizeof(struct proc_persona_info
));
849 *out_content_size
= (mach_voucher_attr_content_size_t
)sizeof(*token
);
852 /* In the case of no value, return error KERN_INVALID_VALUE */
853 *out_content_size
= 0;
854 return KERN_INVALID_VALUE
;
856 case BANK_PERSONA_ID
:
858 if ((sizeof(persona_id
)) > *out_content_size
) {
859 *out_content_size
= 0;
860 return KERN_NO_SPACE
;
863 for (i
= 0; i
< value_count
; i
++) {
864 bank_handle
= values
[i
];
865 bank_element
= HANDLE_TO_BANK_ELEMENT(bank_handle
);
866 if (bank_element
== BANK_DEFAULT_VALUE
) {
870 if (bank_element
== BANK_DEFAULT_TASK_VALUE
) {
871 bank_element
= CAST_TO_BANK_ELEMENT(get_bank_task_context(current_task(), FALSE
));
874 if (bank_element
->be_type
== BANK_TASK
) {
875 bank_task
= CAST_TO_BANK_TASK(bank_element
);
876 persona_id
= bank_task
->bt_persona_id
;
877 } else if (bank_element
->be_type
== BANK_ACCOUNT
) {
878 bank_account
= CAST_TO_BANK_ACCOUNT(bank_element
);
879 persona_id
= bank_account
->ba_so_persona_id
;
881 panic("Bogus bank type: %d passed in voucher_command\n", bank_element
->be_type
);
884 memcpy(out_content
, &persona_id
, sizeof(persona_id
));
885 *out_content_size
= (mach_voucher_attr_content_size_t
)sizeof(persona_id
);
888 /* In the case of no value, return error KERN_INVALID_VALUE */
889 *out_content_size
= 0;
890 return KERN_INVALID_VALUE
;
893 return KERN_INVALID_ARGUMENT
;
901 ipc_voucher_attr_manager_t __assert_only manager
)
903 assert(manager
== &bank_manager
);
909 * Bank Internal Routines.
913 * Routine: bank_task_alloc_init
914 * Purpose: Allocate and initialize a bank task structure.
915 * Returns: bank_task_t on Success.
916 * BANK_TASK_NULL: on Failure.
917 * Notes: Leaves the task and ledger blank and has only 1 ref,
918 * needs to take 1 extra ref after the task field is initialized.
921 bank_task_alloc_init(task_t task
)
923 bank_task_t new_bank_task
;
925 new_bank_task
= (bank_task_t
) zalloc(bank_task_zone
);
926 if (new_bank_task
== BANK_TASK_NULL
) {
927 return BANK_TASK_NULL
;
930 new_bank_task
->bt_type
= BANK_TASK
;
931 new_bank_task
->bt_voucher_ref
= 0;
932 new_bank_task
->bt_refs
= 1;
933 new_bank_task
->bt_made
= 0;
934 new_bank_task
->bt_ledger
= LEDGER_NULL
;
935 new_bank_task
->bt_hasentitlement
= bank_task_is_propagate_entitled(task
);
936 queue_init(&new_bank_task
->bt_accounts_to_pay
);
937 queue_init(&new_bank_task
->bt_accounts_to_charge
);
938 lck_mtx_init(&new_bank_task
->bt_acc_to_pay_lock
, &bank_lock_grp
, &bank_lock_attr
);
939 lck_mtx_init(&new_bank_task
->bt_acc_to_charge_lock
, &bank_lock_grp
, &bank_lock_attr
);
942 * Initialize the persona_id struct
944 bzero(&new_bank_task
->bt_proc_persona
, sizeof(new_bank_task
->bt_proc_persona
));
945 new_bank_task
->bt_flags
= 0;
946 new_bank_task
->bt_unique_pid
= proc_uniqueid(task
->bsd_info
);
947 new_bank_task
->bt_pid
= proc_pid(task
->bsd_info
);
948 new_bank_task
->bt_pidversion
= proc_pidversion(task
->bsd_info
);
949 new_bank_task
->bt_persona_id
= proc_persona_id(task
->bsd_info
);
950 new_bank_task
->bt_uid
= proc_getuid(task
->bsd_info
);
951 new_bank_task
->bt_gid
= proc_getgid(task
->bsd_info
);
952 proc_getexecutableuuid(task
->bsd_info
, new_bank_task
->bt_macho_uuid
, sizeof(new_bank_task
->bt_macho_uuid
));
954 #if DEVELOPMENT || DEBUG
955 new_bank_task
->bt_task
= NULL
;
956 lck_mtx_lock(&bank_tasks_list_lock
);
957 queue_enter(&bank_tasks_list
, new_bank_task
, bank_task_t
, bt_global_elt
);
958 lck_mtx_unlock(&bank_tasks_list_lock
);
960 return new_bank_task
;
964 * Routine: proc_is_propagate_entitled
965 * Purpose: Check if the process is allowed to propagate secure originator.
966 * Returns: TRUE if entitled.
970 bank_task_is_propagate_entitled(task_t t
)
972 /* Check if it has an entitlement which disallows secure originator propagation */
973 boolean_t entitled
= FALSE
;
974 entitled
= IOTaskHasEntitlement(t
, ENTITLEMENT_PERSONA_NO_PROPAGATE
);
979 /* If it's a platform binary, allow propogation by default */
980 if (disable_persona_propogate_check
|| (t
->t_flags
& TF_PLATFORM
)) {
988 * Routine: proc_is_persona_modify_entitled
989 * Purpose: Check if the process has persona modify entitlement.
990 * Returns: TRUE if entitled.
994 bank_task_is_persona_modify_entitled(task_t t
)
996 boolean_t entitled
= FALSE
;
997 entitled
= IOTaskHasEntitlement(t
, ENTITLEMENT_PERSONA_MODIFY
);
1002 * Routine: bank_account_alloc_init
1003 * Purpose: Allocate and Initialize the bank account struct.
1004 * Returns: bank_account_t : On Success.
1005 * BANK_ACCOUNT_NULL: On Failure.
1007 static bank_account_t
1008 bank_account_alloc_init(
1009 bank_task_t bank_holder
,
1010 bank_task_t bank_merchant
,
1011 bank_task_t bank_secureoriginator
,
1012 bank_task_t bank_proximateprocess
,
1013 struct thread_group
*thread_group
,
1014 uint32_t persona_id
)
1016 bank_account_t new_bank_account
;
1017 bank_account_t bank_account
;
1018 boolean_t entry_found
= FALSE
;
1019 ledger_t new_ledger
= ledger_instantiate(bank_ledger_template
, LEDGER_CREATE_INACTIVE_ENTRIES
);
1021 if (new_ledger
== LEDGER_NULL
) {
1022 return BANK_ACCOUNT_NULL
;
1025 ledger_entry_setactive(new_ledger
, bank_ledgers
.cpu_time
);
1026 ledger_entry_setactive(new_ledger
, bank_ledgers
.energy
);
1027 new_bank_account
= (bank_account_t
) zalloc(bank_account_zone
);
1028 if (new_bank_account
== BANK_ACCOUNT_NULL
) {
1029 ledger_dereference(new_ledger
);
1030 return BANK_ACCOUNT_NULL
;
1033 new_bank_account
->ba_type
= BANK_ACCOUNT
;
1034 new_bank_account
->ba_voucher_ref
= 0;
1035 new_bank_account
->ba_refs
= 1;
1036 new_bank_account
->ba_made
= 1;
1037 new_bank_account
->ba_bill
= new_ledger
;
1038 new_bank_account
->ba_merchant
= bank_merchant
;
1039 new_bank_account
->ba_holder
= bank_holder
;
1040 new_bank_account
->ba_secureoriginator
= bank_secureoriginator
;
1041 new_bank_account
->ba_proximateprocess
= bank_proximateprocess
;
1042 new_bank_account
->ba_so_persona_id
= persona_id
;
1044 /* Iterate through accounts need to pay list to find the existing entry */
1045 lck_mtx_lock(&bank_holder
->bt_acc_to_pay_lock
);
1046 queue_iterate(&bank_holder
->bt_accounts_to_pay
, bank_account
, bank_account_t
, ba_next_acc_to_pay
) {
1047 if (bank_account
->ba_merchant
!= bank_merchant
||
1048 bank_account
->ba_secureoriginator
!= bank_secureoriginator
||
1049 bank_account
->ba_proximateprocess
!= bank_proximateprocess
||
1050 bank_get_bank_account_thread_group(bank_account
) != thread_group
||
1051 bank_account
->ba_so_persona_id
!= persona_id
) {
1056 /* Take a made ref, since this value would be returned to voucher system. */
1057 bank_account_made_reference(bank_account
);
1062 /* Create a linkage between the holder and the merchant task, Grab both the list locks before adding it to the list. */
1063 lck_mtx_lock(&bank_merchant
->bt_acc_to_charge_lock
);
1065 /* Add the account entry into Accounts need to pay account link list. */
1066 queue_enter(&bank_holder
->bt_accounts_to_pay
, new_bank_account
, bank_account_t
, ba_next_acc_to_pay
);
1068 /* Add the account entry into Accounts need to charge account link list. */
1069 queue_enter(&bank_merchant
->bt_accounts_to_charge
, new_bank_account
, bank_account_t
, ba_next_acc_to_charge
);
1071 lck_mtx_unlock(&bank_merchant
->bt_acc_to_charge_lock
);
1074 lck_mtx_unlock(&bank_holder
->bt_acc_to_pay_lock
);
1077 ledger_dereference(new_ledger
);
1078 zfree(bank_account_zone
, new_bank_account
);
1079 return bank_account
;
1082 bank_task_reference(bank_holder
);
1083 bank_task_reference(bank_merchant
);
1084 bank_task_reference(bank_secureoriginator
);
1085 bank_task_reference(bank_proximateprocess
);
1087 #if DEVELOPMENT || DEBUG
1088 new_bank_account
->ba_task
= NULL
;
1089 lck_mtx_lock(&bank_accounts_list_lock
);
1090 queue_enter(&bank_accounts_list
, new_bank_account
, bank_account_t
, ba_global_elt
);
1091 lck_mtx_unlock(&bank_accounts_list_lock
);
1094 return new_bank_account
;
1098 * Routine: get_bank_task_context
1099 * Purpose: Get the bank context of the given task
1100 * Returns: bank_task_t on Success.
1101 * BANK_TASK_NULL: on Failure.
1102 * Note: Initialize bank context if NULL.
1105 get_bank_task_context
1107 boolean_t initialize
)
1109 bank_task_t bank_task
;
1111 if (task
->bank_context
|| !initialize
) {
1112 assert(task
->bank_context
!= NULL
);
1113 return task
->bank_context
;
1116 bank_task
= bank_task_alloc_init(task
);
1118 /* Grab the task lock and check if we won the race. */
1120 if (task
->bank_context
) {
1122 if (bank_task
!= BANK_TASK_NULL
) {
1123 bank_task_dealloc(bank_task
, 1);
1125 return task
->bank_context
;
1126 } else if (bank_task
== BANK_TASK_NULL
) {
1128 return BANK_TASK_NULL
;
1130 /* We won the race. Take a ref on the ledger and initialize bank task. */
1131 bank_task
->bt_ledger
= task
->ledger
;
1132 #if DEVELOPMENT || DEBUG
1133 bank_task
->bt_task
= task
;
1135 ledger_reference(task
->ledger
);
1137 /* Grab the global bank task lock before setting the bank context on a task */
1138 global_bank_task_lock();
1139 task
->bank_context
= bank_task
;
1140 global_bank_task_unlock();
1148 * Routine: bank_task_dealloc
1149 * Purpose: Drops the reference on bank task.
1154 bank_task_t bank_task
,
1155 mach_voucher_attr_value_reference_t sync
)
1157 assert(bank_task
->bt_refs
>= 0);
1159 if (bank_task_release_num(bank_task
, sync
) > (int)sync
) {
1163 assert(bank_task
->bt_refs
== 0);
1164 assert(queue_empty(&bank_task
->bt_accounts_to_pay
));
1165 assert(queue_empty(&bank_task
->bt_accounts_to_charge
));
1167 assert(!LEDGER_VALID(bank_task
->bt_ledger
));
1168 lck_mtx_destroy(&bank_task
->bt_acc_to_pay_lock
, &bank_lock_grp
);
1169 lck_mtx_destroy(&bank_task
->bt_acc_to_charge_lock
, &bank_lock_grp
);
1172 #if DEVELOPMENT || DEBUG
1173 lck_mtx_lock(&bank_tasks_list_lock
);
1174 queue_remove(&bank_tasks_list
, bank_task
, bank_task_t
, bt_global_elt
);
1175 lck_mtx_unlock(&bank_tasks_list_lock
);
1178 zfree(bank_task_zone
, bank_task
);
1182 * Routine: bank_account_dealloc_with_sync
1183 * Purpose: Drop the reference on bank account if the sync matches.
1184 * Returns: KERN_SUCCESS if sync matches.
1185 * KERN_FAILURE on mismatch.
1187 static kern_return_t
1188 bank_account_dealloc_with_sync(
1189 bank_account_t bank_account
,
1190 mach_voucher_attr_value_reference_t sync
)
1192 bank_task_t bank_holder
= bank_account
->ba_holder
;
1193 bank_task_t bank_merchant
= bank_account
->ba_merchant
;
1194 bank_task_t bank_secureoriginator
= bank_account
->ba_secureoriginator
;
1195 bank_task_t bank_proximateprocess
= bank_account
->ba_proximateprocess
;
1196 ledger_t bank_merchant_ledger
= LEDGER_NULL
;
1199 * Grab a reference on the bank_merchant_ledger, since we would not be able
1200 * to take bt_acc_to_pay_lock for bank_merchant later.
1202 bank_merchant_ledger
= bank_get_bank_task_ledger_with_ref(bank_merchant
);
1204 /* Grab the acc to pay list lock and check the sync value */
1205 lck_mtx_lock(&bank_holder
->bt_acc_to_pay_lock
);
1207 if (bank_account
->ba_made
!= sync
) {
1208 lck_mtx_unlock(&bank_holder
->bt_acc_to_pay_lock
);
1209 if (bank_merchant_ledger
) {
1210 ledger_dereference(bank_merchant_ledger
);
1212 return KERN_FAILURE
;
1215 bank_account_made_release_num(bank_account
, sync
);
1217 if (bank_account_release_num(bank_account
, 1) > 1) {
1218 panic("Releasing a non zero ref bank account %p\n", bank_account
);
1222 /* Grab both the acc to pay and acc to charge locks */
1223 lck_mtx_lock(&bank_merchant
->bt_acc_to_charge_lock
);
1225 /* No need to take ledger reference for bank_holder ledger since bt_acc_to_pay_lock is locked */
1226 bank_rollup_chit_to_tasks(bank_account
->ba_bill
, bank_holder
->bt_ledger
, bank_merchant_ledger
,
1227 bank_holder
->bt_pid
, bank_merchant
->bt_pid
);
1229 /* Remove the account entry from Accounts need to pay account link list. */
1230 queue_remove(&bank_holder
->bt_accounts_to_pay
, bank_account
, bank_account_t
, ba_next_acc_to_pay
);
1232 /* Remove the account entry from Accounts need to charge account link list. */
1233 queue_remove(&bank_merchant
->bt_accounts_to_charge
, bank_account
, bank_account_t
, ba_next_acc_to_charge
);
1235 lck_mtx_unlock(&bank_merchant
->bt_acc_to_charge_lock
);
1236 lck_mtx_unlock(&bank_holder
->bt_acc_to_pay_lock
);
1238 if (bank_merchant_ledger
) {
1239 ledger_dereference(bank_merchant_ledger
);
1241 ledger_dereference(bank_account
->ba_bill
);
1243 /* Drop the reference of bank holder and merchant */
1244 bank_task_dealloc(bank_holder
, 1);
1245 bank_task_dealloc(bank_merchant
, 1);
1246 bank_task_dealloc(bank_secureoriginator
, 1);
1247 bank_task_dealloc(bank_proximateprocess
, 1);
1249 #if DEVELOPMENT || DEBUG
1250 lck_mtx_lock(&bank_accounts_list_lock
);
1251 queue_remove(&bank_accounts_list
, bank_account
, bank_account_t
, ba_global_elt
);
1252 lck_mtx_unlock(&bank_accounts_list_lock
);
1255 zfree(bank_account_zone
, bank_account
);
1256 return KERN_SUCCESS
;
1260 * Routine: bank_rollup_chit_to_tasks
1261 * Purpose: Debit and Credit holder's and merchant's ledgers.
1265 bank_rollup_chit_to_tasks(
1267 ledger_t bank_holder_ledger
,
1268 ledger_t bank_merchant_ledger
,
1269 int bank_holder_pid
,
1270 int bank_merchant_pid
)
1272 ledger_amount_t credit
;
1273 ledger_amount_t debit
;
1276 if (bank_holder_ledger
== bank_merchant_ledger
) {
1280 ret
= ledger_get_entries(bill
, bank_ledgers
.cpu_time
, &credit
, &debit
);
1281 if (ret
== KERN_SUCCESS
) {
1282 KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE
,
1283 (BANK_CODE(BANK_ACCOUNT_INFO
, (BANK_SETTLE_CPU_TIME
))) | DBG_FUNC_NONE
,
1284 bank_merchant_pid
, bank_holder_pid
, credit
, debit
, 0);
1286 if (bank_holder_ledger
) {
1287 ledger_credit(bank_holder_ledger
, task_ledgers
.cpu_time_billed_to_me
, credit
);
1288 ledger_debit(bank_holder_ledger
, task_ledgers
.cpu_time_billed_to_me
, debit
);
1291 if (bank_merchant_ledger
) {
1292 ledger_credit(bank_merchant_ledger
, task_ledgers
.cpu_time_billed_to_others
, credit
);
1293 ledger_debit(bank_merchant_ledger
, task_ledgers
.cpu_time_billed_to_others
, debit
);
1297 ret
= ledger_get_entries(bill
, bank_ledgers
.energy
, &credit
, &debit
);
1298 if (ret
== KERN_SUCCESS
) {
1299 KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE
,
1300 (BANK_CODE(BANK_ACCOUNT_INFO
, (BANK_SETTLE_ENERGY
))) | DBG_FUNC_NONE
,
1301 bank_merchant_pid
, bank_holder_pid
, credit
, debit
, 0);
1303 if (bank_holder_ledger
) {
1304 ledger_credit(bank_holder_ledger
, task_ledgers
.energy_billed_to_me
, credit
);
1305 ledger_debit(bank_holder_ledger
, task_ledgers
.energy_billed_to_me
, debit
);
1308 if (bank_merchant_ledger
) {
1309 ledger_credit(bank_merchant_ledger
, task_ledgers
.energy_billed_to_others
, credit
);
1310 ledger_debit(bank_merchant_ledger
, task_ledgers
.energy_billed_to_others
, debit
);
1318 * Routine: bank_task_destroy
1319 * Purpose: Drops reference on bank task.
1323 bank_task_destroy(task_t task
)
1325 bank_task_t bank_task
;
1327 /* Grab the global bank task lock before dropping the ref on task bank context */
1328 global_bank_task_lock();
1329 bank_task
= task
->bank_context
;
1330 task
->bank_context
= NULL
;
1331 global_bank_task_unlock();
1333 bank_destroy_bank_task_ledger(bank_task
);
1334 bank_task_dealloc(bank_task
, 1);
1338 * Routine: bank_task_initialize
1339 * Purpose: Initialize the bank context of a task.
1343 bank_task_initialize(task_t task
)
1345 get_bank_task_context(task
, TRUE
);
1349 * Routine: init_bank_ledgers
1350 * Purpose: Initialize template for bank ledgers.
1354 init_bank_ledgers(void)
1356 ledger_template_t t
;
1359 assert(bank_ledger_template
== NULL
);
1361 if ((t
= ledger_template_create("Bank ledger")) == NULL
) {
1362 panic("couldn't create bank ledger template");
1365 if ((idx
= ledger_entry_add(t
, "cpu_time", "sched", "ns")) < 0) {
1366 panic("couldn't create cpu_time entry for bank ledger template");
1368 bank_ledgers
.cpu_time
= idx
;
1370 if ((idx
= ledger_entry_add(t
, "energy", "power", "nj")) < 0) {
1371 panic("couldn't create energy entry for bank ledger template");
1373 bank_ledgers
.energy
= idx
;
1375 ledger_template_complete(t
);
1376 bank_ledger_template
= t
;
1379 /* Routine: bank_billed_balance_safe
1380 * Purpose: Walk through all the bank accounts billed to me by other tasks and get the current billing balance.
1381 * Called from another task. It takes global bank task lock to make sure the bank context is
1382 * not deallocated while accesing it.
1383 * Returns: cpu balance and energy balance in out paremeters.
1386 bank_billed_balance_safe(task_t task
, uint64_t *cpu_time
, uint64_t *energy
)
1388 bank_task_t bank_task
= BANK_TASK_NULL
;
1389 ledger_amount_t credit
, debit
;
1390 uint64_t cpu_balance
= 0;
1391 uint64_t energy_balance
= 0;
1394 /* Task might be in exec, grab the global bank task lock before accessing bank context. */
1395 global_bank_task_lock();
1396 /* Grab a reference on bank context */
1397 if (task
->bank_context
!= NULL
) {
1398 bank_task
= task
->bank_context
;
1399 bank_task_reference(bank_task
);
1401 global_bank_task_unlock();
1404 bank_billed_balance(bank_task
, &cpu_balance
, &energy_balance
);
1405 bank_task_dealloc(bank_task
, 1);
1407 kr
= ledger_get_entries(task
->ledger
, task_ledgers
.cpu_time_billed_to_me
,
1409 if (kr
== KERN_SUCCESS
) {
1410 cpu_balance
= credit
- debit
;
1412 kr
= ledger_get_entries(task
->ledger
, task_ledgers
.energy_billed_to_me
,
1414 if (kr
== KERN_SUCCESS
) {
1415 energy_balance
= credit
- debit
;
1419 *cpu_time
= cpu_balance
;
1420 *energy
= energy_balance
;
1425 * Routine: bank_billed_time
1426 * Purpose: Walk through the Accounts need to pay account list and get the current billing balance.
1427 * Returns: cpu balance and energy balance in out paremeters.
1430 bank_billed_balance(bank_task_t bank_task
, uint64_t *cpu_time
, uint64_t *energy
)
1432 int64_t cpu_balance
= 0;
1433 int64_t energy_balance
= 0;
1434 bank_account_t bank_account
;
1437 if (bank_task
== BANK_TASK_NULL
) {
1443 lck_mtx_lock(&bank_task
->bt_acc_to_pay_lock
);
1445 /* bt_acc_to_pay_lock locked, no need to take ledger reference for bt_ledger */
1446 if (bank_task
->bt_ledger
!= LEDGER_NULL
) {
1447 kr
= ledger_get_balance(bank_task
->bt_ledger
, task_ledgers
.cpu_time_billed_to_me
, &temp
);
1448 if (kr
== KERN_SUCCESS
&& temp
>= 0) {
1449 cpu_balance
+= temp
;
1451 #if DEVELOPMENT || DEBUG
1453 printf("bank_bill_time: ledger_get_balance failed or negative balance in ledger: %lld\n", temp
);
1455 #endif /* DEVELOPMENT || DEBUG */
1457 kr
= ledger_get_balance(bank_task
->bt_ledger
, task_ledgers
.energy_billed_to_me
, &temp
);
1458 if (kr
== KERN_SUCCESS
&& temp
>= 0) {
1459 energy_balance
+= temp
;
1463 queue_iterate(&bank_task
->bt_accounts_to_pay
, bank_account
, bank_account_t
, ba_next_acc_to_pay
) {
1465 kr
= ledger_get_balance(bank_account
->ba_bill
, bank_ledgers
.cpu_time
, &temp
);
1466 if (kr
== KERN_SUCCESS
&& temp
>= 0) {
1467 cpu_balance
+= temp
;
1469 #if DEVELOPMENT || DEBUG
1471 printf("bank_bill_time: ledger_get_balance failed or negative balance in ledger: %lld\n", temp
);
1473 #endif /* DEVELOPMENT || DEBUG */
1475 kr
= ledger_get_balance(bank_account
->ba_bill
, bank_ledgers
.energy
, &temp
);
1476 if (kr
== KERN_SUCCESS
&& temp
>= 0) {
1477 energy_balance
+= temp
;
1480 lck_mtx_unlock(&bank_task
->bt_acc_to_pay_lock
);
1481 *cpu_time
= (uint64_t)cpu_balance
;
1482 *energy
= (uint64_t)energy_balance
;
1486 /* Routine: bank_serviced_balance_safe
1487 * Purpose: Walk through the bank accounts billed to other tasks by me and get the current balance to be charged.
1488 * Called from another task. It takes global bank task lock to make sure the bank context is
1489 * not deallocated while accesing it.
1490 * Returns: cpu balance and energy balance in out paremeters.
1493 bank_serviced_balance_safe(task_t task
, uint64_t *cpu_time
, uint64_t *energy
)
1495 bank_task_t bank_task
= BANK_TASK_NULL
;
1496 ledger_amount_t credit
, debit
;
1497 uint64_t cpu_balance
= 0;
1498 uint64_t energy_balance
= 0;
1501 /* Task might be in exec, grab the global bank task lock before accessing bank context. */
1502 global_bank_task_lock();
1503 /* Grab a reference on bank context */
1504 if (task
->bank_context
!= NULL
) {
1505 bank_task
= task
->bank_context
;
1506 bank_task_reference(bank_task
);
1508 global_bank_task_unlock();
1511 bank_serviced_balance(bank_task
, &cpu_balance
, &energy_balance
);
1512 bank_task_dealloc(bank_task
, 1);
1514 kr
= ledger_get_entries(task
->ledger
, task_ledgers
.cpu_time_billed_to_others
,
1516 if (kr
== KERN_SUCCESS
) {
1517 cpu_balance
= credit
- debit
;
1520 kr
= ledger_get_entries(task
->ledger
, task_ledgers
.energy_billed_to_others
,
1522 if (kr
== KERN_SUCCESS
) {
1523 energy_balance
= credit
- debit
;
1527 *cpu_time
= cpu_balance
;
1528 *energy
= energy_balance
;
1533 * Routine: bank_serviced_balance
1534 * Purpose: Walk through the Account need to charge account list and get the current balance to be charged.
1535 * Returns: cpu balance and energy balance in out paremeters.
1538 bank_serviced_balance(bank_task_t bank_task
, uint64_t *cpu_time
, uint64_t *energy
)
1540 int64_t cpu_balance
= 0;
1541 int64_t energy_balance
= 0;
1542 bank_account_t bank_account
;
1545 ledger_t ledger
= LEDGER_NULL
;
1546 if (bank_task
== BANK_TASK_NULL
) {
1552 /* Grab a ledger reference on bt_ledger for bank_task */
1553 ledger
= bank_get_bank_task_ledger_with_ref(bank_task
);
1555 lck_mtx_lock(&bank_task
->bt_acc_to_charge_lock
);
1558 kr
= ledger_get_balance(ledger
, task_ledgers
.cpu_time_billed_to_others
, &temp
);
1559 if (kr
== KERN_SUCCESS
&& temp
>= 0) {
1560 cpu_balance
+= temp
;
1562 #if DEVELOPMENT || DEBUG
1564 printf("bank_serviced_time: ledger_get_balance failed or negative balance in ledger: %lld\n", temp
);
1566 #endif /* DEVELOPMENT || DEBUG */
1568 kr
= ledger_get_balance(ledger
, task_ledgers
.energy_billed_to_others
, &temp
);
1569 if (kr
== KERN_SUCCESS
&& temp
>= 0) {
1570 energy_balance
+= temp
;
1574 queue_iterate(&bank_task
->bt_accounts_to_charge
, bank_account
, bank_account_t
, ba_next_acc_to_charge
) {
1576 kr
= ledger_get_balance(bank_account
->ba_bill
, bank_ledgers
.cpu_time
, &temp
);
1577 if (kr
== KERN_SUCCESS
&& temp
>= 0) {
1578 cpu_balance
+= temp
;
1580 #if DEVELOPMENT || DEBUG
1582 printf("bank_serviced_time: ledger_get_balance failed or negative balance in ledger: %lld\n", temp
);
1584 #endif /* DEVELOPMENT || DEBUG */
1586 kr
= ledger_get_balance(bank_account
->ba_bill
, bank_ledgers
.energy
, &temp
);
1587 if (kr
== KERN_SUCCESS
&& temp
>= 0) {
1588 energy_balance
+= temp
;
1591 lck_mtx_unlock(&bank_task
->bt_acc_to_charge_lock
);
1593 ledger_dereference(ledger
);
1595 *cpu_time
= (uint64_t)cpu_balance
;
1596 *energy
= (uint64_t)energy_balance
;
1601 * Routine: bank_get_voucher_bank_account
1602 * Purpose: Get the bank account from the voucher.
1603 * Returns: bank_account if bank_account attribute present in voucher.
1604 * NULL on no attribute or no bank_element
1606 static bank_account_t
1607 bank_get_voucher_bank_account(ipc_voucher_t voucher
)
1609 bank_element_t bank_element
= BANK_ELEMENT_NULL
;
1610 bank_account_t bank_account
= BANK_ACCOUNT_NULL
;
1611 mach_voucher_attr_value_handle_t vals
[MACH_VOUCHER_ATTR_VALUE_MAX_NESTED
];
1612 mach_voucher_attr_value_handle_array_size_t val_count
;
1615 val_count
= MACH_VOUCHER_ATTR_VALUE_MAX_NESTED
;
1616 kr
= mach_voucher_attr_control_get_values(bank_voucher_attr_control
,
1621 if (kr
!= KERN_SUCCESS
|| val_count
== 0) {
1622 return BANK_ACCOUNT_NULL
;
1625 bank_element
= HANDLE_TO_BANK_ELEMENT(vals
[0]);
1626 if (bank_element
== BANK_DEFAULT_VALUE
) {
1627 return BANK_ACCOUNT_NULL
;
1629 if (bank_element
== BANK_DEFAULT_TASK_VALUE
) {
1630 bank_element
= CAST_TO_BANK_ELEMENT(get_bank_task_context(current_task(), FALSE
));
1633 if (bank_element
->be_type
== BANK_TASK
) {
1634 return BANK_ACCOUNT_NULL
;
1635 } else if (bank_element
->be_type
== BANK_ACCOUNT
) {
1636 bank_account
= CAST_TO_BANK_ACCOUNT(bank_element
);
1637 return bank_account
;
1639 panic("Bogus bank type: %d passed in bank_get_voucher_bank_account\n", bank_element
->be_type
);
1641 return BANK_ACCOUNT_NULL
;
1645 * Routine: bank_get_bank_task_ledger_with_ref
1646 * Purpose: Get the bank ledger from the bank task and return a reference to it.
1649 bank_get_bank_task_ledger_with_ref(bank_task_t bank_task
)
1651 ledger_t ledger
= LEDGER_NULL
;
1653 lck_mtx_lock(&bank_task
->bt_acc_to_pay_lock
);
1654 ledger
= bank_task
->bt_ledger
;
1656 ledger_reference(ledger
);
1658 lck_mtx_unlock(&bank_task
->bt_acc_to_pay_lock
);
1664 * Routine: bank_destroy_bank_task_ledger
1665 * Purpose: Drop the bank task reference on the task ledger.
1668 bank_destroy_bank_task_ledger(bank_task_t bank_task
)
1672 /* Remove the ledger reference from the bank task */
1673 lck_mtx_lock(&bank_task
->bt_acc_to_pay_lock
);
1674 assert(LEDGER_VALID(bank_task
->bt_ledger
));
1675 ledger
= bank_task
->bt_ledger
;
1676 bank_task
->bt_ledger
= LEDGER_NULL
;
1677 lck_mtx_unlock(&bank_task
->bt_acc_to_pay_lock
);
1679 ledger_dereference(ledger
);
1683 * Routine: bank_get_bank_account_ledger
1684 * Purpose: Get the bankledger from the bank account if ba_merchant different than ba_holder
1687 bank_get_bank_account_ledger(bank_account_t bank_account
)
1689 ledger_t bankledger
= LEDGER_NULL
;
1691 if (bank_account
!= BANK_ACCOUNT_NULL
&&
1692 bank_account
->ba_holder
!= bank_account
->ba_merchant
) {
1693 bankledger
= bank_account
->ba_bill
;
1700 * Routine: bank_get_bank_task_thread_group
1701 * Purpose: Get the bank task's thread group from the bank task
1703 static struct thread_group
*
1704 bank_get_bank_task_thread_group(bank_task_t bank_task __unused
)
1706 struct thread_group
*banktg
= NULL
;
1713 * Routine: bank_get_bank_account_thread_group
1714 * Purpose: Get the bank account's thread group from the bank account
1716 static struct thread_group
*
1717 bank_get_bank_account_thread_group(bank_account_t bank_account __unused
)
1719 struct thread_group
*banktg
= NULL
;
1726 * Routine: bank_get_bank_ledger_thread_group_and_persona
1727 * Purpose: Get the bankledger (chit), thread group and persona id from the voucher.
1728 * Returns: bankledger, thread group if bank_account attribute present in voucher
1732 bank_get_bank_ledger_thread_group_and_persona(
1733 ipc_voucher_t voucher
,
1734 ledger_t
*bankledger
,
1735 struct thread_group
**banktg
,
1736 uint32_t *persona_id
)
1738 bank_account_t bank_account
;
1739 bank_task_t bank_task
;
1740 struct thread_group
*thread_group
= NULL
;
1742 bank_account
= bank_get_voucher_bank_account(voucher
);
1743 bank_task
= get_bank_task_context(current_task(), FALSE
);
1744 if (persona_id
!= NULL
) {
1745 if (bank_account
!= BANK_ACCOUNT_NULL
) {
1746 *persona_id
= bank_account
->ba_so_persona_id
;
1748 *persona_id
= bank_task
->bt_persona_id
;
1752 * Use BANK_ACCOUNT_NULL if the ba_holder is same as ba_merchant
1753 * and bank account thread group is same as current thread group
1754 * i.e. ba_merchant's thread group.
1756 * The bank account might have ba_holder same as ba_merchant but different
1757 * thread group if daemon sends a voucher to an App and then App sends the
1758 * same voucher back to the daemon (IPC code will replace thread group in the
1759 * voucher to App's thread group when it gets auto redeemed by the App).
1761 if ((bank_account
!= NULL
) &&
1762 (bank_account
->ba_holder
== bank_account
->ba_merchant
) &&
1763 (bank_get_bank_account_thread_group(bank_account
) ==
1764 bank_get_bank_task_thread_group(bank_account
->ba_merchant
))) {
1765 bank_account
= BANK_ACCOUNT_NULL
;
1768 if (bankledger
!= NULL
) {
1769 *bankledger
= bank_get_bank_account_ledger(bank_account
);
1772 if (banktg
!= NULL
) {
1773 thread_group
= bank_get_bank_account_thread_group(bank_account
);
1775 /* Return NULL thread group if voucher has current task's thread group */
1776 if (thread_group
== bank_get_bank_task_thread_group(bank_task
)) {
1777 thread_group
= NULL
;
1779 *banktg
= thread_group
;
1781 return KERN_SUCCESS
;
1785 * Routine: bank_swap_thread_bank_ledger
1786 * Purpose: swap the bank ledger on the thread.
1788 * Note: Should be only called for current thread or thread which is not started.
1791 bank_swap_thread_bank_ledger(thread_t thread __unused
, ledger_t new_ledger __unused
)
1794 processor_t processor
;
1795 ledger_t old_ledger
= thread
->t_bankledger
;
1796 int64_t ctime
, effective_ledger_time_consumed
= 0;
1797 int64_t remainder
= 0, consumed
= 0;
1798 int64_t effective_energy_consumed
= 0;
1799 uint64_t thread_energy
;
1801 if (old_ledger
== LEDGER_NULL
&& new_ledger
== LEDGER_NULL
) {
1805 assert((thread
== current_thread() || thread
->started
== 0));
1808 thread_lock(thread
);
1811 * Calculation of time elapsed by the thread before voucher swap.
1812 * Following is the timeline which shows all the variables used in the calculation below.
1816 * |<- consumed ->|<- remainder ->|
1817 * timeline ----------------------------------------------------------------->
1819 * thread_dispatch ctime quantum end
1821 * |<-effective_ledger_time -> |
1822 * deduct_bank_ledger_time
1825 ctime
= mach_absolute_time();
1826 processor
= thread
->last_processor
;
1827 if (processor
!= NULL
) {
1828 if ((int64_t)processor
->quantum_end
> ctime
) {
1829 remainder
= (int64_t)processor
->quantum_end
- ctime
;
1832 consumed
= thread
->quantum_remaining
- remainder
;
1833 effective_ledger_time_consumed
= consumed
- thread
->t_deduct_bank_ledger_time
;
1836 thread
->t_deduct_bank_ledger_time
= consumed
;
1838 thread_energy
= ml_energy_stat(thread
);
1839 effective_energy_consumed
=
1840 thread_energy
- thread
->t_deduct_bank_ledger_energy
;
1841 assert(effective_energy_consumed
>= 0);
1842 thread
->t_deduct_bank_ledger_energy
= thread_energy
;
1844 thread
->t_bankledger
= new_ledger
;
1846 thread_unlock(thread
);
1849 if (old_ledger
!= LEDGER_NULL
) {
1850 ledger_credit(old_ledger
,
1851 bank_ledgers
.cpu_time
,
1852 effective_ledger_time_consumed
);
1853 ledger_credit(old_ledger
,
1854 bank_ledgers
.energy
,
1855 effective_energy_consumed
);
1860 * Routine: bank_verify_persona_id
1861 * Purpose: Verifies if the persona id is valid
1863 * The caller should check if the task is entitled
1867 bank_verify_persona_id(uint32_t persona_id
)
1869 /* A successful lookup implies that the persona id is valid */
1870 void *persona
= persona_lookup(persona_id
);
1874 persona_put(persona
);