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