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