]> git.saurik.com Git - apple/xnu.git/blob - osfmk/kern/host.c
2d13930a1aa185972f69bdef42bd21f70690c5a9
[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 * Gestalt for various trap facilities.
233 */
234 case HOST_MACH_MSG_TRAP:
235 case HOST_SEMAPHORE_TRAPS:
236 {
237 *count = 0;
238 return KERN_SUCCESS;
239 }
240
241 default:
242 return(KERN_INVALID_ARGUMENT);
243 }
244 }
245
246 kern_return_t
247 host_statistics(
248 host_t host,
249 host_flavor_t flavor,
250 host_info_t info,
251 mach_msg_type_number_t *count)
252 {
253
254 if (host == HOST_NULL)
255 return(KERN_INVALID_HOST);
256
257 switch(flavor) {
258
259 case HOST_LOAD_INFO: {
260 register host_load_info_t load_info;
261 extern uint32_t avenrun[3], mach_factor[3];
262
263 if (*count < HOST_LOAD_INFO_COUNT)
264 return(KERN_FAILURE);
265
266 load_info = (host_load_info_t) info;
267
268 bcopy((char *) avenrun,
269 (char *) load_info->avenrun,
270 sizeof avenrun);
271 bcopy((char *) mach_factor,
272 (char *) load_info->mach_factor,
273 sizeof mach_factor);
274
275 *count = HOST_LOAD_INFO_COUNT;
276 return(KERN_SUCCESS);
277 }
278
279 case HOST_VM_INFO: {
280 register vm_statistics_t stat;
281 vm_statistics_data_t host_vm_stat;
282 extern int vm_page_free_count, vm_page_active_count,
283 vm_page_inactive_count, vm_page_wire_count;
284
285 if (*count < HOST_VM_INFO_COUNT)
286 return(KERN_FAILURE);
287
288 stat = &vm_stat[0];
289 host_vm_stat = *stat;
290 #if NCPUS > 1
291 {
292 register int i;
293
294 for (i = 1; i < NCPUS; i++) {
295 stat++;
296 host_vm_stat.zero_fill_count +=
297 stat->zero_fill_count;
298 host_vm_stat.reactivations +=
299 stat->reactivations;
300 host_vm_stat.pageins += stat->pageins;
301 host_vm_stat.pageouts += stat->pageouts;
302 host_vm_stat.faults += stat->faults;
303 host_vm_stat.cow_faults += stat->cow_faults;
304 host_vm_stat.lookups += stat->lookups;
305 host_vm_stat.hits += stat->hits;
306 }
307 }
308 #endif
309
310 stat = (vm_statistics_t) info;
311
312 stat->free_count = vm_page_free_count;
313 stat->active_count = vm_page_active_count;
314 stat->inactive_count = vm_page_inactive_count;
315 stat->wire_count = vm_page_wire_count;
316 stat->zero_fill_count = host_vm_stat.zero_fill_count;
317 stat->reactivations = host_vm_stat.reactivations;
318 stat->pageins = host_vm_stat.pageins;
319 stat->pageouts = host_vm_stat.pageouts;
320 stat->faults = host_vm_stat.faults;
321 stat->cow_faults = host_vm_stat.cow_faults;
322 stat->lookups = host_vm_stat.lookups;
323 stat->hits = host_vm_stat.hits;
324
325 *count = HOST_VM_INFO_COUNT;
326 return(KERN_SUCCESS);
327 }
328
329 case HOST_CPU_LOAD_INFO: {
330 host_cpu_load_info_t cpu_load_info;
331 unsigned long ticks_value1, ticks_value2;
332 int i;
333
334 #define GET_TICKS_VALUE(__cpu,__state) \
335 MACRO_BEGIN \
336 do { \
337 ticks_value1 = *(volatile integer_t *) \
338 (&machine_slot[(__cpu)].cpu_ticks[(__state)]); \
339 ticks_value2 = *(volatile integer_t *) \
340 (&machine_slot[(__cpu)].cpu_ticks[(__state)]); \
341 } while (ticks_value1 != ticks_value2); \
342 cpu_load_info->cpu_ticks[(__state)] += ticks_value1; \
343 MACRO_END
344
345 if (*count < HOST_CPU_LOAD_INFO_COUNT)
346 return KERN_FAILURE;
347
348 cpu_load_info = (host_cpu_load_info_t) info;
349
350 cpu_load_info->cpu_ticks[CPU_STATE_USER] = 0;
351 cpu_load_info->cpu_ticks[CPU_STATE_NICE] = 0;
352 cpu_load_info->cpu_ticks[CPU_STATE_SYSTEM] = 0;
353 cpu_load_info->cpu_ticks[CPU_STATE_IDLE] = 0;
354 for (i = 0; i < NCPUS; i++) {
355 if (!machine_slot[i].is_cpu ||
356 !machine_slot[i].running)
357 continue;
358 GET_TICKS_VALUE(i, CPU_STATE_USER);
359 GET_TICKS_VALUE(i, CPU_STATE_NICE);
360 GET_TICKS_VALUE(i, CPU_STATE_SYSTEM);
361 GET_TICKS_VALUE(i, CPU_STATE_IDLE);
362 }
363
364 *count = HOST_CPU_LOAD_INFO_COUNT;
365 return KERN_SUCCESS;
366 }
367
368 default:
369 return(KERN_INVALID_ARGUMENT);
370 }
371 }
372
373 /*
374 * Get host statistics that require privilege.
375 * None for now, just call the un-privileged version.
376 */
377 kern_return_t
378 host_priv_statistics(
379 host_priv_t host_priv,
380 host_flavor_t flavor,
381 host_info_t info,
382 mach_msg_type_number_t *count)
383 {
384 return(host_statistics((host_t)host_priv, flavor, info, count));
385 }
386
387
388 kern_return_t
389 host_page_size(
390 host_t host,
391 vm_size_t *out_page_size)
392 {
393 if (host == HOST_NULL)
394 return(KERN_INVALID_ARGUMENT);
395
396 *out_page_size = PAGE_SIZE;
397
398 return(KERN_SUCCESS);
399 }
400
401 /*
402 * Return kernel version string (more than you ever
403 * wanted to know about what version of the kernel this is).
404 */
405
406 kern_return_t
407 host_kernel_version(
408 host_t host,
409 kernel_version_t out_version)
410 {
411 extern char version[];
412
413 if (host == HOST_NULL)
414 return(KERN_INVALID_ARGUMENT);
415
416 (void) strncpy(out_version, version, sizeof(kernel_version_t));
417
418 return(KERN_SUCCESS);
419 }
420
421 /*
422 * host_processor_sets:
423 *
424 * List all processor sets on the host.
425 */
426 kern_return_t
427 host_processor_sets(
428 host_priv_t host_priv,
429 processor_set_name_array_t *pset_list,
430 mach_msg_type_number_t *count)
431 {
432 vm_offset_t addr;
433
434 if (host_priv == HOST_PRIV_NULL)
435 return KERN_INVALID_ARGUMENT;
436
437 /*
438 * Allocate memory. Can be pageable because it won't be
439 * touched while holding a lock.
440 */
441
442 addr = kalloc((vm_size_t) sizeof(mach_port_t));
443 if (addr == 0)
444 return KERN_RESOURCE_SHORTAGE;
445
446 /* take ref for convert_pset_name_to_port */
447 pset_reference(&default_pset);
448 /* do the conversion that Mig should handle */
449 *((ipc_port_t *) addr) = convert_pset_name_to_port(&default_pset);
450
451 *pset_list = (processor_set_array_t)addr;
452 *count = 1;
453
454 return KERN_SUCCESS;
455 }
456
457 /*
458 * host_processor_set_priv:
459 *
460 * Return control port for given processor set.
461 */
462 kern_return_t
463 host_processor_set_priv(
464 host_priv_t host_priv,
465 processor_set_t pset_name,
466 processor_set_t *pset)
467 {
468 if ((host_priv == HOST_PRIV_NULL) || (pset_name == PROCESSOR_SET_NULL)) {
469 *pset = PROCESSOR_SET_NULL;
470 return(KERN_INVALID_ARGUMENT);
471 }
472
473 *pset = pset_name;
474 pset_reference(*pset);
475 return(KERN_SUCCESS);
476 }
477
478 /*
479 * host_processor_info
480 *
481 * Return info about the processors on this host. It will return
482 * the number of processors, and the specific type of info requested
483 * in an OOL array.
484 */
485 kern_return_t
486 host_processor_info(
487 host_t host,
488 processor_flavor_t flavor,
489 natural_t *proc_count,
490 processor_info_array_t *proc_info,
491 mach_msg_type_number_t *proc_info_count)
492 {
493 int i;
494 int num;
495 int count;
496 vm_size_t size;
497 vm_offset_t addr;
498 kern_return_t kr;
499 vm_map_copy_t copy;
500 processor_info_t proc_data;
501
502 if (host == HOST_NULL)
503 return KERN_INVALID_ARGUMENT;
504
505 kr = processor_info_count(flavor, &count);
506 if (kr != KERN_SUCCESS) {
507 return kr;
508 }
509
510 for (num = i = 0; i < NCPUS; i++)
511 if (machine_slot[i].is_cpu)
512 num++;
513
514 size = (vm_size_t)round_page(num * count * sizeof(natural_t));
515
516 kr = vm_allocate(ipc_kernel_map, &addr, size, TRUE);
517 if (kr != KERN_SUCCESS)
518 return KERN_RESOURCE_SHORTAGE;
519
520 kr = vm_map_wire(ipc_kernel_map, addr, addr + size,
521 VM_PROT_READ|VM_PROT_WRITE, FALSE);
522 if (kr != KERN_SUCCESS) {
523 kmem_free(ipc_kernel_map, addr, size);
524 return KERN_RESOURCE_SHORTAGE;
525 }
526
527 proc_data = (processor_info_t) addr;
528 for (i = 0; i < NCPUS; i++) {
529 int count2 = count;
530 host_t host2;
531
532 if (machine_slot[i].is_cpu) {
533 kr = processor_info(cpu_to_processor(i),
534 flavor,
535 &host2,
536 proc_data,
537 &count2);
538 if (kr != KERN_SUCCESS) {
539 kmem_free(ipc_kernel_map, addr, size);
540 return kr;
541 }
542 assert(count == count2);
543 proc_data += count;
544 }
545 }
546
547 kr = vm_map_unwire(ipc_kernel_map, addr, addr + size, FALSE);
548 assert(kr == KERN_SUCCESS);
549 size = (vm_size_t)(num * count * sizeof(natural_t));
550 kr = vm_map_copyin(ipc_kernel_map, addr, size, TRUE, &copy);
551 assert(kr == KERN_SUCCESS);
552
553 *proc_count = num;
554 *proc_info = (processor_info_array_t) copy;
555 *proc_info_count = num * count;
556 return(KERN_SUCCESS);
557 }
558
559
560 /*
561 * host_get_io_master
562 *
563 * Return the IO master access port for this host.
564 */
565 kern_return_t
566 host_get_io_master(
567 host_t host,
568 io_master_t *io_master)
569 {
570 if (host == HOST_NULL)
571 return KERN_INVALID_ARGUMENT;
572 *io_master = ipc_port_copy_send(realhost.io_master);
573 return KERN_SUCCESS;
574 }
575
576 #define io_master_deallocate(x)
577
578 /*
579 * host_get_io_master
580 *
581 * Return the IO master access port for this host.
582 */
583 kern_return_t
584 host_set_io_master(
585 host_priv_t host_priv,
586 io_master_t io_master)
587 {
588 io_master_t old_master;
589
590 if (host_priv == HOST_PRIV_NULL)
591 return KERN_INVALID_ARGUMENT;
592
593 old_master = realhost.io_master;
594 realhost.io_master = io_master;
595 io_master_deallocate(old_master);
596 return KERN_SUCCESS;
597 }
598
599 /*
600 * User interface for setting a special port.
601 *
602 * Only permits the user to set a user-owned special port
603 * ID, rejecting a kernel-owned special port ID.
604 *
605 * A special kernel port cannot be set up using this
606 * routine; use kernel_set_special_port() instead.
607 */
608 kern_return_t
609 host_set_special_port(
610 host_priv_t host_priv,
611 int id,
612 ipc_port_t port)
613 {
614 #if DIPC
615 return norma_set_special_port(host_priv, id, port);
616 #else
617 return KERN_FAILURE;
618 #endif
619 }
620
621
622 /*
623 * User interface for retrieving a special port.
624 *
625 * When all processing is local, this call does not block.
626 * If processing goes remote to discover a remote UID,
627 * this call blocks but not indefinitely. If the remote
628 * node does not exist, has panic'ed, or is booting but
629 * hasn't yet turned on DIPC, then we expect the transport
630 * to return an error.
631 *
632 * This routine always returns SUCCESS, even if there's
633 * no resulting port.
634 *
635 * Note that there is nothing to prevent a user special
636 * port from disappearing after it has been discovered by
637 * the caller; thus, using a special port can always result
638 * in a "port not valid" error.
639 */
640
641 kern_return_t
642 host_get_special_port(
643 host_priv_t host_priv,
644 int node,
645 int id,
646 ipc_port_t *portp)
647 {
648 #if DIPC
649 return norma_get_special_port(host_priv, node, id, portp);
650 #else
651 return KERN_FAILURE;
652 #endif
653 }
654
655 host_t
656 host_self(void)
657 {
658 return &realhost;
659 }
660
661 host_priv_t
662 host_priv_self(void)
663 {
664 return &realhost;
665 }
666
667 host_security_t
668 host_security_self(void)
669 {
670 return &realhost;
671 }
672