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