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