]> git.saurik.com Git - apple/xnu.git/blob - osfmk/voucher/ipc_pthread_priority.c
baf70d7bada7f191cdb1ecb402dcb856c1d002d8
[apple/xnu.git] / osfmk / voucher / ipc_pthread_priority.c
1 /*
2 * Copyright (c) 2012-2016 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 <voucher/ipc_pthread_priority_types.h>
30 #include <voucher/ipc_pthread_priority_internal.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 <sys/kdebug.h>
43 #include <IOKit/IOBSD.h>
44 #include <mach/mach_voucher_attr_control.h>
45
46 ipc_voucher_attr_control_t ipc_pthread_priority_voucher_attr_control; /* communication channel from PTHPRIORITY to voucher system */
47
48 #define IPC_PTHREAD_PRIORITY_VALUE_TO_HANDLE(x) ((mach_voucher_attr_value_handle_t)(x))
49 #define HANDLE_TO_IPC_PTHREAD_PRIORITY_VALUE(x) ((ipc_pthread_priority_value_t)(x))
50
51 extern unsigned long pthread_priority_canonicalize(unsigned long priority, boolean_t for_propagation);
52
53 kern_return_t
54 ipc_pthread_priority_release_value(
55 ipc_voucher_attr_manager_t __assert_only manager,
56 mach_voucher_attr_key_t __assert_only key,
57 mach_voucher_attr_value_handle_t value,
58 mach_voucher_attr_value_reference_t sync);
59
60 kern_return_t
61 ipc_pthread_priority_get_value(
62 ipc_voucher_attr_manager_t __assert_only manager,
63 mach_voucher_attr_key_t __assert_only key,
64 mach_voucher_attr_recipe_command_t command,
65 mach_voucher_attr_value_handle_array_t prev_values,
66 mach_msg_type_number_t __assert_only prev_value_count,
67 mach_voucher_attr_content_t recipe,
68 mach_voucher_attr_content_size_t recipe_size,
69 mach_voucher_attr_value_handle_t *out_value,
70 mach_voucher_attr_value_flags_t *out_flags,
71 ipc_voucher_t *out_value_voucher);
72
73 kern_return_t
74 ipc_pthread_priority_extract_content(
75 ipc_voucher_attr_manager_t __assert_only manager,
76 mach_voucher_attr_key_t __assert_only key,
77 mach_voucher_attr_value_handle_array_t values,
78 mach_msg_type_number_t value_count,
79 mach_voucher_attr_recipe_command_t *out_command,
80 mach_voucher_attr_content_t out_recipe,
81 mach_voucher_attr_content_size_t *in_out_recipe_size);
82
83 kern_return_t
84 ipc_pthread_priority_command(
85 ipc_voucher_attr_manager_t __assert_only manager,
86 mach_voucher_attr_key_t __assert_only key,
87 mach_voucher_attr_value_handle_array_t values,
88 mach_msg_type_number_t value_count,
89 mach_voucher_attr_command_t command,
90 mach_voucher_attr_content_t in_content,
91 mach_voucher_attr_content_size_t in_content_size,
92 mach_voucher_attr_content_t out_content,
93 mach_voucher_attr_content_size_t *in_out_content_size);
94
95 void
96 ipc_pthread_priority_release(ipc_voucher_attr_manager_t __assert_only manager);
97
98 /*
99 * communication channel from voucher system to IPC_PTHREAD_PRIORITY
100 */
101 struct ipc_voucher_attr_manager ipc_pthread_priority_manager = {
102 .ivam_release_value = ipc_pthread_priority_release_value,
103 .ivam_get_value = ipc_pthread_priority_get_value,
104 .ivam_extract_content = ipc_pthread_priority_extract_content,
105 .ivam_command = ipc_pthread_priority_command,
106 .ivam_release = ipc_pthread_priority_release,
107 .ivam_flags = IVAM_FLAGS_NONE,
108 };
109
110 /*
111 * Routine: ipc_pthread_priority_init
112 * Purpose: Initialize the IPC_PTHREAD_PRIORITY subsystem.
113 * Returns: None.
114 */
115 void
116 ipc_pthread_priority_init()
117 {
118 kern_return_t kr = KERN_SUCCESS;
119
120 /* Register the ipc_pthread_priority manager with the Vouchers sub system. */
121 kr = ipc_register_well_known_mach_voucher_attr_manager(
122 &ipc_pthread_priority_manager,
123 0,
124 MACH_VOUCHER_ATTR_KEY_PTHPRIORITY,
125 &ipc_pthread_priority_voucher_attr_control);
126 if (kr != KERN_SUCCESS )
127 panic("IPC_PTHREAD_PRIORITY subsystem initialization failed");
128
129 kprintf("IPC_PTHREAD_PRIORITY subsystem is initialized\n");
130 return ;
131 }
132
133 /*
134 * IPC_PTHREAD_PRIORITY Resource Manager Routines.
135 */
136
137
138 /*
139 * Routine: ipc_pthread_priority_release_value
140 * Purpose: Release a value, if sync matches the sync count in value.
141 * Returns: KERN_SUCCESS: on Successful deletion.
142 * KERN_FAILURE: if sync value does not matches.
143 */
144 kern_return_t
145 ipc_pthread_priority_release_value(
146 ipc_voucher_attr_manager_t __assert_only manager,
147 mach_voucher_attr_key_t __assert_only key,
148 mach_voucher_attr_value_handle_t value,
149 mach_voucher_attr_value_reference_t sync)
150 {
151 assert(MACH_VOUCHER_ATTR_KEY_PTHPRIORITY == key);
152 assert(manager == &ipc_pthread_priority_manager);
153
154 ipc_pthread_priority_value_t ipc_pthread_priority_value = HANDLE_TO_IPC_PTHREAD_PRIORITY_VALUE(value);
155
156 panic("ipc_pthread_priority_release_value called for a persistent PTHPRIORITY value %x with sync value %d\n", ipc_pthread_priority_value, sync);
157 return KERN_FAILURE;
158 }
159
160 /*
161 * Routine: ipc_pthread_priority_get_value
162 */
163 kern_return_t
164 ipc_pthread_priority_get_value(
165 ipc_voucher_attr_manager_t __assert_only manager,
166 mach_voucher_attr_key_t __assert_only key,
167 mach_voucher_attr_recipe_command_t command,
168 mach_voucher_attr_value_handle_array_t __unused prev_values,
169 mach_msg_type_number_t __unused prev_value_count,
170 mach_voucher_attr_content_t recipe,
171 mach_voucher_attr_content_size_t recipe_size,
172 mach_voucher_attr_value_handle_t *out_value,
173 mach_voucher_attr_value_flags_t *out_flags,
174 ipc_voucher_t *out_value_voucher)
175 {
176 kern_return_t kr = KERN_SUCCESS;
177 ipc_pthread_priority_value_t ipc_pthread_priority_value;
178 ipc_pthread_priority_value_t canonicalize_priority_value;
179
180 assert(MACH_VOUCHER_ATTR_KEY_PTHPRIORITY == key);
181 assert(manager == &ipc_pthread_priority_manager);
182
183 /* never an out voucher */
184 *out_value_voucher = IPC_VOUCHER_NULL;
185 *out_flags = MACH_VOUCHER_ATTR_VALUE_FLAGS_NONE;
186
187 switch (command) {
188
189 case MACH_VOUCHER_ATTR_PTHPRIORITY_CREATE:
190
191 if (recipe_size != sizeof(ipc_pthread_priority_value_t)) {
192 return KERN_INVALID_ARGUMENT;
193 }
194
195 memcpy(&ipc_pthread_priority_value, recipe, recipe_size);
196
197 if (ipc_pthread_priority_value == PTHPRIORITY_ATTR_DEFAULT_VALUE) {
198 *out_value = IPC_PTHREAD_PRIORITY_VALUE_TO_HANDLE(PTHPRIORITY_ATTR_DEFAULT_VALUE);
199 return kr;
200 }
201
202 /* Callout to pthread kext to get the canonicalized value */
203 canonicalize_priority_value = (ipc_pthread_priority_value_t) pthread_priority_canonicalize(
204 (unsigned long)ipc_pthread_priority_value, true);
205
206 *out_value = IPC_PTHREAD_PRIORITY_VALUE_TO_HANDLE(canonicalize_priority_value);
207 *out_flags = MACH_VOUCHER_ATTR_VALUE_FLAGS_PERSIST;
208 return kr;
209
210 default:
211 kr = KERN_INVALID_ARGUMENT;
212 break;
213 }
214
215 return kr;
216 }
217
218 /*
219 * Routine: ipc_pthread_priority_extract_content
220 * Purpose: Extract a set of pthread_priority value from an array of voucher values.
221 * Returns: KERN_SUCCESS: on Success.
222 * KERN_NO_SPACE: insufficeint buffer provided to fill an array of pthread_priority values.
223 */
224 kern_return_t
225 ipc_pthread_priority_extract_content(
226 ipc_voucher_attr_manager_t __assert_only manager,
227 mach_voucher_attr_key_t __assert_only key,
228 mach_voucher_attr_value_handle_array_t values,
229 mach_msg_type_number_t value_count,
230 mach_voucher_attr_recipe_command_t *out_command,
231 mach_voucher_attr_content_t out_recipe,
232 mach_voucher_attr_content_size_t *in_out_recipe_size)
233 {
234 kern_return_t kr = KERN_SUCCESS;
235 mach_msg_type_number_t i;
236 ipc_pthread_priority_value_t ipc_pthread_priority_value;
237
238 assert(MACH_VOUCHER_ATTR_KEY_PTHPRIORITY == key);
239 assert(manager == &ipc_pthread_priority_manager);
240
241 for (i = 0; i < value_count; i++) {
242 ipc_pthread_priority_value = HANDLE_TO_IPC_PTHREAD_PRIORITY_VALUE(values[i]);
243
244 if (ipc_pthread_priority_value == PTHPRIORITY_ATTR_DEFAULT_VALUE) {
245 continue;
246 }
247
248 if (MACH_VOUCHER_PTHPRIORITY_CONTENT_SIZE > *in_out_recipe_size) {
249 *in_out_recipe_size = 0;
250 return KERN_NO_SPACE;
251 }
252
253 memcpy(&out_recipe[0], &ipc_pthread_priority_value, sizeof(ipc_pthread_priority_value));
254 *out_command = MACH_VOUCHER_ATTR_PTHPRIORITY_NULL;
255 *in_out_recipe_size = (mach_voucher_attr_content_size_t)sizeof(ipc_pthread_priority_value);
256 return kr;
257 }
258
259 *in_out_recipe_size = 0;
260 return KERN_INVALID_VALUE;
261 }
262
263 /*
264 * Routine: ipc_pthread_priority_command
265 * Purpose: Execute a command against a set of PTHPRIORITY values.
266 * Returns: KERN_SUCCESS: On successful execution of command.
267 * KERN_FAILURE: On failure.
268 */
269 kern_return_t
270 ipc_pthread_priority_command(
271 ipc_voucher_attr_manager_t __assert_only manager,
272 mach_voucher_attr_key_t __assert_only key,
273 mach_voucher_attr_value_handle_array_t __unused values,
274 mach_msg_type_number_t __unused value_count,
275 mach_voucher_attr_command_t __unused command,
276 mach_voucher_attr_content_t __unused in_content,
277 mach_voucher_attr_content_size_t __unused in_content_size,
278 mach_voucher_attr_content_t __unused out_content,
279 mach_voucher_attr_content_size_t __unused *out_content_size)
280 {
281 assert(MACH_VOUCHER_ATTR_KEY_PTHPRIORITY == key);
282 assert(manager == &ipc_pthread_priority_manager);
283
284 return KERN_FAILURE;
285 }
286
287 void
288 ipc_pthread_priority_release(
289 ipc_voucher_attr_manager_t __assert_only manager)
290 {
291 assert(manager == &ipc_pthread_priority_manager);
292 }