]>
Commit | Line | Data |
---|---|---|
1c79356b | 1 | /* |
b0d623f7 | 2 | * Copyright (c) 2000-2009 Apple Inc. All rights reserved. |
1c79356b | 3 | * |
2d21ac55 | 4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ |
3e170ce0 | 5 | * |
2d21ac55 A |
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. | |
3e170ce0 | 14 | * |
2d21ac55 A |
15 | * Please obtain a copy of the License at |
16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. | |
3e170ce0 | 17 | * |
2d21ac55 A |
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 | |
8f6c56a5 A |
20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
2d21ac55 A |
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. | |
3e170ce0 | 25 | * |
2d21ac55 | 26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ |
1c79356b A |
27 | */ |
28 | /* | |
29 | * @OSF_COPYRIGHT@ | |
30 | */ | |
3e170ce0 | 31 | /* |
1c79356b A |
32 | * Mach Operating System |
33 | * Copyright (c) 1991,1990,1989,1988 Carnegie Mellon University | |
34 | * All Rights Reserved. | |
3e170ce0 | 35 | * |
1c79356b A |
36 | * Permission to use, copy, modify and distribute this software and its |
37 | * documentation is hereby granted, provided that both the copyright | |
38 | * notice and this permission notice appear in all copies of the | |
39 | * software, derivative works or modified versions, and any portions | |
40 | * thereof, and that both notices appear in supporting documentation. | |
3e170ce0 | 41 | * |
1c79356b A |
42 | * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" |
43 | * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR | |
44 | * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. | |
3e170ce0 | 45 | * |
1c79356b | 46 | * Carnegie Mellon requests users of this software to return to |
3e170ce0 | 47 | * |
1c79356b A |
48 | * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU |
49 | * School of Computer Science | |
50 | * Carnegie Mellon University | |
51 | * Pittsburgh PA 15213-3890 | |
3e170ce0 | 52 | * |
1c79356b A |
53 | * any improvements or extensions that they make and grant Carnegie Mellon |
54 | * the rights to redistribute these changes. | |
55 | */ | |
56 | /* | |
57 | */ | |
58 | ||
59 | /* | |
60 | * host.c | |
61 | * | |
62 | * Non-ipc host functions. | |
63 | */ | |
64 | ||
91447636 | 65 | #include <mach/mach_types.h> |
1c79356b | 66 | #include <mach/boolean.h> |
1c79356b | 67 | #include <mach/host_info.h> |
55e303ae | 68 | #include <mach/host_special_ports.h> |
1c79356b A |
69 | #include <mach/kern_return.h> |
70 | #include <mach/machine.h> | |
71 | #include <mach/port.h> | |
1c79356b A |
72 | #include <mach/processor_info.h> |
73 | #include <mach/vm_param.h> | |
91447636 | 74 | #include <mach/processor.h> |
1c79356b | 75 | #include <mach/mach_host_server.h> |
91447636 A |
76 | #include <mach/host_priv_server.h> |
77 | #include <mach/vm_map.h> | |
39236c6e | 78 | #include <mach/task_info.h> |
91447636 | 79 | |
490019cf A |
80 | #include <machine/commpage.h> |
81 | #include <machine/cpu_capabilities.h> | |
82 | ||
91447636 A |
83 | #include <kern/kern_types.h> |
84 | #include <kern/assert.h> | |
85 | #include <kern/kalloc.h> | |
86 | #include <kern/host.h> | |
87 | #include <kern/host_statistics.h> | |
88 | #include <kern/ipc_host.h> | |
89 | #include <kern/misc_protos.h> | |
90 | #include <kern/sched.h> | |
91 | #include <kern/processor.h> | |
0a7de745 | 92 | #include <kern/mach_node.h> // mach_node_port_changed() |
91447636 A |
93 | |
94 | #include <vm/vm_map.h> | |
39236c6e A |
95 | #include <vm/vm_purgeable_internal.h> |
96 | #include <vm/vm_pageout.h> | |
91447636 | 97 | |
cb323159 A |
98 | #include <IOKit/IOBSD.h> // IOTaskHasEntitlement |
99 | #include <IOKit/IOKitKeys.h> // DriverKit entitlement strings | |
100 | ||
39037602 | 101 | |
3e170ce0 A |
102 | #if CONFIG_ATM |
103 | #include <atm/atm_internal.h> | |
104 | #endif | |
105 | ||
106 | #if CONFIG_MACF | |
107 | #include <security/mac_mach_internal.h> | |
108 | #endif | |
109 | ||
39037602 A |
110 | #include <pexpert/pexpert.h> |
111 | ||
3e170ce0 | 112 | host_data_t realhost; |
1c79356b | 113 | |
6d2010ae A |
114 | vm_extmod_statistics_data_t host_extmod_statistics; |
115 | ||
1c79356b | 116 | kern_return_t |
3e170ce0 | 117 | host_processors(host_priv_t host_priv, processor_array_t * out_array, mach_msg_type_number_t * countp) |
1c79356b | 118 | { |
39037602 | 119 | processor_t processor, *tp; |
3e170ce0 A |
120 | void * addr; |
121 | unsigned int count, i; | |
1c79356b | 122 | |
0a7de745 A |
123 | if (host_priv == HOST_PRIV_NULL) { |
124 | return KERN_INVALID_ARGUMENT; | |
125 | } | |
1c79356b A |
126 | |
127 | assert(host_priv == &realhost); | |
128 | ||
91447636 A |
129 | count = processor_count; |
130 | assert(count != 0); | |
1c79356b | 131 | |
3e170ce0 | 132 | addr = kalloc((vm_size_t)(count * sizeof(mach_port_t))); |
0a7de745 A |
133 | if (addr == 0) { |
134 | return KERN_RESOURCE_SHORTAGE; | |
135 | } | |
1c79356b | 136 | |
3e170ce0 | 137 | tp = (processor_t *)addr; |
91447636 A |
138 | *tp++ = processor = processor_list; |
139 | ||
140 | if (count > 1) { | |
0a7de745 | 141 | simple_lock(&processor_list_lock, LCK_GRP_NULL); |
91447636 | 142 | |
0a7de745 | 143 | for (i = 1; i < count; i++) { |
91447636 | 144 | *tp++ = processor = processor->processor_list; |
0a7de745 | 145 | } |
91447636 A |
146 | |
147 | simple_unlock(&processor_list_lock); | |
148 | } | |
1c79356b A |
149 | |
150 | *countp = count; | |
91447636 | 151 | *out_array = (processor_array_t)addr; |
1c79356b A |
152 | |
153 | /* do the conversion that Mig should handle */ | |
3e170ce0 | 154 | tp = (processor_t *)addr; |
0a7de745 | 155 | for (i = 0; i < count; i++) { |
3e170ce0 | 156 | ((mach_port_t *)tp)[i] = (mach_port_t)convert_processor_to_port(tp[i]); |
0a7de745 | 157 | } |
1c79356b | 158 | |
0a7de745 | 159 | return KERN_SUCCESS; |
1c79356b A |
160 | } |
161 | ||
162 | kern_return_t | |
3e170ce0 | 163 | host_info(host_t host, host_flavor_t flavor, host_info_t info, mach_msg_type_number_t * count) |
1c79356b | 164 | { |
0a7de745 A |
165 | if (host == HOST_NULL) { |
166 | return KERN_INVALID_ARGUMENT; | |
167 | } | |
1c79356b | 168 | |
3e170ce0 A |
169 | switch (flavor) { |
170 | case HOST_BASIC_INFO: { | |
39037602 A |
171 | host_basic_info_t basic_info; |
172 | int master_id; | |
1c79356b A |
173 | |
174 | /* | |
175 | * Basic information about this host. | |
176 | */ | |
0a7de745 A |
177 | if (*count < HOST_BASIC_INFO_OLD_COUNT) { |
178 | return KERN_FAILURE; | |
179 | } | |
1c79356b | 180 | |
3e170ce0 | 181 | basic_info = (host_basic_info_t)info; |
1c79356b | 182 | |
1c79356b | 183 | basic_info->memory_size = machine_info.memory_size; |
2d21ac55 | 184 | basic_info->max_cpus = machine_info.max_cpus; |
0a7de745 A |
185 | #if defined(__x86_64__) |
186 | basic_info->avail_cpus = processor_avail_count_user; | |
187 | #else | |
2d21ac55 | 188 | basic_info->avail_cpus = processor_avail_count; |
0a7de745 | 189 | #endif |
b0d623f7 A |
190 | master_id = master_processor->cpu_id; |
191 | basic_info->cpu_type = slot_type(master_id); | |
192 | basic_info->cpu_subtype = slot_subtype(master_id); | |
91447636 A |
193 | |
194 | if (*count >= HOST_BASIC_INFO_COUNT) { | |
b0d623f7 | 195 | basic_info->cpu_threadtype = slot_threadtype(master_id); |
91447636 A |
196 | basic_info->physical_cpu = machine_info.physical_cpu; |
197 | basic_info->physical_cpu_max = machine_info.physical_cpu_max; | |
0a7de745 A |
198 | #if defined(__x86_64__) |
199 | basic_info->logical_cpu = basic_info->avail_cpus; | |
200 | #else | |
91447636 | 201 | basic_info->logical_cpu = machine_info.logical_cpu; |
0a7de745 | 202 | #endif |
91447636 A |
203 | basic_info->logical_cpu_max = machine_info.logical_cpu_max; |
204 | basic_info->max_mem = machine_info.max_mem; | |
205 | ||
206 | *count = HOST_BASIC_INFO_COUNT; | |
207 | } else { | |
208 | *count = HOST_BASIC_INFO_OLD_COUNT; | |
209 | } | |
1c79356b | 210 | |
0a7de745 | 211 | return KERN_SUCCESS; |
1c79356b A |
212 | } |
213 | ||
3e170ce0 | 214 | case HOST_SCHED_INFO: { |
39037602 | 215 | host_sched_info_t sched_info; |
6d2010ae A |
216 | uint32_t quantum_time; |
217 | uint64_t quantum_ns; | |
1c79356b A |
218 | |
219 | /* | |
220 | * Return scheduler information. | |
221 | */ | |
0a7de745 A |
222 | if (*count < HOST_SCHED_INFO_COUNT) { |
223 | return KERN_FAILURE; | |
224 | } | |
1c79356b | 225 | |
3e170ce0 | 226 | sched_info = (host_sched_info_t)info; |
1c79356b | 227 | |
6d2010ae A |
228 | quantum_time = SCHED(initial_quantum_size)(THREAD_NULL); |
229 | absolutetime_to_nanoseconds(quantum_time, &quantum_ns); | |
230 | ||
3e170ce0 | 231 | sched_info->min_timeout = sched_info->min_quantum = (uint32_t)(quantum_ns / 1000 / 1000); |
1c79356b A |
232 | |
233 | *count = HOST_SCHED_INFO_COUNT; | |
234 | ||
0a7de745 | 235 | return KERN_SUCCESS; |
1c79356b A |
236 | } |
237 | ||
3e170ce0 | 238 | case HOST_RESOURCE_SIZES: { |
1c79356b A |
239 | /* |
240 | * Return sizes of kernel data structures | |
241 | */ | |
0a7de745 A |
242 | if (*count < HOST_RESOURCE_SIZES_COUNT) { |
243 | return KERN_FAILURE; | |
244 | } | |
1c79356b A |
245 | |
246 | /* XXX Fail until ledgers are implemented */ | |
0a7de745 | 247 | return KERN_INVALID_ARGUMENT; |
1c79356b | 248 | } |
3e170ce0 A |
249 | |
250 | case HOST_PRIORITY_INFO: { | |
39037602 | 251 | host_priority_info_t priority_info; |
1c79356b | 252 | |
0a7de745 A |
253 | if (*count < HOST_PRIORITY_INFO_COUNT) { |
254 | return KERN_FAILURE; | |
255 | } | |
1c79356b | 256 | |
3e170ce0 | 257 | priority_info = (host_priority_info_t)info; |
1c79356b | 258 | |
3e170ce0 A |
259 | priority_info->kernel_priority = MINPRI_KERNEL; |
260 | priority_info->system_priority = MINPRI_KERNEL; | |
261 | priority_info->server_priority = MINPRI_RESERVED; | |
262 | priority_info->user_priority = BASEPRI_DEFAULT; | |
263 | priority_info->depress_priority = DEPRESSPRI; | |
264 | priority_info->idle_priority = IDLEPRI; | |
265 | priority_info->minimum_priority = MINPRI_USER; | |
266 | priority_info->maximum_priority = MAXPRI_RESERVED; | |
1c79356b A |
267 | |
268 | *count = HOST_PRIORITY_INFO_COUNT; | |
269 | ||
0a7de745 | 270 | return KERN_SUCCESS; |
1c79356b A |
271 | } |
272 | ||
273 | /* | |
9bccf70c | 274 | * Gestalt for various trap facilities. |
1c79356b | 275 | */ |
9bccf70c | 276 | case HOST_MACH_MSG_TRAP: |
3e170ce0 | 277 | case HOST_SEMAPHORE_TRAPS: { |
1c79356b | 278 | *count = 0; |
0a7de745 | 279 | return KERN_SUCCESS; |
1c79356b A |
280 | } |
281 | ||
39037602 A |
282 | case HOST_CAN_HAS_DEBUGGER: { |
283 | host_can_has_debugger_info_t can_has_debugger_info; | |
284 | ||
0a7de745 A |
285 | if (*count < HOST_CAN_HAS_DEBUGGER_COUNT) { |
286 | return KERN_FAILURE; | |
287 | } | |
39037602 A |
288 | |
289 | can_has_debugger_info = (host_can_has_debugger_info_t)info; | |
290 | can_has_debugger_info->can_has_debugger = PE_i_can_has_debugger(NULL); | |
291 | *count = HOST_CAN_HAS_DEBUGGER_COUNT; | |
292 | ||
293 | return KERN_SUCCESS; | |
294 | } | |
295 | ||
3e170ce0 | 296 | case HOST_VM_PURGABLE: { |
0a7de745 A |
297 | if (*count < HOST_VM_PURGABLE_COUNT) { |
298 | return KERN_FAILURE; | |
299 | } | |
39236c6e | 300 | |
3e170ce0 | 301 | vm_purgeable_stats((vm_purgeable_info_t)info, NULL); |
39236c6e A |
302 | |
303 | *count = HOST_VM_PURGABLE_COUNT; | |
0a7de745 | 304 | return KERN_SUCCESS; |
39236c6e A |
305 | } |
306 | ||
3e170ce0 A |
307 | case HOST_DEBUG_INFO_INTERNAL: { |
308 | #if DEVELOPMENT || DEBUG | |
0a7de745 A |
309 | if (*count < HOST_DEBUG_INFO_INTERNAL_COUNT) { |
310 | return KERN_FAILURE; | |
311 | } | |
3e170ce0 A |
312 | |
313 | host_debug_info_internal_t debug_info = (host_debug_info_internal_t)info; | |
314 | bzero(debug_info, sizeof(host_debug_info_internal_data_t)); | |
315 | *count = HOST_DEBUG_INFO_INTERNAL_COUNT; | |
316 | ||
317 | #if CONFIG_COALITIONS | |
318 | debug_info->config_coalitions = 1; | |
319 | #endif | |
3e170ce0 | 320 | debug_info->config_bank = 1; |
3e170ce0 A |
321 | #if CONFIG_ATM |
322 | debug_info->config_atm = 1; | |
323 | #endif | |
324 | #if CONFIG_CSR | |
325 | debug_info->config_csr = 1; | |
326 | #endif | |
0a7de745 | 327 | return KERN_SUCCESS; |
3e170ce0 | 328 | #else /* DEVELOPMENT || DEBUG */ |
0a7de745 | 329 | return KERN_NOT_SUPPORTED; |
3e170ce0 A |
330 | #endif |
331 | } | |
332 | ||
d9a64523 A |
333 | case HOST_PREFERRED_USER_ARCH: { |
334 | host_preferred_user_arch_t user_arch_info; | |
335 | ||
336 | /* | |
337 | * Basic information about this host. | |
338 | */ | |
0a7de745 A |
339 | if (*count < HOST_PREFERRED_USER_ARCH_COUNT) { |
340 | return KERN_FAILURE; | |
341 | } | |
d9a64523 A |
342 | |
343 | user_arch_info = (host_preferred_user_arch_t)info; | |
344 | ||
345 | #if defined(PREFERRED_USER_CPU_TYPE) && defined(PREFERRED_USER_CPU_SUBTYPE) | |
cb323159 A |
346 | cpu_type_t preferred_cpu_type; |
347 | cpu_subtype_t preferred_cpu_subtype; | |
348 | if (!PE_get_default("kern.preferred_cpu_type", &preferred_cpu_type, sizeof(cpu_type_t))) { | |
349 | preferred_cpu_type = PREFERRED_USER_CPU_TYPE; | |
350 | } | |
351 | if (!PE_get_default("kern.preferred_cpu_subtype", &preferred_cpu_subtype, sizeof(cpu_subtype_t))) { | |
352 | preferred_cpu_subtype = PREFERRED_USER_CPU_SUBTYPE; | |
353 | } | |
354 | user_arch_info->cpu_type = preferred_cpu_type; | |
355 | user_arch_info->cpu_subtype = preferred_cpu_subtype; | |
d9a64523 | 356 | #else |
cb323159 A |
357 | int master_id = master_processor->cpu_id; |
358 | user_arch_info->cpu_type = slot_type(master_id); | |
d9a64523 A |
359 | user_arch_info->cpu_subtype = slot_subtype(master_id); |
360 | #endif | |
361 | ||
362 | *count = HOST_PREFERRED_USER_ARCH_COUNT; | |
363 | ||
0a7de745 | 364 | return KERN_SUCCESS; |
d9a64523 A |
365 | } |
366 | ||
0a7de745 | 367 | default: return KERN_INVALID_ARGUMENT; |
1c79356b A |
368 | } |
369 | } | |
370 | ||
cc8bc92a A |
371 | kern_return_t host_statistics(host_t host, host_flavor_t flavor, host_info_t info, mach_msg_type_number_t * count); |
372 | ||
1c79356b | 373 | kern_return_t |
3e170ce0 | 374 | host_statistics(host_t host, host_flavor_t flavor, host_info_t info, mach_msg_type_number_t * count) |
1c79356b | 375 | { |
3e170ce0 | 376 | uint32_t i; |
1c79356b | 377 | |
0a7de745 A |
378 | if (host == HOST_NULL) { |
379 | return KERN_INVALID_HOST; | |
380 | } | |
1c79356b | 381 | |
3e170ce0 A |
382 | switch (flavor) { |
383 | case HOST_LOAD_INFO: { | |
384 | host_load_info_t load_info; | |
1c79356b | 385 | |
0a7de745 A |
386 | if (*count < HOST_LOAD_INFO_COUNT) { |
387 | return KERN_FAILURE; | |
388 | } | |
1c79356b | 389 | |
3e170ce0 | 390 | load_info = (host_load_info_t)info; |
1c79356b | 391 | |
3e170ce0 A |
392 | bcopy((char *)avenrun, (char *)load_info->avenrun, sizeof avenrun); |
393 | bcopy((char *)mach_factor, (char *)load_info->mach_factor, sizeof mach_factor); | |
1c79356b A |
394 | |
395 | *count = HOST_LOAD_INFO_COUNT; | |
0a7de745 | 396 | return KERN_SUCCESS; |
91447636 A |
397 | } |
398 | ||
3e170ce0 | 399 | case HOST_VM_INFO: { |
39037602 A |
400 | processor_t processor; |
401 | vm_statistics64_t stat; | |
3e170ce0 A |
402 | vm_statistics64_data_t host_vm_stat; |
403 | vm_statistics_t stat32; | |
404 | mach_msg_type_number_t original_count; | |
405 | ||
0a7de745 A |
406 | if (*count < HOST_VM_INFO_REV0_COUNT) { |
407 | return KERN_FAILURE; | |
408 | } | |
1c79356b | 409 | |
91447636 A |
410 | processor = processor_list; |
411 | stat = &PROCESSOR_DATA(processor, vm_stat); | |
1c79356b | 412 | host_vm_stat = *stat; |
91447636 A |
413 | |
414 | if (processor_count > 1) { | |
0a7de745 | 415 | simple_lock(&processor_list_lock, LCK_GRP_NULL); |
91447636 A |
416 | |
417 | while ((processor = processor->processor_list) != NULL) { | |
418 | stat = &PROCESSOR_DATA(processor, vm_stat); | |
419 | ||
3e170ce0 | 420 | host_vm_stat.zero_fill_count += stat->zero_fill_count; |
91447636 | 421 | host_vm_stat.reactivations += stat->reactivations; |
1c79356b A |
422 | host_vm_stat.pageins += stat->pageins; |
423 | host_vm_stat.pageouts += stat->pageouts; | |
424 | host_vm_stat.faults += stat->faults; | |
425 | host_vm_stat.cow_faults += stat->cow_faults; | |
426 | host_vm_stat.lookups += stat->lookups; | |
427 | host_vm_stat.hits += stat->hits; | |
428 | } | |
91447636 A |
429 | |
430 | simple_unlock(&processor_list_lock); | |
1c79356b | 431 | } |
1c79356b | 432 | |
3e170ce0 | 433 | stat32 = (vm_statistics_t)info; |
b0d623f7 A |
434 | |
435 | stat32->free_count = VM_STATISTICS_TRUNCATE_TO_32_BIT(vm_page_free_count + vm_page_speculative_count); | |
436 | stat32->active_count = VM_STATISTICS_TRUNCATE_TO_32_BIT(vm_page_active_count); | |
3e170ce0 | 437 | |
b0d623f7 A |
438 | if (vm_page_local_q) { |
439 | for (i = 0; i < vm_page_local_q_count; i++) { | |
3e170ce0 | 440 | struct vpl * lq; |
b0d623f7 A |
441 | |
442 | lq = &vm_page_local_q[i].vpl_un.vpl; | |
443 | ||
444 | stat32->active_count += VM_STATISTICS_TRUNCATE_TO_32_BIT(lq->vpl_count); | |
445 | } | |
446 | } | |
447 | stat32->inactive_count = VM_STATISTICS_TRUNCATE_TO_32_BIT(vm_page_inactive_count); | |
5ba3f43e A |
448 | #if CONFIG_EMBEDDED |
449 | stat32->wire_count = VM_STATISTICS_TRUNCATE_TO_32_BIT(vm_page_wire_count); | |
450 | #else | |
0b4c1975 | 451 | stat32->wire_count = VM_STATISTICS_TRUNCATE_TO_32_BIT(vm_page_wire_count + vm_page_throttled_count + vm_lopage_free_count); |
5ba3f43e | 452 | #endif |
b0d623f7 A |
453 | stat32->zero_fill_count = VM_STATISTICS_TRUNCATE_TO_32_BIT(host_vm_stat.zero_fill_count); |
454 | stat32->reactivations = VM_STATISTICS_TRUNCATE_TO_32_BIT(host_vm_stat.reactivations); | |
455 | stat32->pageins = VM_STATISTICS_TRUNCATE_TO_32_BIT(host_vm_stat.pageins); | |
456 | stat32->pageouts = VM_STATISTICS_TRUNCATE_TO_32_BIT(host_vm_stat.pageouts); | |
457 | stat32->faults = VM_STATISTICS_TRUNCATE_TO_32_BIT(host_vm_stat.faults); | |
458 | stat32->cow_faults = VM_STATISTICS_TRUNCATE_TO_32_BIT(host_vm_stat.cow_faults); | |
459 | stat32->lookups = VM_STATISTICS_TRUNCATE_TO_32_BIT(host_vm_stat.lookups); | |
460 | stat32->hits = VM_STATISTICS_TRUNCATE_TO_32_BIT(host_vm_stat.hits); | |
91447636 | 461 | |
2d21ac55 A |
462 | /* |
463 | * Fill in extra info added in later revisions of the | |
464 | * vm_statistics data structure. Fill in only what can fit | |
465 | * in the data structure the caller gave us ! | |
466 | */ | |
467 | original_count = *count; | |
468 | *count = HOST_VM_INFO_REV0_COUNT; /* rev0 already filled in */ | |
469 | if (original_count >= HOST_VM_INFO_REV1_COUNT) { | |
470 | /* rev1 added "purgeable" info */ | |
b0d623f7 A |
471 | stat32->purgeable_count = VM_STATISTICS_TRUNCATE_TO_32_BIT(vm_page_purgeable_count); |
472 | stat32->purges = VM_STATISTICS_TRUNCATE_TO_32_BIT(vm_page_purged_count); | |
2d21ac55 A |
473 | *count = HOST_VM_INFO_REV1_COUNT; |
474 | } | |
b0d623f7 | 475 | |
2d21ac55 A |
476 | if (original_count >= HOST_VM_INFO_REV2_COUNT) { |
477 | /* rev2 added "speculative" info */ | |
b0d623f7 | 478 | stat32->speculative_count = VM_STATISTICS_TRUNCATE_TO_32_BIT(vm_page_speculative_count); |
2d21ac55 | 479 | *count = HOST_VM_INFO_REV2_COUNT; |
91447636 A |
480 | } |
481 | ||
b0d623f7 A |
482 | /* rev3 changed some of the fields to be 64-bit*/ |
483 | ||
0a7de745 | 484 | return KERN_SUCCESS; |
91447636 | 485 | } |
3e170ce0 A |
486 | |
487 | case HOST_CPU_LOAD_INFO: { | |
39037602 | 488 | processor_t processor; |
3e170ce0 | 489 | host_cpu_load_info_t cpu_load_info; |
1c79356b | 490 | |
0a7de745 A |
491 | if (*count < HOST_CPU_LOAD_INFO_COUNT) { |
492 | return KERN_FAILURE; | |
493 | } | |
91447636 | 494 | |
3e170ce0 A |
495 | #define GET_TICKS_VALUE(state, ticks) \ |
496 | MACRO_BEGIN cpu_load_info->cpu_ticks[(state)] += (uint32_t)(ticks / hz_tick_interval); \ | |
497 | MACRO_END | |
498 | #define GET_TICKS_VALUE_FROM_TIMER(processor, state, timer) \ | |
499 | MACRO_BEGIN GET_TICKS_VALUE(state, timer_grab(&PROCESSOR_DATA(processor, timer))); \ | |
500 | MACRO_END | |
1c79356b | 501 | |
91447636 | 502 | cpu_load_info = (host_cpu_load_info_t)info; |
1c79356b | 503 | cpu_load_info->cpu_ticks[CPU_STATE_USER] = 0; |
1c79356b A |
504 | cpu_load_info->cpu_ticks[CPU_STATE_SYSTEM] = 0; |
505 | cpu_load_info->cpu_ticks[CPU_STATE_IDLE] = 0; | |
2d21ac55 | 506 | cpu_load_info->cpu_ticks[CPU_STATE_NICE] = 0; |
91447636 | 507 | |
0a7de745 | 508 | simple_lock(&processor_list_lock, LCK_GRP_NULL); |
91447636 | 509 | |
6d2010ae | 510 | for (processor = processor_list; processor != NULL; processor = processor->processor_list) { |
3e170ce0 A |
511 | timer_t idle_state; |
512 | uint64_t idle_time_snapshot1, idle_time_snapshot2; | |
513 | uint64_t idle_time_tstamp1, idle_time_tstamp2; | |
514 | ||
39236c6e | 515 | /* See discussion in processor_info(PROCESSOR_CPU_LOAD_INFO) */ |
91447636 | 516 | |
39236c6e | 517 | GET_TICKS_VALUE_FROM_TIMER(processor, CPU_STATE_USER, user_state); |
316670eb | 518 | if (precise_user_kernel_time) { |
39236c6e | 519 | GET_TICKS_VALUE_FROM_TIMER(processor, CPU_STATE_SYSTEM, system_state); |
316670eb A |
520 | } else { |
521 | /* system_state may represent either sys or user */ | |
39236c6e | 522 | GET_TICKS_VALUE_FROM_TIMER(processor, CPU_STATE_USER, system_state); |
316670eb | 523 | } |
6d2010ae A |
524 | |
525 | idle_state = &PROCESSOR_DATA(processor, idle_state); | |
39236c6e A |
526 | idle_time_snapshot1 = timer_grab(idle_state); |
527 | idle_time_tstamp1 = idle_state->tstamp; | |
3e170ce0 | 528 | |
39236c6e A |
529 | if (PROCESSOR_DATA(processor, current_state) != idle_state) { |
530 | /* Processor is non-idle, so idle timer should be accurate */ | |
531 | GET_TICKS_VALUE_FROM_TIMER(processor, CPU_STATE_IDLE, idle_state); | |
532 | } else if ((idle_time_snapshot1 != (idle_time_snapshot2 = timer_grab(idle_state))) || | |
0a7de745 | 533 | (idle_time_tstamp1 != (idle_time_tstamp2 = idle_state->tstamp))) { |
39236c6e A |
534 | /* Idle timer is being updated concurrently, second stamp is good enough */ |
535 | GET_TICKS_VALUE(CPU_STATE_IDLE, idle_time_snapshot2); | |
536 | } else { | |
537 | /* | |
538 | * Idle timer may be very stale. Fortunately we have established | |
539 | * that idle_time_snapshot1 and idle_time_tstamp1 are unchanging | |
540 | */ | |
541 | idle_time_snapshot1 += mach_absolute_time() - idle_time_tstamp1; | |
3e170ce0 | 542 | |
39236c6e | 543 | GET_TICKS_VALUE(CPU_STATE_IDLE, idle_time_snapshot1); |
6d2010ae | 544 | } |
1c79356b | 545 | } |
6d2010ae | 546 | simple_unlock(&processor_list_lock); |
316670eb | 547 | |
1c79356b | 548 | *count = HOST_CPU_LOAD_INFO_COUNT; |
91447636 | 549 | |
0a7de745 | 550 | return KERN_SUCCESS; |
91447636 | 551 | } |
1c79356b | 552 | |
3e170ce0 | 553 | case HOST_EXPIRED_TASK_INFO: { |
4b17d6b6 | 554 | if (*count < TASK_POWER_INFO_COUNT) { |
0a7de745 | 555 | return KERN_FAILURE; |
4b17d6b6 A |
556 | } |
557 | ||
5ba3f43e A |
558 | task_power_info_t tinfo1 = (task_power_info_t)info; |
559 | task_power_info_v2_t tinfo2 = (task_power_info_v2_t)info; | |
4b17d6b6 | 560 | |
5ba3f43e A |
561 | tinfo1->task_interrupt_wakeups = dead_task_statistics.task_interrupt_wakeups; |
562 | tinfo1->task_platform_idle_wakeups = dead_task_statistics.task_platform_idle_wakeups; | |
4b17d6b6 | 563 | |
5ba3f43e | 564 | tinfo1->task_timer_wakeups_bin_1 = dead_task_statistics.task_timer_wakeups_bin_1; |
39236c6e | 565 | |
5ba3f43e | 566 | tinfo1->task_timer_wakeups_bin_2 = dead_task_statistics.task_timer_wakeups_bin_2; |
4b17d6b6 | 567 | |
5ba3f43e A |
568 | tinfo1->total_user = dead_task_statistics.total_user_time; |
569 | tinfo1->total_system = dead_task_statistics.total_system_time; | |
570 | if (*count < TASK_POWER_INFO_V2_COUNT) { | |
571 | *count = TASK_POWER_INFO_COUNT; | |
0a7de745 | 572 | } else if (*count >= TASK_POWER_INFO_V2_COUNT) { |
5ba3f43e A |
573 | tinfo2->gpu_energy.task_gpu_utilisation = dead_task_statistics.task_gpu_ns; |
574 | #if defined(__arm__) || defined(__arm64__) | |
575 | tinfo2->task_energy = dead_task_statistics.task_energy; | |
576 | tinfo2->task_ptime = dead_task_statistics.total_ptime; | |
577 | tinfo2->task_pset_switches = dead_task_statistics.total_pset_switches; | |
578 | #endif | |
579 | *count = TASK_POWER_INFO_V2_COUNT; | |
580 | } | |
4b17d6b6 | 581 | |
0a7de745 | 582 | return KERN_SUCCESS; |
39236c6e | 583 | } |
0a7de745 | 584 | default: return KERN_INVALID_ARGUMENT; |
1c79356b A |
585 | } |
586 | } | |
587 | ||
3e170ce0 | 588 | extern uint32_t c_segment_pages_compressed; |
b0d623f7 | 589 | |
cc8bc92a A |
590 | #define HOST_STATISTICS_TIME_WINDOW 1 /* seconds */ |
591 | #define HOST_STATISTICS_MAX_REQUESTS 10 /* maximum number of requests per window */ | |
592 | #define HOST_STATISTICS_MIN_REQUESTS 2 /* minimum number of requests per window */ | |
593 | ||
594 | uint64_t host_statistics_time_window; | |
595 | ||
596 | static lck_mtx_t host_statistics_lck; | |
597 | static lck_grp_t* host_statistics_lck_grp; | |
598 | ||
0a7de745 A |
599 | #define HOST_VM_INFO64_REV0 0 |
600 | #define HOST_VM_INFO64_REV1 1 | |
601 | #define HOST_EXTMOD_INFO64_REV0 2 | |
602 | #define HOST_LOAD_INFO_REV0 3 | |
603 | #define HOST_VM_INFO_REV0 4 | |
604 | #define HOST_VM_INFO_REV1 5 | |
605 | #define HOST_VM_INFO_REV2 6 | |
606 | #define HOST_CPU_LOAD_INFO_REV0 7 | |
607 | #define HOST_EXPIRED_TASK_INFO_REV0 8 | |
608 | #define HOST_EXPIRED_TASK_INFO_REV1 9 | |
609 | #define NUM_HOST_INFO_DATA_TYPES 10 | |
cc8bc92a A |
610 | |
611 | static vm_statistics64_data_t host_vm_info64_rev0 = {}; | |
612 | static vm_statistics64_data_t host_vm_info64_rev1 = {}; | |
613 | static vm_extmod_statistics_data_t host_extmod_info64 = {}; | |
614 | static host_load_info_data_t host_load_info = {}; | |
615 | static vm_statistics_data_t host_vm_info_rev0 = {}; | |
616 | static vm_statistics_data_t host_vm_info_rev1 = {}; | |
617 | static vm_statistics_data_t host_vm_info_rev2 = {}; | |
618 | static host_cpu_load_info_data_t host_cpu_load_info = {}; | |
619 | static task_power_info_data_t host_expired_task_info = {}; | |
620 | static task_power_info_v2_data_t host_expired_task_info2 = {}; | |
621 | ||
622 | struct host_stats_cache { | |
623 | uint64_t last_access; | |
624 | uint64_t current_requests; | |
625 | uint64_t max_requests; | |
626 | uintptr_t data; | |
627 | mach_msg_type_number_t count; //NOTE count is in sizeof(integer_t) | |
628 | }; | |
629 | ||
630 | static struct host_stats_cache g_host_stats_cache[NUM_HOST_INFO_DATA_TYPES] = { | |
631 | [HOST_VM_INFO64_REV0] = { .last_access = 0, .current_requests = 0, .max_requests = 0, .data = (uintptr_t)&host_vm_info64_rev0, .count = HOST_VM_INFO64_REV0_COUNT }, | |
632 | [HOST_VM_INFO64_REV1] = { .last_access = 0, .current_requests = 0, .max_requests = 0, .data = (uintptr_t)&host_vm_info64_rev1, .count = HOST_VM_INFO64_REV1_COUNT }, | |
633 | [HOST_EXTMOD_INFO64_REV0] = { .last_access = 0, .current_requests = 0, .max_requests = 0, .data = (uintptr_t)&host_extmod_info64, .count = HOST_EXTMOD_INFO64_COUNT }, | |
634 | [HOST_LOAD_INFO_REV0] = { .last_access = 0, .current_requests = 0, .max_requests = 0, .data = (uintptr_t)&host_load_info, .count = HOST_LOAD_INFO_COUNT }, | |
635 | [HOST_VM_INFO_REV0] = { .last_access = 0, .current_requests = 0, .max_requests = 0, .data = (uintptr_t)&host_vm_info_rev0, .count = HOST_VM_INFO_REV0_COUNT }, | |
636 | [HOST_VM_INFO_REV1] = { .last_access = 0, .current_requests = 0, .max_requests = 0, .data = (uintptr_t)&host_vm_info_rev1, .count = HOST_VM_INFO_REV1_COUNT }, | |
637 | [HOST_VM_INFO_REV2] = { .last_access = 0, .current_requests = 0, .max_requests = 0, .data = (uintptr_t)&host_vm_info_rev2, .count = HOST_VM_INFO_REV2_COUNT }, | |
638 | [HOST_CPU_LOAD_INFO_REV0] = { .last_access = 0, .current_requests = 0, .max_requests = 0, .data = (uintptr_t)&host_cpu_load_info, .count = HOST_CPU_LOAD_INFO_COUNT }, | |
639 | [HOST_EXPIRED_TASK_INFO_REV0] = { .last_access = 0, .current_requests = 0, .max_requests = 0, .data = (uintptr_t)&host_expired_task_info, .count = TASK_POWER_INFO_COUNT }, | |
640 | [HOST_EXPIRED_TASK_INFO_REV1] = { .last_access = 0, .current_requests = 0, .max_requests = 0, .data = (uintptr_t)&host_expired_task_info2, .count = TASK_POWER_INFO_V2_COUNT}, | |
641 | }; | |
642 | ||
643 | ||
644 | void | |
645 | host_statistics_init(void) | |
646 | { | |
647 | host_statistics_lck_grp = lck_grp_alloc_init("host_statistics", LCK_GRP_ATTR_NULL); | |
648 | lck_mtx_init(&host_statistics_lck, host_statistics_lck_grp, LCK_ATTR_NULL); | |
649 | nanoseconds_to_absolutetime((HOST_STATISTICS_TIME_WINDOW * NSEC_PER_SEC), &host_statistics_time_window); | |
650 | } | |
651 | ||
652 | static void | |
653 | cache_host_statistics(int index, host_info64_t info) | |
654 | { | |
0a7de745 A |
655 | if (index < 0 || index >= NUM_HOST_INFO_DATA_TYPES) { |
656 | return; | |
657 | } | |
cc8bc92a | 658 | |
0a7de745 A |
659 | task_t task = current_task(); |
660 | if (task->t_flags & TF_PLATFORM) { | |
661 | return; | |
662 | } | |
cc8bc92a | 663 | |
0a7de745 A |
664 | memcpy((void *)g_host_stats_cache[index].data, info, g_host_stats_cache[index].count * sizeof(integer_t)); |
665 | return; | |
cc8bc92a A |
666 | } |
667 | ||
668 | static void | |
669 | get_cached_info(int index, host_info64_t info, mach_msg_type_number_t* count) | |
670 | { | |
0a7de745 A |
671 | if (index < 0 || index >= NUM_HOST_INFO_DATA_TYPES) { |
672 | *count = 0; | |
673 | return; | |
674 | } | |
cc8bc92a | 675 | |
0a7de745 A |
676 | *count = g_host_stats_cache[index].count; |
677 | memcpy(info, (void *)g_host_stats_cache[index].data, g_host_stats_cache[index].count * sizeof(integer_t)); | |
cc8bc92a A |
678 | } |
679 | ||
680 | static int | |
681 | get_host_info_data_index(bool is_stat64, host_flavor_t flavor, mach_msg_type_number_t* count, kern_return_t* ret) | |
682 | { | |
683 | switch (flavor) { | |
0a7de745 A |
684 | case HOST_VM_INFO64: |
685 | if (!is_stat64) { | |
686 | *ret = KERN_INVALID_ARGUMENT; | |
687 | return -1; | |
688 | } | |
689 | if (*count < HOST_VM_INFO64_REV0_COUNT) { | |
690 | *ret = KERN_FAILURE; | |
691 | return -1; | |
692 | } | |
693 | if (*count >= HOST_VM_INFO64_REV1_COUNT) { | |
694 | return HOST_VM_INFO64_REV1; | |
695 | } | |
696 | return HOST_VM_INFO64_REV0; | |
cc8bc92a A |
697 | |
698 | case HOST_EXTMOD_INFO64: | |
0a7de745 A |
699 | if (!is_stat64) { |
700 | *ret = KERN_INVALID_ARGUMENT; | |
701 | return -1; | |
702 | } | |
703 | if (*count < HOST_EXTMOD_INFO64_COUNT) { | |
704 | *ret = KERN_FAILURE; | |
705 | return -1; | |
706 | } | |
707 | return HOST_EXTMOD_INFO64_REV0; | |
cc8bc92a A |
708 | |
709 | case HOST_LOAD_INFO: | |
0a7de745 A |
710 | if (*count < HOST_LOAD_INFO_COUNT) { |
711 | *ret = KERN_FAILURE; | |
712 | return -1; | |
713 | } | |
714 | return HOST_LOAD_INFO_REV0; | |
cc8bc92a A |
715 | |
716 | case HOST_VM_INFO: | |
0a7de745 A |
717 | if (*count < HOST_VM_INFO_REV0_COUNT) { |
718 | *ret = KERN_FAILURE; | |
719 | return -1; | |
720 | } | |
721 | if (*count >= HOST_VM_INFO_REV2_COUNT) { | |
722 | return HOST_VM_INFO_REV2; | |
723 | } | |
724 | if (*count >= HOST_VM_INFO_REV1_COUNT) { | |
725 | return HOST_VM_INFO_REV1; | |
726 | } | |
727 | return HOST_VM_INFO_REV0; | |
cc8bc92a A |
728 | |
729 | case HOST_CPU_LOAD_INFO: | |
0a7de745 A |
730 | if (*count < HOST_CPU_LOAD_INFO_COUNT) { |
731 | *ret = KERN_FAILURE; | |
732 | return -1; | |
733 | } | |
734 | return HOST_CPU_LOAD_INFO_REV0; | |
cc8bc92a A |
735 | |
736 | case HOST_EXPIRED_TASK_INFO: | |
0a7de745 A |
737 | if (*count < TASK_POWER_INFO_COUNT) { |
738 | *ret = KERN_FAILURE; | |
739 | return -1; | |
740 | } | |
741 | if (*count >= TASK_POWER_INFO_V2_COUNT) { | |
742 | return HOST_EXPIRED_TASK_INFO_REV1; | |
743 | } | |
744 | return HOST_EXPIRED_TASK_INFO_REV0; | |
cc8bc92a A |
745 | |
746 | default: | |
0a7de745 A |
747 | *ret = KERN_INVALID_ARGUMENT; |
748 | return -1; | |
cc8bc92a | 749 | } |
cc8bc92a A |
750 | } |
751 | ||
752 | static bool | |
753 | rate_limit_host_statistics(bool is_stat64, host_flavor_t flavor, host_info64_t info, mach_msg_type_number_t* count, kern_return_t* ret, int *pindex) | |
754 | { | |
755 | task_t task = current_task(); | |
756 | ||
757 | assert(task != kernel_task); | |
758 | ||
759 | *ret = KERN_SUCCESS; | |
760 | ||
761 | /* Access control only for third party applications */ | |
762 | if (task->t_flags & TF_PLATFORM) { | |
763 | return FALSE; | |
764 | } | |
765 | ||
766 | /* Rate limit to HOST_STATISTICS_MAX_REQUESTS queries for each HOST_STATISTICS_TIME_WINDOW window of time */ | |
767 | bool rate_limited = FALSE; | |
768 | bool set_last_access = TRUE; | |
769 | ||
770 | /* there is a cache for every flavor */ | |
771 | int index = get_host_info_data_index(is_stat64, flavor, count, ret); | |
0a7de745 | 772 | if (index == -1) { |
cc8bc92a | 773 | goto out; |
0a7de745 | 774 | } |
cc8bc92a A |
775 | |
776 | *pindex = index; | |
777 | lck_mtx_lock(&host_statistics_lck); | |
778 | if (g_host_stats_cache[index].last_access > mach_continuous_time() - host_statistics_time_window) { | |
779 | set_last_access = FALSE; | |
780 | if (g_host_stats_cache[index].current_requests++ >= g_host_stats_cache[index].max_requests) { | |
781 | rate_limited = TRUE; | |
782 | get_cached_info(index, info, count); | |
783 | } | |
784 | } | |
785 | if (set_last_access) { | |
786 | g_host_stats_cache[index].current_requests = 1; | |
787 | /* | |
788 | * select a random number of requests (included between HOST_STATISTICS_MIN_REQUESTS and HOST_STATISTICS_MAX_REQUESTS) | |
789 | * to let query host_statistics. | |
790 | * In this way it is not possible to infer looking at when the a cached copy changes if host_statistics was called on | |
791 | * the provious window. | |
792 | */ | |
793 | g_host_stats_cache[index].max_requests = (mach_absolute_time() % (HOST_STATISTICS_MAX_REQUESTS - HOST_STATISTICS_MIN_REQUESTS + 1)) + HOST_STATISTICS_MIN_REQUESTS; | |
794 | g_host_stats_cache[index].last_access = mach_continuous_time(); | |
795 | } | |
796 | lck_mtx_unlock(&host_statistics_lck); | |
797 | out: | |
798 | return rate_limited; | |
799 | } | |
800 | ||
801 | kern_return_t host_statistics64(host_t host, host_flavor_t flavor, host_info_t info, mach_msg_type_number_t * count); | |
802 | ||
b0d623f7 | 803 | kern_return_t |
3e170ce0 | 804 | host_statistics64(host_t host, host_flavor_t flavor, host_info64_t info, mach_msg_type_number_t * count) |
b0d623f7 | 805 | { |
3e170ce0 A |
806 | uint32_t i; |
807 | ||
0a7de745 A |
808 | if (host == HOST_NULL) { |
809 | return KERN_INVALID_HOST; | |
810 | } | |
b0d623f7 | 811 | |
3e170ce0 A |
812 | switch (flavor) { |
813 | case HOST_VM_INFO64: /* We were asked to get vm_statistics64 */ | |
814 | { | |
39037602 A |
815 | processor_t processor; |
816 | vm_statistics64_t stat; | |
3e170ce0 A |
817 | vm_statistics64_data_t host_vm_stat; |
818 | mach_msg_type_number_t original_count; | |
819 | unsigned int local_q_internal_count; | |
820 | unsigned int local_q_external_count; | |
821 | ||
0a7de745 A |
822 | if (*count < HOST_VM_INFO64_REV0_COUNT) { |
823 | return KERN_FAILURE; | |
824 | } | |
3e170ce0 A |
825 | |
826 | processor = processor_list; | |
827 | stat = &PROCESSOR_DATA(processor, vm_stat); | |
828 | host_vm_stat = *stat; | |
829 | ||
830 | if (processor_count > 1) { | |
0a7de745 | 831 | simple_lock(&processor_list_lock, LCK_GRP_NULL); |
3e170ce0 A |
832 | |
833 | while ((processor = processor->processor_list) != NULL) { | |
834 | stat = &PROCESSOR_DATA(processor, vm_stat); | |
835 | ||
836 | host_vm_stat.zero_fill_count += stat->zero_fill_count; | |
837 | host_vm_stat.reactivations += stat->reactivations; | |
838 | host_vm_stat.pageins += stat->pageins; | |
839 | host_vm_stat.pageouts += stat->pageouts; | |
840 | host_vm_stat.faults += stat->faults; | |
841 | host_vm_stat.cow_faults += stat->cow_faults; | |
842 | host_vm_stat.lookups += stat->lookups; | |
843 | host_vm_stat.hits += stat->hits; | |
844 | host_vm_stat.compressions += stat->compressions; | |
845 | host_vm_stat.decompressions += stat->decompressions; | |
846 | host_vm_stat.swapins += stat->swapins; | |
847 | host_vm_stat.swapouts += stat->swapouts; | |
39236c6e | 848 | } |
b0d623f7 | 849 | |
3e170ce0 | 850 | simple_unlock(&processor_list_lock); |
b0d623f7 A |
851 | } |
852 | ||
3e170ce0 A |
853 | stat = (vm_statistics64_t)info; |
854 | ||
855 | stat->free_count = vm_page_free_count + vm_page_speculative_count; | |
856 | stat->active_count = vm_page_active_count; | |
6d2010ae | 857 | |
3e170ce0 A |
858 | local_q_internal_count = 0; |
859 | local_q_external_count = 0; | |
860 | if (vm_page_local_q) { | |
861 | for (i = 0; i < vm_page_local_q_count; i++) { | |
862 | struct vpl * lq; | |
6d2010ae | 863 | |
3e170ce0 | 864 | lq = &vm_page_local_q[i].vpl_un.vpl; |
6d2010ae | 865 | |
3e170ce0 A |
866 | stat->active_count += lq->vpl_count; |
867 | local_q_internal_count += lq->vpl_internal_count; | |
868 | local_q_external_count += lq->vpl_external_count; | |
869 | } | |
870 | } | |
871 | stat->inactive_count = vm_page_inactive_count; | |
5ba3f43e A |
872 | #if CONFIG_EMBEDDED |
873 | stat->wire_count = vm_page_wire_count; | |
874 | #else | |
3e170ce0 | 875 | stat->wire_count = vm_page_wire_count + vm_page_throttled_count + vm_lopage_free_count; |
5ba3f43e | 876 | #endif |
3e170ce0 A |
877 | stat->zero_fill_count = host_vm_stat.zero_fill_count; |
878 | stat->reactivations = host_vm_stat.reactivations; | |
879 | stat->pageins = host_vm_stat.pageins; | |
880 | stat->pageouts = host_vm_stat.pageouts; | |
881 | stat->faults = host_vm_stat.faults; | |
882 | stat->cow_faults = host_vm_stat.cow_faults; | |
883 | stat->lookups = host_vm_stat.lookups; | |
884 | stat->hits = host_vm_stat.hits; | |
885 | ||
886 | stat->purgeable_count = vm_page_purgeable_count; | |
887 | stat->purges = vm_page_purged_count; | |
888 | ||
889 | stat->speculative_count = vm_page_speculative_count; | |
6d2010ae | 890 | |
3e170ce0 A |
891 | /* |
892 | * Fill in extra info added in later revisions of the | |
893 | * vm_statistics data structure. Fill in only what can fit | |
894 | * in the data structure the caller gave us ! | |
895 | */ | |
896 | original_count = *count; | |
897 | *count = HOST_VM_INFO64_REV0_COUNT; /* rev0 already filled in */ | |
898 | if (original_count >= HOST_VM_INFO64_REV1_COUNT) { | |
899 | /* rev1 added "throttled count" */ | |
900 | stat->throttled_count = vm_page_throttled_count; | |
901 | /* rev1 added "compression" info */ | |
902 | stat->compressor_page_count = VM_PAGE_COMPRESSOR_COUNT; | |
903 | stat->compressions = host_vm_stat.compressions; | |
904 | stat->decompressions = host_vm_stat.decompressions; | |
905 | stat->swapins = host_vm_stat.swapins; | |
906 | stat->swapouts = host_vm_stat.swapouts; | |
907 | /* rev1 added: | |
908 | * "external page count" | |
909 | * "anonymous page count" | |
910 | * "total # of pages (uncompressed) held in the compressor" | |
911 | */ | |
912 | stat->external_page_count = (vm_page_pageable_external_count + local_q_external_count); | |
913 | stat->internal_page_count = (vm_page_pageable_internal_count + local_q_internal_count); | |
914 | stat->total_uncompressed_pages_in_compressor = c_segment_pages_compressed; | |
915 | *count = HOST_VM_INFO64_REV1_COUNT; | |
6d2010ae A |
916 | } |
917 | ||
0a7de745 | 918 | return KERN_SUCCESS; |
b0d623f7 | 919 | } |
b0d623f7 | 920 | |
3e170ce0 A |
921 | case HOST_EXTMOD_INFO64: /* We were asked to get vm_statistics64 */ |
922 | { | |
923 | vm_extmod_statistics_t out_extmod_statistics; | |
924 | ||
0a7de745 A |
925 | if (*count < HOST_EXTMOD_INFO64_COUNT) { |
926 | return KERN_FAILURE; | |
927 | } | |
3e170ce0 A |
928 | |
929 | out_extmod_statistics = (vm_extmod_statistics_t)info; | |
930 | *out_extmod_statistics = host_extmod_statistics; | |
931 | ||
932 | *count = HOST_EXTMOD_INFO64_COUNT; | |
933 | ||
0a7de745 | 934 | return KERN_SUCCESS; |
3e170ce0 A |
935 | } |
936 | ||
937 | default: /* If we didn't recognize the flavor, send to host_statistics */ | |
0a7de745 | 938 | return host_statistics(host, flavor, (host_info_t)info, count); |
3e170ce0 A |
939 | } |
940 | } | |
b0d623f7 | 941 | |
cc8bc92a A |
942 | kern_return_t |
943 | host_statistics64_from_user(host_t host, host_flavor_t flavor, host_info64_t info, mach_msg_type_number_t * count) | |
944 | { | |
945 | kern_return_t ret = KERN_SUCCESS; | |
946 | int index; | |
947 | ||
0a7de745 A |
948 | if (host == HOST_NULL) { |
949 | return KERN_INVALID_HOST; | |
950 | } | |
cc8bc92a | 951 | |
0a7de745 | 952 | if (rate_limit_host_statistics(TRUE, flavor, info, count, &ret, &index)) { |
cc8bc92a | 953 | return ret; |
0a7de745 | 954 | } |
cc8bc92a | 955 | |
0a7de745 | 956 | if (ret != KERN_SUCCESS) { |
cc8bc92a | 957 | return ret; |
0a7de745 | 958 | } |
cc8bc92a A |
959 | |
960 | ret = host_statistics64(host, flavor, info, count); | |
961 | ||
0a7de745 | 962 | if (ret == KERN_SUCCESS) { |
cc8bc92a | 963 | cache_host_statistics(index, info); |
0a7de745 | 964 | } |
cc8bc92a A |
965 | |
966 | return ret; | |
967 | } | |
968 | ||
969 | kern_return_t | |
970 | host_statistics_from_user(host_t host, host_flavor_t flavor, host_info64_t info, mach_msg_type_number_t * count) | |
971 | { | |
972 | kern_return_t ret = KERN_SUCCESS; | |
973 | int index; | |
974 | ||
0a7de745 A |
975 | if (host == HOST_NULL) { |
976 | return KERN_INVALID_HOST; | |
977 | } | |
cc8bc92a | 978 | |
0a7de745 | 979 | if (rate_limit_host_statistics(FALSE, flavor, info, count, &ret, &index)) { |
cc8bc92a | 980 | return ret; |
0a7de745 | 981 | } |
cc8bc92a | 982 | |
0a7de745 | 983 | if (ret != KERN_SUCCESS) { |
cc8bc92a | 984 | return ret; |
0a7de745 | 985 | } |
cc8bc92a A |
986 | |
987 | ret = host_statistics(host, flavor, info, count); | |
988 | ||
0a7de745 | 989 | if (ret == KERN_SUCCESS) { |
cc8bc92a | 990 | cache_host_statistics(index, info); |
0a7de745 | 991 | } |
cc8bc92a A |
992 | |
993 | return ret; | |
994 | } | |
995 | ||
1c79356b A |
996 | /* |
997 | * Get host statistics that require privilege. | |
998 | * None for now, just call the un-privileged version. | |
999 | */ | |
1000 | kern_return_t | |
3e170ce0 | 1001 | host_priv_statistics(host_priv_t host_priv, host_flavor_t flavor, host_info_t info, mach_msg_type_number_t * count) |
1c79356b | 1002 | { |
0a7de745 | 1003 | return host_statistics((host_t)host_priv, flavor, info, count); |
1c79356b A |
1004 | } |
1005 | ||
6d2010ae | 1006 | kern_return_t |
3e170ce0 | 1007 | set_sched_stats_active(boolean_t active) |
6d2010ae A |
1008 | { |
1009 | sched_stats_active = active; | |
0a7de745 | 1010 | return KERN_SUCCESS; |
6d2010ae A |
1011 | } |
1012 | ||
d9a64523 A |
1013 | |
1014 | uint64_t | |
1015 | get_pages_grabbed_count(void) | |
1016 | { | |
1017 | processor_t processor; | |
0a7de745 | 1018 | uint64_t pages_grabbed_count = 0; |
d9a64523 | 1019 | |
0a7de745 | 1020 | simple_lock(&processor_list_lock, LCK_GRP_NULL); |
d9a64523 A |
1021 | |
1022 | processor = processor_list; | |
1023 | ||
1024 | while (processor) { | |
0a7de745 | 1025 | pages_grabbed_count += PROCESSOR_DATA(processor, page_grab_count); |
d9a64523 A |
1026 | processor = processor->processor_list; |
1027 | } | |
1028 | simple_unlock(&processor_list_lock); | |
1029 | ||
0a7de745 | 1030 | return pages_grabbed_count; |
d9a64523 A |
1031 | } |
1032 | ||
1033 | ||
6d2010ae | 1034 | kern_return_t |
3e170ce0 | 1035 | get_sched_statistics(struct _processor_statistics_np * out, uint32_t * count) |
6d2010ae A |
1036 | { |
1037 | processor_t processor; | |
1038 | ||
1039 | if (!sched_stats_active) { | |
0a7de745 | 1040 | return KERN_FAILURE; |
6d2010ae A |
1041 | } |
1042 | ||
0a7de745 | 1043 | simple_lock(&processor_list_lock, LCK_GRP_NULL); |
3e170ce0 A |
1044 | |
1045 | if (*count < (processor_count + 1) * sizeof(struct _processor_statistics_np)) { /* One for RT */ | |
6d2010ae | 1046 | simple_unlock(&processor_list_lock); |
0a7de745 | 1047 | return KERN_FAILURE; |
6d2010ae A |
1048 | } |
1049 | ||
1050 | processor = processor_list; | |
1051 | while (processor) { | |
3e170ce0 A |
1052 | struct processor_sched_statistics * stats = &processor->processor_data.sched_stats; |
1053 | ||
1054 | out->ps_cpuid = processor->cpu_id; | |
1055 | out->ps_csw_count = stats->csw_count; | |
1056 | out->ps_preempt_count = stats->preempt_count; | |
1057 | out->ps_preempted_rt_count = stats->preempted_rt_count; | |
1058 | out->ps_preempted_by_rt_count = stats->preempted_by_rt_count; | |
1059 | out->ps_rt_sched_count = stats->rt_sched_count; | |
1060 | out->ps_interrupt_count = stats->interrupt_count; | |
1061 | out->ps_ipi_count = stats->ipi_count; | |
1062 | out->ps_timer_pop_count = stats->timer_pop_count; | |
1063 | out->ps_runq_count_sum = SCHED(processor_runq_stats_count_sum)(processor); | |
1064 | out->ps_idle_transitions = stats->idle_transitions; | |
1065 | out->ps_quantum_timer_expirations = stats->quantum_timer_expirations; | |
6d2010ae A |
1066 | |
1067 | out++; | |
1068 | processor = processor->processor_list; | |
1069 | } | |
1070 | ||
3e170ce0 | 1071 | *count = (uint32_t)(processor_count * sizeof(struct _processor_statistics_np)); |
6d2010ae A |
1072 | |
1073 | simple_unlock(&processor_list_lock); | |
1074 | ||
1075 | /* And include RT Queue information */ | |
1076 | bzero(out, sizeof(*out)); | |
1077 | out->ps_cpuid = (-1); | |
5ba3f43e | 1078 | out->ps_runq_count_sum = SCHED(rt_runq_count_sum)(); |
6d2010ae A |
1079 | out++; |
1080 | *count += (uint32_t)sizeof(struct _processor_statistics_np); | |
1081 | ||
0a7de745 | 1082 | return KERN_SUCCESS; |
6d2010ae A |
1083 | } |
1084 | ||
1c79356b | 1085 | kern_return_t |
3e170ce0 | 1086 | host_page_size(host_t host, vm_size_t * out_page_size) |
1c79356b | 1087 | { |
0a7de745 A |
1088 | if (host == HOST_NULL) { |
1089 | return KERN_INVALID_ARGUMENT; | |
1090 | } | |
1c79356b | 1091 | |
3e170ce0 | 1092 | *out_page_size = PAGE_SIZE; |
1c79356b | 1093 | |
0a7de745 | 1094 | return KERN_SUCCESS; |
1c79356b A |
1095 | } |
1096 | ||
1097 | /* | |
1098 | * Return kernel version string (more than you ever | |
1099 | * wanted to know about what version of the kernel this is). | |
1100 | */ | |
3e170ce0 | 1101 | extern char version[]; |
1c79356b A |
1102 | |
1103 | kern_return_t | |
3e170ce0 | 1104 | host_kernel_version(host_t host, kernel_version_t out_version) |
1c79356b | 1105 | { |
0a7de745 A |
1106 | if (host == HOST_NULL) { |
1107 | return KERN_INVALID_ARGUMENT; | |
1108 | } | |
1c79356b | 1109 | |
3e170ce0 | 1110 | (void)strncpy(out_version, version, sizeof(kernel_version_t)); |
1c79356b | 1111 | |
0a7de745 | 1112 | return KERN_SUCCESS; |
1c79356b A |
1113 | } |
1114 | ||
1115 | /* | |
1116 | * host_processor_sets: | |
1117 | * | |
1118 | * List all processor sets on the host. | |
1119 | */ | |
1120 | kern_return_t | |
3e170ce0 | 1121 | host_processor_sets(host_priv_t host_priv, processor_set_name_array_t * pset_list, mach_msg_type_number_t * count) |
1c79356b | 1122 | { |
3e170ce0 | 1123 | void * addr; |
1c79356b | 1124 | |
0a7de745 A |
1125 | if (host_priv == HOST_PRIV_NULL) { |
1126 | return KERN_INVALID_ARGUMENT; | |
1127 | } | |
1c79356b A |
1128 | |
1129 | /* | |
1130 | * Allocate memory. Can be pageable because it won't be | |
1131 | * touched while holding a lock. | |
1132 | */ | |
1133 | ||
3e170ce0 | 1134 | addr = kalloc((vm_size_t)sizeof(mach_port_t)); |
0a7de745 A |
1135 | if (addr == 0) { |
1136 | return KERN_RESOURCE_SHORTAGE; | |
1137 | } | |
1c79356b | 1138 | |
1c79356b | 1139 | /* do the conversion that Mig should handle */ |
3e170ce0 | 1140 | *((ipc_port_t *)addr) = convert_pset_name_to_port(&pset0); |
1c79356b A |
1141 | |
1142 | *pset_list = (processor_set_array_t)addr; | |
1143 | *count = 1; | |
1144 | ||
0a7de745 | 1145 | return KERN_SUCCESS; |
1c79356b A |
1146 | } |
1147 | ||
1148 | /* | |
1149 | * host_processor_set_priv: | |
1150 | * | |
1151 | * Return control port for given processor set. | |
1152 | */ | |
1153 | kern_return_t | |
3e170ce0 | 1154 | host_processor_set_priv(host_priv_t host_priv, processor_set_t pset_name, processor_set_t * pset) |
1c79356b | 1155 | { |
3e170ce0 | 1156 | if (host_priv == HOST_PRIV_NULL || pset_name == PROCESSOR_SET_NULL) { |
2d21ac55 A |
1157 | *pset = PROCESSOR_SET_NULL; |
1158 | ||
0a7de745 | 1159 | return KERN_INVALID_ARGUMENT; |
3e170ce0 | 1160 | } |
1c79356b | 1161 | |
3e170ce0 | 1162 | *pset = pset_name; |
2d21ac55 | 1163 | |
0a7de745 | 1164 | return KERN_SUCCESS; |
1c79356b A |
1165 | } |
1166 | ||
1167 | /* | |
1168 | * host_processor_info | |
1169 | * | |
1170 | * Return info about the processors on this host. It will return | |
1171 | * the number of processors, and the specific type of info requested | |
1172 | * in an OOL array. | |
1173 | */ | |
1174 | kern_return_t | |
3e170ce0 | 1175 | host_processor_info(host_t host, |
0a7de745 A |
1176 | processor_flavor_t flavor, |
1177 | natural_t * out_pcount, | |
1178 | processor_info_array_t * out_array, | |
1179 | mach_msg_type_number_t * out_array_count) | |
1c79356b | 1180 | { |
3e170ce0 A |
1181 | kern_return_t result; |
1182 | processor_t processor; | |
1183 | host_t thost; | |
1184 | processor_info_t info; | |
1185 | unsigned int icount, tcount; | |
1186 | unsigned int pcount, i; | |
1187 | vm_offset_t addr; | |
1188 | vm_size_t size, needed; | |
1189 | vm_map_copy_t copy; | |
1c79356b | 1190 | |
0a7de745 A |
1191 | if (host == HOST_NULL) { |
1192 | return KERN_INVALID_ARGUMENT; | |
1193 | } | |
1c79356b | 1194 | |
91447636 | 1195 | result = processor_info_count(flavor, &icount); |
0a7de745 A |
1196 | if (result != KERN_SUCCESS) { |
1197 | return result; | |
1198 | } | |
1c79356b | 1199 | |
91447636 A |
1200 | pcount = processor_count; |
1201 | assert(pcount != 0); | |
1c79356b | 1202 | |
6601e61a | 1203 | needed = pcount * icount * sizeof(natural_t); |
3e170ce0 A |
1204 | size = vm_map_round_page(needed, VM_MAP_PAGE_MASK(ipc_kernel_map)); |
1205 | result = kmem_alloc(ipc_kernel_map, &addr, size, VM_KERN_MEMORY_IPC); | |
0a7de745 A |
1206 | if (result != KERN_SUCCESS) { |
1207 | return KERN_RESOURCE_SHORTAGE; | |
1208 | } | |
91447636 | 1209 | |
3e170ce0 | 1210 | info = (processor_info_t)addr; |
91447636 A |
1211 | processor = processor_list; |
1212 | tcount = icount; | |
1c79356b | 1213 | |
91447636 A |
1214 | result = processor_info(processor, flavor, &thost, info, &tcount); |
1215 | if (result != KERN_SUCCESS) { | |
1c79356b | 1216 | kmem_free(ipc_kernel_map, addr, size); |
0a7de745 | 1217 | return result; |
1c79356b A |
1218 | } |
1219 | ||
91447636 A |
1220 | if (pcount > 1) { |
1221 | for (i = 1; i < pcount; i++) { | |
0a7de745 | 1222 | simple_lock(&processor_list_lock, LCK_GRP_NULL); |
91447636 A |
1223 | processor = processor->processor_list; |
1224 | simple_unlock(&processor_list_lock); | |
1225 | ||
1226 | info += icount; | |
1227 | tcount = icount; | |
1228 | result = processor_info(processor, flavor, &thost, info, &tcount); | |
1229 | if (result != KERN_SUCCESS) { | |
1c79356b | 1230 | kmem_free(ipc_kernel_map, addr, size); |
0a7de745 | 1231 | return result; |
1c79356b | 1232 | } |
1c79356b A |
1233 | } |
1234 | } | |
1235 | ||
0a7de745 | 1236 | if (size != needed) { |
3e170ce0 | 1237 | bzero((char *)addr + needed, size - needed); |
0a7de745 | 1238 | } |
6601e61a | 1239 | |
3e170ce0 | 1240 | result = vm_map_unwire(ipc_kernel_map, vm_map_trunc_page(addr, VM_MAP_PAGE_MASK(ipc_kernel_map)), |
0a7de745 | 1241 | vm_map_round_page(addr + size, VM_MAP_PAGE_MASK(ipc_kernel_map)), FALSE); |
91447636 | 1242 | assert(result == KERN_SUCCESS); |
2dced7af | 1243 | result = vm_map_copyin(ipc_kernel_map, (vm_map_address_t)addr, (vm_map_size_t)needed, TRUE, ©); |
91447636 | 1244 | assert(result == KERN_SUCCESS); |
1c79356b | 1245 | |
91447636 | 1246 | *out_pcount = pcount; |
3e170ce0 | 1247 | *out_array = (processor_info_array_t)copy; |
91447636 A |
1248 | *out_array_count = pcount * icount; |
1249 | ||
0a7de745 | 1250 | return KERN_SUCCESS; |
1c79356b A |
1251 | } |
1252 | ||
d9a64523 A |
1253 | static bool |
1254 | is_valid_host_special_port(int id) | |
1255 | { | |
1256 | return (id <= HOST_MAX_SPECIAL_PORT) && | |
1257 | (id >= HOST_MIN_SPECIAL_PORT) && | |
1258 | ((id <= HOST_LAST_SPECIAL_KERNEL_PORT) || (id > HOST_MAX_SPECIAL_KERNEL_PORT)); | |
1259 | } | |
1260 | ||
1c79356b | 1261 | /* |
55e303ae | 1262 | * Kernel interface for setting a special port. |
1c79356b A |
1263 | */ |
1264 | kern_return_t | |
3e170ce0 | 1265 | kernel_set_special_port(host_priv_t host_priv, int id, ipc_port_t port) |
1c79356b | 1266 | { |
55e303ae A |
1267 | ipc_port_t old_port; |
1268 | ||
0a7de745 | 1269 | if (!is_valid_host_special_port(id)) { |
d9a64523 | 1270 | panic("attempted to set invalid special port %d", id); |
0a7de745 | 1271 | } |
d9a64523 | 1272 | |
39037602 | 1273 | #if !MACH_FLIPC |
0a7de745 A |
1274 | if (id == HOST_NODE_PORT) { |
1275 | return KERN_NOT_SUPPORTED; | |
1276 | } | |
39037602 A |
1277 | #endif |
1278 | ||
55e303ae A |
1279 | host_lock(host_priv); |
1280 | old_port = host_priv->special[id]; | |
94ff46dc A |
1281 | if ((id == HOST_AMFID_PORT) && (task_pid(current_task()) != 1)) { |
1282 | host_unlock(host_priv); | |
1283 | return KERN_NO_ACCESS; | |
1284 | } | |
55e303ae A |
1285 | host_priv->special[id] = port; |
1286 | host_unlock(host_priv); | |
39037602 A |
1287 | |
1288 | #if MACH_FLIPC | |
0a7de745 | 1289 | if (id == HOST_NODE_PORT) { |
39037602 | 1290 | mach_node_port_changed(); |
0a7de745 | 1291 | } |
39037602 A |
1292 | #endif |
1293 | ||
0a7de745 | 1294 | if (IP_VALID(old_port)) { |
55e303ae | 1295 | ipc_port_release_send(old_port); |
0a7de745 A |
1296 | } |
1297 | return KERN_SUCCESS; | |
1c79356b A |
1298 | } |
1299 | ||
39037602 A |
1300 | /* |
1301 | * Kernel interface for retrieving a special port. | |
1302 | */ | |
1303 | kern_return_t | |
1304 | kernel_get_special_port(host_priv_t host_priv, int id, ipc_port_t * portp) | |
1305 | { | |
0a7de745 | 1306 | if (!is_valid_host_special_port(id)) { |
d9a64523 | 1307 | panic("attempted to get invalid special port %d", id); |
0a7de745 | 1308 | } |
d9a64523 A |
1309 | |
1310 | host_lock(host_priv); | |
1311 | *portp = host_priv->special[id]; | |
1312 | host_unlock(host_priv); | |
0a7de745 | 1313 | return KERN_SUCCESS; |
39037602 A |
1314 | } |
1315 | ||
1c79356b A |
1316 | /* |
1317 | * User interface for setting a special port. | |
1318 | * | |
1319 | * Only permits the user to set a user-owned special port | |
1320 | * ID, rejecting a kernel-owned special port ID. | |
1321 | * | |
1322 | * A special kernel port cannot be set up using this | |
1323 | * routine; use kernel_set_special_port() instead. | |
1324 | */ | |
1325 | kern_return_t | |
3e170ce0 | 1326 | host_set_special_port(host_priv_t host_priv, int id, ipc_port_t port) |
1c79356b | 1327 | { |
0a7de745 A |
1328 | if (host_priv == HOST_PRIV_NULL || id <= HOST_MAX_SPECIAL_KERNEL_PORT || id > HOST_MAX_SPECIAL_PORT) { |
1329 | return KERN_INVALID_ARGUMENT; | |
1330 | } | |
55e303ae | 1331 | |
cb323159 A |
1332 | if (task_is_driver(current_task())) { |
1333 | return KERN_NO_ACCESS; | |
1334 | } | |
1335 | ||
3e170ce0 | 1336 | #if CONFIG_MACF |
0a7de745 A |
1337 | if (mac_task_check_set_host_special_port(current_task(), id, port) != 0) { |
1338 | return KERN_NO_ACCESS; | |
1339 | } | |
3e170ce0 | 1340 | #endif |
1c79356b | 1341 | |
0a7de745 | 1342 | return kernel_set_special_port(host_priv, id, port); |
3e170ce0 | 1343 | } |
1c79356b A |
1344 | |
1345 | /* | |
1346 | * User interface for retrieving a special port. | |
1347 | * | |
1c79356b A |
1348 | * Note that there is nothing to prevent a user special |
1349 | * port from disappearing after it has been discovered by | |
1350 | * the caller; thus, using a special port can always result | |
1351 | * in a "port not valid" error. | |
1352 | */ | |
1353 | ||
1354 | kern_return_t | |
3e170ce0 | 1355 | host_get_special_port(host_priv_t host_priv, __unused int node, int id, ipc_port_t * portp) |
1c79356b | 1356 | { |
3e170ce0 | 1357 | ipc_port_t port; |
55e303ae | 1358 | |
0a7de745 A |
1359 | if (host_priv == HOST_PRIV_NULL || id == HOST_SECURITY_PORT || id > HOST_MAX_SPECIAL_PORT || id < HOST_MIN_SPECIAL_PORT) { |
1360 | return KERN_INVALID_ARGUMENT; | |
1361 | } | |
55e303ae | 1362 | |
cb323159 A |
1363 | task_t task = current_task(); |
1364 | if (task && task_is_driver(task) && id > HOST_MAX_SPECIAL_KERNEL_PORT) { | |
1365 | /* allow HID drivers to get the sysdiagnose port for keychord handling */ | |
1366 | if (IOTaskHasEntitlement(task, kIODriverKitHIDFamilyEventServiceEntitlementKey) && | |
1367 | id == HOST_SYSDIAGNOSE_PORT) { | |
1368 | goto get_special_port; | |
1369 | } | |
1370 | return KERN_NO_ACCESS; | |
1371 | } | |
1372 | ||
1373 | get_special_port: | |
55e303ae A |
1374 | host_lock(host_priv); |
1375 | port = realhost.special[id]; | |
1376 | *portp = ipc_port_copy_send(port); | |
1377 | host_unlock(host_priv); | |
1378 | ||
0a7de745 | 1379 | return KERN_SUCCESS; |
55e303ae A |
1380 | } |
1381 | ||
55e303ae | 1382 | /* |
3e170ce0 | 1383 | * host_get_io_master |
55e303ae A |
1384 | * |
1385 | * Return the IO master access port for this host. | |
1386 | */ | |
1387 | kern_return_t | |
3e170ce0 | 1388 | host_get_io_master(host_t host, io_master_t * io_masterp) |
55e303ae | 1389 | { |
0a7de745 A |
1390 | if (host == HOST_NULL) { |
1391 | return KERN_INVALID_ARGUMENT; | |
1392 | } | |
55e303ae | 1393 | |
0a7de745 | 1394 | return host_get_io_master_port(host_priv_self(), io_masterp); |
1c79356b A |
1395 | } |
1396 | ||
1397 | host_t | |
1398 | host_self(void) | |
1399 | { | |
0a7de745 | 1400 | return &realhost; |
1c79356b A |
1401 | } |
1402 | ||
1403 | host_priv_t | |
1404 | host_priv_self(void) | |
1405 | { | |
0a7de745 | 1406 | return &realhost; |
1c79356b A |
1407 | } |
1408 | ||
1409 | host_security_t | |
1410 | host_security_self(void) | |
1411 | { | |
0a7de745 | 1412 | return &realhost; |
3e170ce0 A |
1413 | } |
1414 | ||
1415 | kern_return_t | |
c6bf4f31 | 1416 | host_set_atm_diagnostic_flag(host_t host, uint32_t diagnostic_flag) |
3e170ce0 | 1417 | { |
c6bf4f31 | 1418 | if (host == HOST_NULL) { |
0a7de745 A |
1419 | return KERN_INVALID_ARGUMENT; |
1420 | } | |
3e170ce0 | 1421 | |
c6bf4f31 A |
1422 | if (!IOTaskHasEntitlement(current_task(), "com.apple.private.set-atm-diagnostic-flag")) { |
1423 | return KERN_NO_ACCESS; | |
1424 | } | |
3e170ce0 A |
1425 | |
1426 | #if CONFIG_ATM | |
0a7de745 | 1427 | return atm_set_diagnostic_config(diagnostic_flag); |
3e170ce0 A |
1428 | #else |
1429 | (void)diagnostic_flag; | |
0a7de745 | 1430 | return KERN_NOT_SUPPORTED; |
3e170ce0 | 1431 | #endif |
1c79356b | 1432 | } |
490019cf A |
1433 | |
1434 | kern_return_t | |
1435 | host_set_multiuser_config_flags(host_priv_t host_priv, uint32_t multiuser_config) | |
1436 | { | |
5ba3f43e | 1437 | #if CONFIG_EMBEDDED |
0a7de745 A |
1438 | if (host_priv == HOST_PRIV_NULL) { |
1439 | return KERN_INVALID_ARGUMENT; | |
1440 | } | |
5ba3f43e A |
1441 | |
1442 | assert(host_priv == &realhost); | |
1443 | ||
1444 | /* | |
1445 | * Always enforce that the multiuser bit is set | |
1446 | * if a value is written to the commpage word. | |
1447 | */ | |
1448 | commpage_update_multiuser_config(multiuser_config | kIsMultiUserDevice); | |
0a7de745 | 1449 | return KERN_SUCCESS; |
5ba3f43e | 1450 | #else |
490019cf A |
1451 | (void)host_priv; |
1452 | (void)multiuser_config; | |
0a7de745 | 1453 | return KERN_NOT_SUPPORTED; |
5ba3f43e | 1454 | #endif |
490019cf | 1455 | } |