]> git.saurik.com Git - apple/xnu.git/blob - osfmk/kern/host.c
96aed635440ddcf5add7671cb93f1544cdb5e801
[apple/xnu.git] / osfmk / kern / host.c
1 /*
2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_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. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23 /*
24 * @OSF_COPYRIGHT@
25 */
26 /*
27 * Mach Operating System
28 * Copyright (c) 1991,1990,1989,1988 Carnegie Mellon University
29 * All Rights Reserved.
30 *
31 * Permission to use, copy, modify and distribute this software and its
32 * documentation is hereby granted, provided that both the copyright
33 * notice and this permission notice appear in all copies of the
34 * software, derivative works or modified versions, and any portions
35 * thereof, and that both notices appear in supporting documentation.
36 *
37 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
38 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
39 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
40 *
41 * Carnegie Mellon requests users of this software to return to
42 *
43 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
44 * School of Computer Science
45 * Carnegie Mellon University
46 * Pittsburgh PA 15213-3890
47 *
48 * any improvements or extensions that they make and grant Carnegie Mellon
49 * the rights to redistribute these changes.
50 */
51 /*
52 */
53
54 /*
55 * host.c
56 *
57 * Non-ipc host functions.
58 */
59
60 #include <mach_host.h>
61
62 #include <mach/mach_types.h>
63 #include <mach/boolean.h>
64 #include <mach/host_info.h>
65 #include <mach/host_special_ports.h>
66 #include <mach/kern_return.h>
67 #include <mach/machine.h>
68 #include <mach/port.h>
69 #include <mach/processor_info.h>
70 #include <mach/vm_param.h>
71 #include <mach/processor.h>
72 #include <mach/mach_host_server.h>
73 #include <mach/host_priv_server.h>
74 #include <mach/vm_map.h>
75
76 #include <kern/kern_types.h>
77 #include <kern/assert.h>
78 #include <kern/kalloc.h>
79 #include <kern/host.h>
80 #include <kern/host_statistics.h>
81 #include <kern/ipc_host.h>
82 #include <kern/misc_protos.h>
83 #include <kern/sched.h>
84 #include <kern/processor.h>
85
86 #include <vm/vm_map.h>
87
88 #if DIPC
89 #include <dipc/dipc_funcs.h>
90 #include <dipc/special_ports.h>
91 #endif
92
93 host_data_t realhost;
94
95 kern_return_t
96 host_processors(
97 host_priv_t host_priv,
98 processor_array_t *out_array,
99 mach_msg_type_number_t *countp)
100 {
101 register processor_t processor, *tp;
102 void *addr;
103 unsigned int count, i;
104
105 if (host_priv == HOST_PRIV_NULL)
106 return (KERN_INVALID_ARGUMENT);
107
108 assert(host_priv == &realhost);
109
110 count = processor_count;
111 assert(count != 0);
112
113 addr = kalloc((vm_size_t) (count * sizeof(mach_port_t)));
114 if (addr == 0)
115 return (KERN_RESOURCE_SHORTAGE);
116
117 tp = (processor_t *) addr;
118 *tp++ = processor = processor_list;
119
120 if (count > 1) {
121 simple_lock(&processor_list_lock);
122
123 for (i = 1; i < count; i++)
124 *tp++ = processor = processor->processor_list;
125
126 simple_unlock(&processor_list_lock);
127 }
128
129 *countp = count;
130 *out_array = (processor_array_t)addr;
131
132 /* do the conversion that Mig should handle */
133
134 tp = (processor_t *) addr;
135 for (i = 0; i < count; i++)
136 ((mach_port_t *) tp)[i] =
137 (mach_port_t)convert_processor_to_port(tp[i]);
138
139 return (KERN_SUCCESS);
140 }
141
142 kern_return_t
143 host_info(
144 host_t host,
145 host_flavor_t flavor,
146 host_info_t info,
147 mach_msg_type_number_t *count)
148 {
149
150 if (host == HOST_NULL)
151 return (KERN_INVALID_ARGUMENT);
152
153 switch (flavor) {
154
155 case HOST_BASIC_INFO:
156 {
157 register host_basic_info_t basic_info;
158 register int master_slot;
159
160 /*
161 * Basic information about this host.
162 */
163 if (*count < HOST_BASIC_INFO_OLD_COUNT)
164 return (KERN_FAILURE);
165
166 basic_info = (host_basic_info_t) info;
167
168 basic_info->max_cpus = machine_info.max_cpus;
169 basic_info->avail_cpus = machine_info.avail_cpus;
170 basic_info->memory_size = machine_info.memory_size;
171 master_slot = PROCESSOR_DATA(master_processor, slot_num);
172 basic_info->cpu_type = slot_type(master_slot);
173 basic_info->cpu_subtype = slot_subtype(master_slot);
174
175 if (*count >= HOST_BASIC_INFO_COUNT) {
176 basic_info->cpu_threadtype = slot_threadtype(master_slot);
177 basic_info->physical_cpu = machine_info.physical_cpu;
178 basic_info->physical_cpu_max = machine_info.physical_cpu_max;
179 basic_info->logical_cpu = machine_info.logical_cpu;
180 basic_info->logical_cpu_max = machine_info.logical_cpu_max;
181 basic_info->max_mem = machine_info.max_mem;
182
183 *count = HOST_BASIC_INFO_COUNT;
184 } else {
185 *count = HOST_BASIC_INFO_OLD_COUNT;
186 }
187
188 return (KERN_SUCCESS);
189 }
190
191 case HOST_SCHED_INFO:
192 {
193 register host_sched_info_t sched_info;
194
195 /*
196 * Return scheduler information.
197 */
198 if (*count < HOST_SCHED_INFO_COUNT)
199 return (KERN_FAILURE);
200
201 sched_info = (host_sched_info_t) info;
202
203 sched_info->min_timeout =
204 sched_info->min_quantum = std_quantum_us / 1000;
205
206 *count = HOST_SCHED_INFO_COUNT;
207
208 return (KERN_SUCCESS);
209 }
210
211 case HOST_RESOURCE_SIZES:
212 {
213 /*
214 * Return sizes of kernel data structures
215 */
216 if (*count < HOST_RESOURCE_SIZES_COUNT)
217 return (KERN_FAILURE);
218
219 /* XXX Fail until ledgers are implemented */
220 return (KERN_INVALID_ARGUMENT);
221 }
222
223 case HOST_PRIORITY_INFO:
224 {
225 register host_priority_info_t priority_info;
226
227 if (*count < HOST_PRIORITY_INFO_COUNT)
228 return (KERN_FAILURE);
229
230 priority_info = (host_priority_info_t) info;
231
232 priority_info->kernel_priority = MINPRI_KERNEL;
233 priority_info->system_priority = MINPRI_KERNEL;
234 priority_info->server_priority = MINPRI_RESERVED;
235 priority_info->user_priority = BASEPRI_DEFAULT;
236 priority_info->depress_priority = DEPRESSPRI;
237 priority_info->idle_priority = IDLEPRI;
238 priority_info->minimum_priority = MINPRI_USER;
239 priority_info->maximum_priority = MAXPRI_RESERVED;
240
241 *count = HOST_PRIORITY_INFO_COUNT;
242
243 return (KERN_SUCCESS);
244 }
245
246 /*
247 * Gestalt for various trap facilities.
248 */
249 case HOST_MACH_MSG_TRAP:
250 case HOST_SEMAPHORE_TRAPS:
251 {
252 *count = 0;
253 return (KERN_SUCCESS);
254 }
255
256 default:
257 return (KERN_INVALID_ARGUMENT);
258 }
259 }
260
261 kern_return_t
262 host_statistics(
263 host_t host,
264 host_flavor_t flavor,
265 host_info_t info,
266 mach_msg_type_number_t *count)
267 {
268
269 if (host == HOST_NULL)
270 return (KERN_INVALID_HOST);
271
272 switch(flavor) {
273
274 case HOST_LOAD_INFO:
275 {
276 host_load_info_t load_info;
277
278 if (*count < HOST_LOAD_INFO_COUNT)
279 return (KERN_FAILURE);
280
281 load_info = (host_load_info_t) info;
282
283 bcopy((char *) avenrun,
284 (char *) load_info->avenrun, sizeof avenrun);
285 bcopy((char *) mach_factor,
286 (char *) load_info->mach_factor, sizeof mach_factor);
287
288 *count = HOST_LOAD_INFO_COUNT;
289 return (KERN_SUCCESS);
290 }
291
292 case HOST_VM_INFO:
293 {
294 register processor_t processor;
295 register vm_statistics_t stat;
296 vm_statistics_data_t host_vm_stat;
297
298 if (*count < HOST_VM_INFO_REV0_COUNT)
299 return (KERN_FAILURE);
300
301 processor = processor_list;
302 stat = &PROCESSOR_DATA(processor, vm_stat);
303 host_vm_stat = *stat;
304
305 if (processor_count > 1) {
306 simple_lock(&processor_list_lock);
307
308 while ((processor = processor->processor_list) != NULL) {
309 stat = &PROCESSOR_DATA(processor, vm_stat);
310
311 host_vm_stat.zero_fill_count += stat->zero_fill_count;
312 host_vm_stat.reactivations += stat->reactivations;
313 host_vm_stat.pageins += stat->pageins;
314 host_vm_stat.pageouts += stat->pageouts;
315 host_vm_stat.faults += stat->faults;
316 host_vm_stat.cow_faults += stat->cow_faults;
317 host_vm_stat.lookups += stat->lookups;
318 host_vm_stat.hits += stat->hits;
319 }
320
321 simple_unlock(&processor_list_lock);
322 }
323
324 stat = (vm_statistics_t) info;
325
326 stat->free_count = vm_page_free_count;
327 stat->active_count = vm_page_active_count;
328 stat->inactive_count = vm_page_inactive_count;
329 stat->wire_count = vm_page_wire_count;
330 stat->zero_fill_count = host_vm_stat.zero_fill_count;
331 stat->reactivations = host_vm_stat.reactivations;
332 stat->pageins = host_vm_stat.pageins;
333 stat->pageouts = host_vm_stat.pageouts;
334 stat->faults = host_vm_stat.faults;
335 stat->cow_faults = host_vm_stat.cow_faults;
336 stat->lookups = host_vm_stat.lookups;
337 stat->hits = host_vm_stat.hits;
338
339 if (*count >= HOST_VM_INFO_COUNT) {
340 /* info that was not in revision 0 of that interface */
341 stat->purgeable_count = vm_page_purgeable_count;
342 stat->purges = vm_page_purged_count;
343 *count = HOST_VM_INFO_COUNT;
344 } else {
345 *count = HOST_VM_INFO_REV0_COUNT;
346 }
347
348 return (KERN_SUCCESS);
349 }
350
351 case HOST_CPU_LOAD_INFO:
352 {
353 register processor_t processor;
354 host_cpu_load_info_t cpu_load_info;
355 unsigned long ticks_value1, ticks_value2;
356
357 if (*count < HOST_CPU_LOAD_INFO_COUNT)
358 return (KERN_FAILURE);
359
360 #define GET_TICKS_VALUE(processor, state) \
361 MACRO_BEGIN \
362 do { \
363 ticks_value1 = *(volatile integer_t *) \
364 &PROCESSOR_DATA((processor), cpu_ticks[(state)]); \
365 ticks_value2 = *(volatile integer_t *) \
366 &PROCESSOR_DATA((processor), cpu_ticks[(state)]); \
367 } while (ticks_value1 != ticks_value2); \
368 \
369 cpu_load_info->cpu_ticks[(state)] += ticks_value1; \
370 MACRO_END
371
372 cpu_load_info = (host_cpu_load_info_t)info;
373 cpu_load_info->cpu_ticks[CPU_STATE_USER] = 0;
374 cpu_load_info->cpu_ticks[CPU_STATE_NICE] = 0;
375 cpu_load_info->cpu_ticks[CPU_STATE_SYSTEM] = 0;
376 cpu_load_info->cpu_ticks[CPU_STATE_IDLE] = 0;
377
378 processor = processor_list;
379 GET_TICKS_VALUE(processor, CPU_STATE_USER);
380 GET_TICKS_VALUE(processor, CPU_STATE_NICE);
381 GET_TICKS_VALUE(processor, CPU_STATE_SYSTEM);
382 GET_TICKS_VALUE(processor, CPU_STATE_IDLE);
383
384 if (processor_count > 1) {
385 simple_lock(&processor_list_lock);
386
387 while ((processor = processor->processor_list) != NULL) {
388 GET_TICKS_VALUE(processor, CPU_STATE_USER);
389 GET_TICKS_VALUE(processor, CPU_STATE_NICE);
390 GET_TICKS_VALUE(processor, CPU_STATE_SYSTEM);
391 GET_TICKS_VALUE(processor, CPU_STATE_IDLE);
392 }
393
394 simple_unlock(&processor_list_lock);
395 }
396
397 *count = HOST_CPU_LOAD_INFO_COUNT;
398
399 return (KERN_SUCCESS);
400 }
401
402 default:
403 return (KERN_INVALID_ARGUMENT);
404 }
405 }
406
407 /*
408 * Get host statistics that require privilege.
409 * None for now, just call the un-privileged version.
410 */
411 kern_return_t
412 host_priv_statistics(
413 host_priv_t host_priv,
414 host_flavor_t flavor,
415 host_info_t info,
416 mach_msg_type_number_t *count)
417 {
418 return(host_statistics((host_t)host_priv, flavor, info, count));
419 }
420
421
422 kern_return_t
423 host_page_size(
424 host_t host,
425 vm_size_t *out_page_size)
426 {
427 if (host == HOST_NULL)
428 return(KERN_INVALID_ARGUMENT);
429
430 *out_page_size = PAGE_SIZE;
431
432 return(KERN_SUCCESS);
433 }
434
435 /*
436 * Return kernel version string (more than you ever
437 * wanted to know about what version of the kernel this is).
438 */
439 extern char version[];
440
441 kern_return_t
442 host_kernel_version(
443 host_t host,
444 kernel_version_t out_version)
445 {
446
447 if (host == HOST_NULL)
448 return(KERN_INVALID_ARGUMENT);
449
450 (void) strncpy(out_version, version, sizeof(kernel_version_t));
451
452 return(KERN_SUCCESS);
453 }
454
455 /*
456 * host_processor_sets:
457 *
458 * List all processor sets on the host.
459 */
460 kern_return_t
461 host_processor_sets(
462 host_priv_t host_priv,
463 processor_set_name_array_t *pset_list,
464 mach_msg_type_number_t *count)
465 {
466 void *addr;
467
468 if (host_priv == HOST_PRIV_NULL)
469 return KERN_INVALID_ARGUMENT;
470
471 /*
472 * Allocate memory. Can be pageable because it won't be
473 * touched while holding a lock.
474 */
475
476 addr = kalloc((vm_size_t) sizeof(mach_port_t));
477 if (addr == 0)
478 return KERN_RESOURCE_SHORTAGE;
479
480 /* take ref for convert_pset_name_to_port */
481 pset_reference(&default_pset);
482 /* do the conversion that Mig should handle */
483 *((ipc_port_t *) addr) = convert_pset_name_to_port(&default_pset);
484
485 *pset_list = (processor_set_array_t)addr;
486 *count = 1;
487
488 return KERN_SUCCESS;
489 }
490
491 /*
492 * host_processor_set_priv:
493 *
494 * Return control port for given processor set.
495 */
496 kern_return_t
497 host_processor_set_priv(
498 host_priv_t host_priv,
499 processor_set_t pset_name,
500 processor_set_t *pset)
501 {
502 if ((host_priv == HOST_PRIV_NULL) || (pset_name == PROCESSOR_SET_NULL)) {
503 *pset = PROCESSOR_SET_NULL;
504 return(KERN_INVALID_ARGUMENT);
505 }
506
507 *pset = pset_name;
508 pset_reference(*pset);
509 return(KERN_SUCCESS);
510 }
511
512 /*
513 * host_processor_info
514 *
515 * Return info about the processors on this host. It will return
516 * the number of processors, and the specific type of info requested
517 * in an OOL array.
518 */
519 kern_return_t
520 host_processor_info(
521 host_t host,
522 processor_flavor_t flavor,
523 natural_t *out_pcount,
524 processor_info_array_t *out_array,
525 mach_msg_type_number_t *out_array_count)
526 {
527 kern_return_t result;
528 processor_t processor;
529 host_t thost;
530 processor_info_t info;
531 unsigned int icount, tcount;
532 unsigned int pcount, i;
533 vm_offset_t addr;
534 vm_size_t size;
535 vm_map_copy_t copy;
536
537 if (host == HOST_NULL)
538 return (KERN_INVALID_ARGUMENT);
539
540 result = processor_info_count(flavor, &icount);
541 if (result != KERN_SUCCESS)
542 return (result);
543
544 pcount = processor_count;
545 assert(pcount != 0);
546
547 size = round_page(pcount * icount * sizeof(natural_t));
548 result = kmem_alloc(ipc_kernel_map, &addr, size);
549 if (result != KERN_SUCCESS)
550 return (KERN_RESOURCE_SHORTAGE);
551
552 info = (processor_info_t) addr;
553 processor = processor_list;
554 tcount = icount;
555
556 result = processor_info(processor, flavor, &thost, info, &tcount);
557 if (result != KERN_SUCCESS) {
558 kmem_free(ipc_kernel_map, addr, size);
559 return (result);
560 }
561
562 if (pcount > 1) {
563 for (i = 1; i < pcount; i++) {
564 simple_lock(&processor_list_lock);
565 processor = processor->processor_list;
566 simple_unlock(&processor_list_lock);
567
568 info += icount;
569 tcount = icount;
570 result = processor_info(processor, flavor, &thost, info, &tcount);
571 if (result != KERN_SUCCESS) {
572 kmem_free(ipc_kernel_map, addr, size);
573 return (result);
574 }
575 }
576 }
577
578 result = vm_map_unwire(ipc_kernel_map, vm_map_trunc_page(addr),
579 vm_map_round_page(addr + size), FALSE);
580 assert(result == KERN_SUCCESS);
581 result = vm_map_copyin(ipc_kernel_map, (vm_map_address_t)addr,
582 (vm_map_size_t)size, TRUE, &copy);
583 assert(result == KERN_SUCCESS);
584
585 *out_pcount = pcount;
586 *out_array = (processor_info_array_t) copy;
587 *out_array_count = pcount * icount;
588
589 return (KERN_SUCCESS);
590 }
591
592 /*
593 * Kernel interface for setting a special port.
594 */
595 kern_return_t
596 kernel_set_special_port(
597 host_priv_t host_priv,
598 int id,
599 ipc_port_t port)
600 {
601 ipc_port_t old_port;
602
603 host_lock(host_priv);
604 old_port = host_priv->special[id];
605 host_priv->special[id] = port;
606 host_unlock(host_priv);
607 if (IP_VALID(old_port))
608 ipc_port_release_send(old_port);
609 return KERN_SUCCESS;
610 }
611
612 /*
613 * User interface for setting a special port.
614 *
615 * Only permits the user to set a user-owned special port
616 * ID, rejecting a kernel-owned special port ID.
617 *
618 * A special kernel port cannot be set up using this
619 * routine; use kernel_set_special_port() instead.
620 */
621 kern_return_t
622 host_set_special_port(
623 host_priv_t host_priv,
624 int id,
625 ipc_port_t port)
626 {
627 if (host_priv == HOST_PRIV_NULL ||
628 id <= HOST_MAX_SPECIAL_KERNEL_PORT || id > HOST_MAX_SPECIAL_PORT ) {
629 if (IP_VALID(port))
630 ipc_port_release_send(port);
631 return KERN_INVALID_ARGUMENT;
632 }
633
634 return kernel_set_special_port(host_priv, id, port);
635 }
636
637
638 /*
639 * User interface for retrieving a special port.
640 *
641 * Note that there is nothing to prevent a user special
642 * port from disappearing after it has been discovered by
643 * the caller; thus, using a special port can always result
644 * in a "port not valid" error.
645 */
646
647 kern_return_t
648 host_get_special_port(
649 host_priv_t host_priv,
650 __unused int node,
651 int id,
652 ipc_port_t *portp)
653 {
654 ipc_port_t port;
655
656 if (host_priv == HOST_PRIV_NULL ||
657 id == HOST_SECURITY_PORT || id > HOST_MAX_SPECIAL_PORT )
658 return KERN_INVALID_ARGUMENT;
659
660 #if DIPC
661 if (node != HOST_LOCAL_NODE)
662 return norma_get_special_port(host_priv, node, id, portp);
663 #endif
664
665 host_lock(host_priv);
666 port = realhost.special[id];
667 *portp = ipc_port_copy_send(port);
668 host_unlock(host_priv);
669
670 return KERN_SUCCESS;
671 }
672
673
674 /*
675 * host_get_io_master
676 *
677 * Return the IO master access port for this host.
678 */
679 kern_return_t
680 host_get_io_master(
681 host_t host,
682 io_master_t *io_masterp)
683 {
684 if (host == HOST_NULL)
685 return KERN_INVALID_ARGUMENT;
686
687 return (host_get_io_master_port(host_priv_self(), io_masterp));
688 }
689
690 host_t
691 host_self(void)
692 {
693 return &realhost;
694 }
695
696 host_priv_t
697 host_priv_self(void)
698 {
699 return &realhost;
700 }
701
702 host_security_t
703 host_security_self(void)
704 {
705 return &realhost;
706 }
707