]> git.saurik.com Git - apple/xnu.git/blame - osfmk/kern/processor.c
xnu-4903.231.4.tar.gz
[apple/xnu.git] / osfmk / kern / processor.c
CommitLineData
1c79356b 1/*
b0d623f7 2 * Copyright (c) 2000-2009 Apple Inc. All rights reserved.
1c79356b 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
1c79356b 5 *
2d21ac55
A
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. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
8f6c56a5 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
8f6c56a5 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b
A
27 */
28/*
29 * @OSF_COPYRIGHT@
30 */
31/*
32 * Mach Operating System
33 * Copyright (c) 1991,1990,1989,1988 Carnegie Mellon University
34 * All Rights Reserved.
35 *
36 * Permission to use, copy, modify and distribute this software and its
37 * documentation is hereby granted, provided that both the copyright
38 * notice and this permission notice appear in all copies of the
39 * software, derivative works or modified versions, and any portions
40 * thereof, and that both notices appear in supporting documentation.
41 *
42 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
43 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
44 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
45 *
46 * Carnegie Mellon requests users of this software to return to
47 *
48 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
49 * School of Computer Science
50 * Carnegie Mellon University
51 * Pittsburgh PA 15213-3890
52 *
53 * any improvements or extensions that they make and grant Carnegie Mellon
54 * the rights to redistribute these changes.
55 */
56/*
57 */
58
59/*
60 * processor.c: processor and processor_set manipulation routines.
61 */
62
1c79356b
A
63#include <mach/boolean.h>
64#include <mach/policy.h>
91447636 65#include <mach/processor.h>
1c79356b
A
66#include <mach/processor_info.h>
67#include <mach/vm_param.h>
68#include <kern/cpu_number.h>
69#include <kern/host.h>
70#include <kern/machine.h>
71#include <kern/misc_protos.h>
72#include <kern/processor.h>
73#include <kern/sched.h>
74#include <kern/task.h>
75#include <kern/thread.h>
76#include <kern/ipc_host.h>
77#include <kern/ipc_tt.h>
78#include <ipc/ipc_port.h>
79#include <kern/kalloc.h>
80
3e170ce0
A
81#include <security/mac_mach_internal.h>
82
d9a64523
A
83#if defined(CONFIG_XNUPOST)
84
85#include <tests/xnupost.h>
86
87#endif /* CONFIG_XNUPOST */
5ba3f43e 88
1c79356b
A
89/*
90 * Exported interface
91 */
92#include <mach/mach_host_server.h>
91447636 93#include <mach/processor_set_server.h>
1c79356b 94
2d21ac55
A
95struct processor_set pset0;
96struct pset_node pset_node0;
97decl_simple_lock_data(static,pset_node_lock)
98
99queue_head_t tasks;
6d2010ae 100queue_head_t terminated_tasks; /* To be used ONLY for stackshot. */
39037602 101queue_head_t corpse_tasks;
2d21ac55 102int tasks_count;
39236c6e 103int terminated_tasks_count;
2d21ac55
A
104queue_head_t threads;
105int threads_count;
b0d623f7 106decl_lck_mtx_data(,tasks_threads_lock)
39037602 107decl_lck_mtx_data(,tasks_corpse_lock)
1c79356b 108
91447636
A
109processor_t processor_list;
110unsigned int processor_count;
111static processor_t processor_list_tail;
112decl_simple_lock_data(,processor_list_lock)
9bccf70c 113
2d21ac55
A
114uint32_t processor_avail_count;
115
b0d623f7
A
116processor_t master_processor;
117int master_cpu = 0;
6d2010ae 118boolean_t sched_stats_active = FALSE;
1c79356b 119
5ba3f43e
A
120processor_t processor_array[MAX_SCHED_CPUS] = { 0 };
121
d9a64523
A
122#if defined(CONFIG_XNUPOST)
123kern_return_t ipi_test(void);
124extern void arm64_ipi_test(void);
125
126kern_return_t
127ipi_test()
128{
129#if __arm64__
130 processor_t p;
131
132 for (p = processor_list; p != NULL; p = p->processor_list) {
133 thread_bind(p);
134 thread_block(THREAD_CONTINUE_NULL);
135 kprintf("Running IPI test on cpu %d\n", p->cpu_id);
136 arm64_ipi_test();
137 }
138
139 /* unbind thread from specific cpu */
140 thread_bind(PROCESSOR_NULL);
141 thread_block(THREAD_CONTINUE_NULL);
142
143 T_PASS("Done running IPI tests");
144#else
145 T_PASS("Unsupported platform. Not running IPI tests");
146
147#endif /* __arm64__ */
148
149 return KERN_SUCCESS;
150}
151#endif /* defined(CONFIG_XNUPOST) */
5ba3f43e
A
152
153
1c79356b 154void
91447636 155processor_bootstrap(void)
1c79356b 156{
2d21ac55
A
157 pset_init(&pset0, &pset_node0);
158 pset_node0.psets = &pset0;
55e303ae 159
2d21ac55 160 simple_lock_init(&pset_node_lock, 0);
55e303ae 161
2d21ac55 162 queue_init(&tasks);
6d2010ae 163 queue_init(&terminated_tasks);
2d21ac55 164 queue_init(&threads);
39037602 165 queue_init(&corpse_tasks);
1c79356b 166
2d21ac55 167 simple_lock_init(&processor_list_lock, 0);
1c79356b 168
2d21ac55 169 master_processor = cpu_to_processor(master_cpu);
1c79356b 170
2d21ac55 171 processor_init(master_processor, master_cpu, &pset0);
1c79356b
A
172}
173
174/*
2d21ac55 175 * Initialize the given processor for the cpu
b0d623f7 176 * indicated by cpu_id, and assign to the
2d21ac55 177 * specified processor set.
1c79356b
A
178 */
179void
180processor_init(
c910b4d9 181 processor_t processor,
b0d623f7 182 int cpu_id,
c910b4d9 183 processor_set_t pset)
1c79356b 184{
bd504ef0
A
185 spl_t s;
186
6d2010ae 187 if (processor != master_processor) {
5ba3f43e 188 /* Scheduler state for master_processor initialized in sched_init() */
6d2010ae
A
189 SCHED(processor_init)(processor);
190 }
c910b4d9 191
d9a64523
A
192 assert(cpu_id < MAX_SCHED_CPUS);
193
c910b4d9
A
194 processor->state = PROCESSOR_OFF_LINE;
195 processor->active_thread = processor->next_thread = processor->idle_thread = THREAD_NULL;
196 processor->processor_set = pset;
5ba3f43e 197 processor_state_update_idle(processor);
39037602 198 processor->starting_pri = MINPRI;
b0d623f7 199 processor->cpu_id = cpu_id;
c910b4d9 200 timer_call_setup(&processor->quantum_timer, thread_quantum_expire, processor);
fe8ab488 201 processor->quantum_end = UINT64_MAX;
c910b4d9 202 processor->deadline = UINT64_MAX;
3e170ce0 203 processor->first_timeslice = FALSE;
fe8ab488
A
204 processor->processor_primary = processor; /* no SMT relationship known at this point */
205 processor->processor_secondary = NULL;
206 processor->is_SMT = FALSE;
39037602 207 processor->is_recommended = (pset->recommended_bitmask & (1ULL << cpu_id)) ? TRUE : FALSE;
c910b4d9 208 processor->processor_self = IP_NULL;
c910b4d9
A
209 processor_data_init(processor);
210 processor->processor_list = NULL;
d9a64523
A
211 processor->cpu_quiesce_state = CPU_QUIESCE_COUNTER_NONE;
212 processor->cpu_quiesce_last_checkin = 0;
91447636 213
bd504ef0 214 s = splsched();
b7266188 215 pset_lock(pset);
5ba3f43e 216 bit_set(pset->cpu_bitmask, cpu_id);
b7266188
A
217 if (pset->cpu_set_count++ == 0)
218 pset->cpu_set_low = pset->cpu_set_hi = cpu_id;
219 else {
220 pset->cpu_set_low = (cpu_id < pset->cpu_set_low)? cpu_id: pset->cpu_set_low;
221 pset->cpu_set_hi = (cpu_id > pset->cpu_set_hi)? cpu_id: pset->cpu_set_hi;
222 }
223 pset_unlock(pset);
bd504ef0 224 splx(s);
b7266188 225
91447636
A
226 simple_lock(&processor_list_lock);
227 if (processor_list == NULL)
c910b4d9 228 processor_list = processor;
91447636 229 else
c910b4d9
A
230 processor_list_tail->processor_list = processor;
231 processor_list_tail = processor;
91447636 232 processor_count++;
5ba3f43e 233 processor_array[cpu_id] = processor;
91447636 234 simple_unlock(&processor_list_lock);
9bccf70c 235}
1c79356b 236
b0d623f7 237void
fe8ab488 238processor_set_primary(
b0d623f7
A
239 processor_t processor,
240 processor_t primary)
241{
fe8ab488
A
242 assert(processor->processor_primary == primary || processor->processor_primary == processor);
243 /* Re-adjust primary point for this (possibly) secondary processor */
244 processor->processor_primary = primary;
245
246 assert(primary->processor_secondary == NULL || primary->processor_secondary == processor);
247 if (primary != processor) {
248 /* Link primary to secondary, assumes a 2-way SMT model
249 * We'll need to move to a queue if any future architecture
250 * requires otherwise.
251 */
252 assert(processor->processor_secondary == NULL);
253 primary->processor_secondary = processor;
254 /* Mark both processors as SMT siblings */
255 primary->is_SMT = TRUE;
256 processor->is_SMT = TRUE;
d9a64523
A
257
258 processor_set_t pset = processor->processor_set;
259 atomic_bit_clear(&pset->primary_map, processor->cpu_id, memory_order_relaxed);
b0d623f7 260 }
b0d623f7
A
261}
262
2d21ac55
A
263processor_set_t
264processor_pset(
265 processor_t processor)
9bccf70c 266{
2d21ac55 267 return (processor->processor_set);
1c79356b
A
268}
269
5ba3f43e
A
270void
271processor_state_update_idle(processor_t processor)
272{
273 processor->current_pri = IDLEPRI;
274 processor->current_sfi_class = SFI_CLASS_KERNEL;
275 processor->current_recommended_pset_type = PSET_SMP;
276 processor->current_perfctl_class = PERFCONTROL_CLASS_IDLE;
277}
278
279void
280processor_state_update_from_thread(processor_t processor, thread_t thread)
281{
282 processor->current_pri = thread->sched_pri;
283 processor->current_sfi_class = thread->sfi_class;
284 processor->current_recommended_pset_type = recommended_pset_type(thread);
285 processor->current_perfctl_class = thread_get_perfcontrol_class(thread);
286}
287
288void
289processor_state_update_explicit(processor_t processor, int pri, sfi_class_id_t sfi_class,
290 pset_cluster_type_t pset_type, perfcontrol_class_t perfctl_class)
291{
292 processor->current_pri = pri;
293 processor->current_sfi_class = sfi_class;
294 processor->current_recommended_pset_type = pset_type;
295 processor->current_perfctl_class = perfctl_class;
296}
297
2d21ac55
A
298pset_node_t
299pset_node_root(void)
9bccf70c 300{
2d21ac55 301 return &pset_node0;
9bccf70c
A
302}
303
2d21ac55
A
304processor_set_t
305pset_create(
306 pset_node_t node)
1c79356b 307{
3e170ce0
A
308 /* some schedulers do not support multiple psets */
309 if (SCHED(multiple_psets_enabled) == FALSE)
fe8ab488 310 return processor_pset(master_processor);
fe8ab488 311
2d21ac55 312 processor_set_t *prev, pset = kalloc(sizeof (*pset));
1c79356b 313
2d21ac55
A
314 if (pset != PROCESSOR_SET_NULL) {
315 pset_init(pset, node);
1c79356b 316
2d21ac55 317 simple_lock(&pset_node_lock);
1c79356b 318
2d21ac55
A
319 prev = &node->psets;
320 while (*prev != PROCESSOR_SET_NULL)
321 prev = &(*prev)->pset_list;
1c79356b 322
2d21ac55 323 *prev = pset;
1c79356b 324
2d21ac55
A
325 simple_unlock(&pset_node_lock);
326 }
1c79356b 327
2d21ac55 328 return (pset);
1c79356b
A
329}
330
5ba3f43e
A
331/*
332 * Find processor set in specified node with specified cluster_id.
333 * Returns default_pset if not found.
334 */
335processor_set_t
336pset_find(
337 uint32_t cluster_id,
338 processor_set_t default_pset)
339{
340 simple_lock(&pset_node_lock);
341 pset_node_t node = &pset_node0;
342 processor_set_t pset = NULL;
343
344 do {
345 pset = node->psets;
346 while (pset != NULL) {
347 if (pset->pset_cluster_id == cluster_id)
348 break;
349 pset = pset->pset_list;
350 }
351 } while ((node = node->node_list) != NULL);
352 simple_unlock(&pset_node_lock);
353 if (pset == NULL)
354 return default_pset;
355 return (pset);
356}
357
1c79356b 358/*
2d21ac55 359 * Initialize the given processor_set structure.
1c79356b
A
360 */
361void
2d21ac55
A
362pset_init(
363 processor_set_t pset,
364 pset_node_t node)
1c79356b 365{
6d2010ae 366 if (pset != &pset0) {
5ba3f43e 367 /* Scheduler state for pset0 initialized in sched_init() */
6d2010ae 368 SCHED(pset_init)(pset);
5ba3f43e 369 SCHED(rt_init)(pset);
6d2010ae
A
370 }
371
6d2010ae 372 pset->online_processor_count = 0;
5ba3f43e 373 pset->load_average = 0;
b7266188
A
374 pset->cpu_set_low = pset->cpu_set_hi = 0;
375 pset->cpu_set_count = 0;
d9a64523 376 pset->last_chosen = -1;
5ba3f43e 377 pset->cpu_bitmask = 0;
39037602 378 pset->recommended_bitmask = ~0ULL;
d9a64523
A
379 pset->primary_map = ~0ULL;
380 pset->cpu_state_map[PROCESSOR_OFF_LINE] = ~0ULL;
381 for (uint i = PROCESSOR_SHUTDOWN; i < PROCESSOR_STATE_LEN; i++) {
382 pset->cpu_state_map[i] = 0;
383 }
39236c6e 384 pset->pending_AST_cpu_mask = 0;
3e170ce0
A
385#if defined(CONFIG_SCHED_DEFERRED_AST)
386 pset->pending_deferred_AST_cpu_mask = 0;
387#endif
5ba3f43e 388 pset->pending_spill_cpu_mask = 0;
2d21ac55
A
389 pset_lock_init(pset);
390 pset->pset_self = IP_NULL;
391 pset->pset_name_self = IP_NULL;
392 pset->pset_list = PROCESSOR_SET_NULL;
393 pset->node = node;
5ba3f43e
A
394 pset->pset_cluster_type = PSET_SMP;
395 pset->pset_cluster_id = 0;
1c79356b
A
396}
397
1c79356b
A
398kern_return_t
399processor_info_count(
91447636 400 processor_flavor_t flavor,
1c79356b
A
401 mach_msg_type_number_t *count)
402{
1c79356b 403 switch (flavor) {
91447636 404
1c79356b
A
405 case PROCESSOR_BASIC_INFO:
406 *count = PROCESSOR_BASIC_INFO_COUNT;
91447636
A
407 break;
408
1c79356b
A
409 case PROCESSOR_CPU_LOAD_INFO:
410 *count = PROCESSOR_CPU_LOAD_INFO_COUNT;
91447636
A
411 break;
412
1c79356b 413 default:
91447636 414 return (cpu_info_count(flavor, count));
1c79356b 415 }
91447636
A
416
417 return (KERN_SUCCESS);
1c79356b
A
418}
419
420
421kern_return_t
422processor_info(
39037602 423 processor_t processor,
91447636
A
424 processor_flavor_t flavor,
425 host_t *host,
426 processor_info_t info,
1c79356b
A
427 mach_msg_type_number_t *count)
428{
39037602 429 int cpu_id, state;
91447636 430 kern_return_t result;
1c79356b
A
431
432 if (processor == PROCESSOR_NULL)
91447636 433 return (KERN_INVALID_ARGUMENT);
1c79356b 434
b0d623f7 435 cpu_id = processor->cpu_id;
1c79356b
A
436
437 switch (flavor) {
438
439 case PROCESSOR_BASIC_INFO:
91447636 440 {
39037602 441 processor_basic_info_t basic_info;
91447636
A
442
443 if (*count < PROCESSOR_BASIC_INFO_COUNT)
444 return (KERN_FAILURE);
445
446 basic_info = (processor_basic_info_t) info;
b0d623f7
A
447 basic_info->cpu_type = slot_type(cpu_id);
448 basic_info->cpu_subtype = slot_subtype(cpu_id);
91447636
A
449 state = processor->state;
450 if (state == PROCESSOR_OFF_LINE)
451 basic_info->running = FALSE;
452 else
453 basic_info->running = TRUE;
b0d623f7 454 basic_info->slot_num = cpu_id;
91447636
A
455 if (processor == master_processor)
456 basic_info->is_master = TRUE;
457 else
458 basic_info->is_master = FALSE;
459
460 *count = PROCESSOR_BASIC_INFO_COUNT;
461 *host = &realhost;
462
463 return (KERN_SUCCESS);
464 }
465
1c79356b 466 case PROCESSOR_CPU_LOAD_INFO:
91447636 467 {
316670eb 468 processor_cpu_load_info_t cpu_load_info;
316670eb 469 timer_t idle_state;
39236c6e
A
470 uint64_t idle_time_snapshot1, idle_time_snapshot2;
471 uint64_t idle_time_tstamp1, idle_time_tstamp2;
472
473 /*
474 * We capture the accumulated idle time twice over
475 * the course of this function, as well as the timestamps
476 * when each were last updated. Since these are
477 * all done using non-atomic racy mechanisms, the
478 * most we can infer is whether values are stable.
479 * timer_grab() is the only function that can be
480 * used reliably on another processor's per-processor
481 * data.
482 */
91447636 483
6d2010ae 484 if (*count < PROCESSOR_CPU_LOAD_INFO_COUNT)
91447636 485 return (KERN_FAILURE);
1c79356b 486
6d2010ae 487 cpu_load_info = (processor_cpu_load_info_t) info;
316670eb
A
488 if (precise_user_kernel_time) {
489 cpu_load_info->cpu_ticks[CPU_STATE_USER] =
b0d623f7 490 (uint32_t)(timer_grab(&PROCESSOR_DATA(processor, user_state)) / hz_tick_interval);
316670eb 491 cpu_load_info->cpu_ticks[CPU_STATE_SYSTEM] =
b0d623f7 492 (uint32_t)(timer_grab(&PROCESSOR_DATA(processor, system_state)) / hz_tick_interval);
316670eb
A
493 } else {
494 uint64_t tval = timer_grab(&PROCESSOR_DATA(processor, user_state)) +
495 timer_grab(&PROCESSOR_DATA(processor, system_state));
496
497 cpu_load_info->cpu_ticks[CPU_STATE_USER] = (uint32_t)(tval / hz_tick_interval);
498 cpu_load_info->cpu_ticks[CPU_STATE_SYSTEM] = 0;
499 }
6d2010ae
A
500
501 idle_state = &PROCESSOR_DATA(processor, idle_state);
39236c6e
A
502 idle_time_snapshot1 = timer_grab(idle_state);
503 idle_time_tstamp1 = idle_state->tstamp;
504
505 /*
506 * Idle processors are not continually updating their
507 * per-processor idle timer, so it may be extremely
508 * out of date, resulting in an over-representation
509 * of non-idle time between two measurement
510 * intervals by e.g. top(1). If we are non-idle, or
511 * have evidence that the timer is being updated
512 * concurrently, we consider its value up-to-date.
513 */
514 if (PROCESSOR_DATA(processor, current_state) != idle_state) {
515 cpu_load_info->cpu_ticks[CPU_STATE_IDLE] =
516 (uint32_t)(idle_time_snapshot1 / hz_tick_interval);
517 } else if ((idle_time_snapshot1 != (idle_time_snapshot2 = timer_grab(idle_state))) ||
518 (idle_time_tstamp1 != (idle_time_tstamp2 = idle_state->tstamp))){
519 /* Idle timer is being updated concurrently, second stamp is good enough */
6d2010ae 520 cpu_load_info->cpu_ticks[CPU_STATE_IDLE] =
39236c6e 521 (uint32_t)(idle_time_snapshot2 / hz_tick_interval);
316670eb 522 } else {
39236c6e
A
523 /*
524 * Idle timer may be very stale. Fortunately we have established
525 * that idle_time_snapshot1 and idle_time_tstamp1 are unchanging
526 */
527 idle_time_snapshot1 += mach_absolute_time() - idle_time_tstamp1;
6d2010ae
A
528
529 cpu_load_info->cpu_ticks[CPU_STATE_IDLE] =
39236c6e 530 (uint32_t)(idle_time_snapshot1 / hz_tick_interval);
6d2010ae 531 }
316670eb 532
2d21ac55 533 cpu_load_info->cpu_ticks[CPU_STATE_NICE] = 0;
1c79356b
A
534
535 *count = PROCESSOR_CPU_LOAD_INFO_COUNT;
536 *host = &realhost;
91447636
A
537
538 return (KERN_SUCCESS);
539 }
540
1c79356b 541 default:
b0d623f7 542 result = cpu_info(flavor, cpu_id, info, count);
91447636
A
543 if (result == KERN_SUCCESS)
544 *host = &realhost;
545
546 return (result);
1c79356b
A
547 }
548}
549
550kern_return_t
551processor_start(
2d21ac55 552 processor_t processor)
1c79356b 553{
2d21ac55
A
554 processor_set_t pset;
555 thread_t thread;
556 kern_return_t result;
557 spl_t s;
1c79356b 558
2d21ac55 559 if (processor == PROCESSOR_NULL || processor->processor_set == PROCESSOR_SET_NULL)
91447636 560 return (KERN_INVALID_ARGUMENT);
1c79356b 561
0b4e3aa0 562 if (processor == master_processor) {
55e303ae
A
563 processor_t prev;
564
2d21ac55 565 prev = thread_bind(processor);
9bccf70c 566 thread_block(THREAD_CONTINUE_NULL);
0b4e3aa0 567
b0d623f7 568 result = cpu_start(processor->cpu_id);
55e303ae 569
2d21ac55 570 thread_bind(prev);
55e303ae
A
571
572 return (result);
0b4e3aa0 573 }
1c79356b
A
574
575 s = splsched();
2d21ac55
A
576 pset = processor->processor_set;
577 pset_lock(pset);
55e303ae 578 if (processor->state != PROCESSOR_OFF_LINE) {
2d21ac55 579 pset_unlock(pset);
1c79356b 580 splx(s);
55e303ae
A
581
582 return (KERN_FAILURE);
1c79356b 583 }
55e303ae 584
d9a64523 585 pset_update_processor_state(pset, processor, PROCESSOR_START);
2d21ac55 586 pset_unlock(pset);
1c79356b
A
587 splx(s);
588
91447636
A
589 /*
590 * Create the idle processor thread.
591 */
592 if (processor->idle_thread == THREAD_NULL) {
593 result = idle_thread_create(processor);
594 if (result != KERN_SUCCESS) {
595 s = splsched();
2d21ac55 596 pset_lock(pset);
d9a64523 597 pset_update_processor_state(pset, processor, PROCESSOR_OFF_LINE);
2d21ac55 598 pset_unlock(pset);
91447636
A
599 splx(s);
600
601 return (result);
602 }
603 }
604
605 /*
606 * If there is no active thread, the processor
607 * has never been started. Create a dedicated
608 * start up thread.
609 */
610 if ( processor->active_thread == THREAD_NULL &&
611 processor->next_thread == THREAD_NULL ) {
612 result = kernel_thread_create((thread_continue_t)processor_start_thread, NULL, MAXPRI_KERNEL, &thread);
613 if (result != KERN_SUCCESS) {
614 s = splsched();
2d21ac55 615 pset_lock(pset);
d9a64523 616 pset_update_processor_state(pset, processor, PROCESSOR_OFF_LINE);
2d21ac55 617 pset_unlock(pset);
91447636
A
618 splx(s);
619
620 return (result);
621 }
1c79356b
A
622
623 s = splsched();
624 thread_lock(thread);
55e303ae 625 thread->bound_processor = processor;
1c79356b 626 processor->next_thread = thread;
55e303ae 627 thread->state = TH_RUN;
3e170ce0 628 thread->last_made_runnable_time = mach_absolute_time();
1c79356b
A
629 thread_unlock(thread);
630 splx(s);
91447636
A
631
632 thread_deallocate(thread);
1c79356b
A
633 }
634
55e303ae
A
635 if (processor->processor_self == IP_NULL)
636 ipc_processor_init(processor);
1c79356b 637
b0d623f7 638 result = cpu_start(processor->cpu_id);
55e303ae 639 if (result != KERN_SUCCESS) {
1c79356b 640 s = splsched();
2d21ac55 641 pset_lock(pset);
d9a64523 642 pset_update_processor_state(pset, processor, PROCESSOR_OFF_LINE);
2d21ac55 643 pset_unlock(pset);
1c79356b 644 splx(s);
55e303ae
A
645
646 return (result);
1c79356b
A
647 }
648
55e303ae
A
649 ipc_processor_enable(processor);
650
651 return (KERN_SUCCESS);
1c79356b
A
652}
653
654kern_return_t
655processor_exit(
656 processor_t processor)
657{
658 if (processor == PROCESSOR_NULL)
659 return(KERN_INVALID_ARGUMENT);
660
661 return(processor_shutdown(processor));
662}
663
664kern_return_t
665processor_control(
666 processor_t processor,
667 processor_info_t info,
668 mach_msg_type_number_t count)
669{
670 if (processor == PROCESSOR_NULL)
671 return(KERN_INVALID_ARGUMENT);
672
b0d623f7 673 return(cpu_control(processor->cpu_id, info, count));
1c79356b 674}
1c79356b
A
675
676kern_return_t
677processor_set_create(
91447636
A
678 __unused host_t host,
679 __unused processor_set_t *new_set,
680 __unused processor_set_t *new_name)
1c79356b 681{
1c79356b
A
682 return(KERN_FAILURE);
683}
684
685kern_return_t
686processor_set_destroy(
91447636 687 __unused processor_set_t pset)
1c79356b 688{
1c79356b
A
689 return(KERN_FAILURE);
690}
691
692kern_return_t
693processor_get_assignment(
694 processor_t processor,
695 processor_set_t *pset)
696{
2d21ac55 697 int state;
1c79356b 698
316670eb
A
699 if (processor == PROCESSOR_NULL)
700 return(KERN_INVALID_ARGUMENT);
701
1c79356b
A
702 state = processor->state;
703 if (state == PROCESSOR_SHUTDOWN || state == PROCESSOR_OFF_LINE)
704 return(KERN_FAILURE);
705
2d21ac55
A
706 *pset = &pset0;
707
1c79356b
A
708 return(KERN_SUCCESS);
709}
710
711kern_return_t
712processor_set_info(
713 processor_set_t pset,
714 int flavor,
715 host_t *host,
716 processor_set_info_t info,
717 mach_msg_type_number_t *count)
718{
719 if (pset == PROCESSOR_SET_NULL)
720 return(KERN_INVALID_ARGUMENT);
721
722 if (flavor == PROCESSOR_SET_BASIC_INFO) {
39037602 723 processor_set_basic_info_t basic_info;
1c79356b
A
724
725 if (*count < PROCESSOR_SET_BASIC_INFO_COUNT)
726 return(KERN_FAILURE);
727
728 basic_info = (processor_set_basic_info_t) info;
2d21ac55 729 basic_info->processor_count = processor_avail_count;
0b4e3aa0 730 basic_info->default_policy = POLICY_TIMESHARE;
1c79356b
A
731
732 *count = PROCESSOR_SET_BASIC_INFO_COUNT;
733 *host = &realhost;
734 return(KERN_SUCCESS);
735 }
736 else if (flavor == PROCESSOR_SET_TIMESHARE_DEFAULT) {
39037602 737 policy_timeshare_base_t ts_base;
1c79356b
A
738
739 if (*count < POLICY_TIMESHARE_BASE_COUNT)
740 return(KERN_FAILURE);
741
742 ts_base = (policy_timeshare_base_t) info;
0b4e3aa0 743 ts_base->base_priority = BASEPRI_DEFAULT;
1c79356b
A
744
745 *count = POLICY_TIMESHARE_BASE_COUNT;
746 *host = &realhost;
747 return(KERN_SUCCESS);
748 }
749 else if (flavor == PROCESSOR_SET_FIFO_DEFAULT) {
39037602 750 policy_fifo_base_t fifo_base;
1c79356b
A
751
752 if (*count < POLICY_FIFO_BASE_COUNT)
753 return(KERN_FAILURE);
754
755 fifo_base = (policy_fifo_base_t) info;
0b4e3aa0 756 fifo_base->base_priority = BASEPRI_DEFAULT;
1c79356b
A
757
758 *count = POLICY_FIFO_BASE_COUNT;
759 *host = &realhost;
760 return(KERN_SUCCESS);
761 }
762 else if (flavor == PROCESSOR_SET_RR_DEFAULT) {
39037602 763 policy_rr_base_t rr_base;
1c79356b
A
764
765 if (*count < POLICY_RR_BASE_COUNT)
766 return(KERN_FAILURE);
767
768 rr_base = (policy_rr_base_t) info;
0b4e3aa0
A
769 rr_base->base_priority = BASEPRI_DEFAULT;
770 rr_base->quantum = 1;
1c79356b
A
771
772 *count = POLICY_RR_BASE_COUNT;
773 *host = &realhost;
774 return(KERN_SUCCESS);
775 }
776 else if (flavor == PROCESSOR_SET_TIMESHARE_LIMITS) {
39037602 777 policy_timeshare_limit_t ts_limit;
1c79356b
A
778
779 if (*count < POLICY_TIMESHARE_LIMIT_COUNT)
780 return(KERN_FAILURE);
781
782 ts_limit = (policy_timeshare_limit_t) info;
91447636 783 ts_limit->max_priority = MAXPRI_KERNEL;
1c79356b
A
784
785 *count = POLICY_TIMESHARE_LIMIT_COUNT;
786 *host = &realhost;
787 return(KERN_SUCCESS);
788 }
789 else if (flavor == PROCESSOR_SET_FIFO_LIMITS) {
39037602 790 policy_fifo_limit_t fifo_limit;
1c79356b
A
791
792 if (*count < POLICY_FIFO_LIMIT_COUNT)
793 return(KERN_FAILURE);
794
795 fifo_limit = (policy_fifo_limit_t) info;
91447636 796 fifo_limit->max_priority = MAXPRI_KERNEL;
1c79356b
A
797
798 *count = POLICY_FIFO_LIMIT_COUNT;
799 *host = &realhost;
800 return(KERN_SUCCESS);
801 }
802 else if (flavor == PROCESSOR_SET_RR_LIMITS) {
39037602 803 policy_rr_limit_t rr_limit;
1c79356b
A
804
805 if (*count < POLICY_RR_LIMIT_COUNT)
806 return(KERN_FAILURE);
807
808 rr_limit = (policy_rr_limit_t) info;
91447636 809 rr_limit->max_priority = MAXPRI_KERNEL;
1c79356b
A
810
811 *count = POLICY_RR_LIMIT_COUNT;
812 *host = &realhost;
813 return(KERN_SUCCESS);
814 }
815 else if (flavor == PROCESSOR_SET_ENABLED_POLICIES) {
39037602 816 int *enabled;
1c79356b
A
817
818 if (*count < (sizeof(*enabled)/sizeof(int)))
819 return(KERN_FAILURE);
820
821 enabled = (int *) info;
0b4e3aa0 822 *enabled = POLICY_TIMESHARE | POLICY_RR | POLICY_FIFO;
1c79356b
A
823
824 *count = sizeof(*enabled)/sizeof(int);
825 *host = &realhost;
826 return(KERN_SUCCESS);
827 }
828
829
830 *host = HOST_NULL;
831 return(KERN_INVALID_ARGUMENT);
832}
833
834/*
835 * processor_set_statistics
836 *
837 * Returns scheduling statistics for a processor set.
838 */
839kern_return_t
840processor_set_statistics(
841 processor_set_t pset,
842 int flavor,
843 processor_set_info_t info,
844 mach_msg_type_number_t *count)
845{
2d21ac55
A
846 if (pset == PROCESSOR_SET_NULL || pset != &pset0)
847 return (KERN_INVALID_PROCESSOR_SET);
848
849 if (flavor == PROCESSOR_SET_LOAD_INFO) {
39037602 850 processor_set_load_info_t load_info;
1c79356b 851
2d21ac55
A
852 if (*count < PROCESSOR_SET_LOAD_INFO_COUNT)
853 return(KERN_FAILURE);
1c79356b 854
2d21ac55 855 load_info = (processor_set_load_info_t) info;
1c79356b 856
2d21ac55
A
857 load_info->mach_factor = sched_mach_factor;
858 load_info->load_average = sched_load_average;
1c79356b 859
2d21ac55
A
860 load_info->task_count = tasks_count;
861 load_info->thread_count = threads_count;
1c79356b 862
2d21ac55
A
863 *count = PROCESSOR_SET_LOAD_INFO_COUNT;
864 return(KERN_SUCCESS);
865 }
1c79356b 866
2d21ac55 867 return(KERN_INVALID_ARGUMENT);
1c79356b
A
868}
869
870/*
871 * processor_set_max_priority:
872 *
873 * Specify max priority permitted on processor set. This affects
874 * newly created and assigned threads. Optionally change existing
875 * ones.
876 */
877kern_return_t
878processor_set_max_priority(
91447636
A
879 __unused processor_set_t pset,
880 __unused int max_priority,
881 __unused boolean_t change_threads)
1c79356b
A
882{
883 return (KERN_INVALID_ARGUMENT);
884}
885
886/*
887 * processor_set_policy_enable:
888 *
889 * Allow indicated policy on processor set.
890 */
891
892kern_return_t
893processor_set_policy_enable(
91447636
A
894 __unused processor_set_t pset,
895 __unused int policy)
1c79356b
A
896{
897 return (KERN_INVALID_ARGUMENT);
898}
899
900/*
901 * processor_set_policy_disable:
902 *
903 * Forbid indicated policy on processor set. Time sharing cannot
904 * be forbidden.
905 */
906kern_return_t
907processor_set_policy_disable(
91447636
A
908 __unused processor_set_t pset,
909 __unused int policy,
910 __unused boolean_t change_threads)
1c79356b
A
911{
912 return (KERN_INVALID_ARGUMENT);
913}
914
1c79356b
A
915/*
916 * processor_set_things:
917 *
918 * Common internals for processor_set_{threads,tasks}
919 */
920kern_return_t
921processor_set_things(
3e170ce0
A
922 processor_set_t pset,
923 void **thing_list,
924 mach_msg_type_number_t *count,
925 int type)
1c79356b 926{
39037602 927 unsigned int i;
3e170ce0
A
928 task_t task;
929 thread_t thread;
930
931 task_t *task_list;
932 unsigned int actual_tasks;
933 vm_size_t task_size, task_size_needed;
1c79356b 934
3e170ce0
A
935 thread_t *thread_list;
936 unsigned int actual_threads;
937 vm_size_t thread_size, thread_size_needed;
938
939 void *addr, *newaddr;
1c79356b 940 vm_size_t size, size_needed;
1c79356b 941
2d21ac55 942 if (pset == PROCESSOR_SET_NULL || pset != &pset0)
91447636 943 return (KERN_INVALID_ARGUMENT);
1c79356b 944
3e170ce0
A
945 task_size = 0;
946 task_size_needed = 0;
947 task_list = NULL;
948 actual_tasks = 0;
949
950 thread_size = 0;
951 thread_size_needed = 0;
952 thread_list = NULL;
953 actual_threads = 0;
1c79356b
A
954
955 for (;;) {
b0d623f7 956 lck_mtx_lock(&tasks_threads_lock);
1c79356b 957
1c79356b 958 /* do we have the memory we need? */
3e170ce0
A
959 if (type == PSET_THING_THREAD)
960 thread_size_needed = threads_count * sizeof(void *);
961#if !CONFIG_MACF
962 else
963#endif
964 task_size_needed = tasks_count * sizeof(void *);
1c79356b 965
3e170ce0
A
966 if (task_size_needed <= task_size &&
967 thread_size_needed <= thread_size)
1c79356b
A
968 break;
969
2d21ac55 970 /* unlock and allocate more memory */
b0d623f7 971 lck_mtx_unlock(&tasks_threads_lock);
1c79356b 972
3e170ce0
A
973 /* grow task array */
974 if (task_size_needed > task_size) {
975 if (task_size != 0)
976 kfree(task_list, task_size);
1c79356b 977
3e170ce0
A
978 assert(task_size_needed > 0);
979 task_size = task_size_needed;
1c79356b 980
3e170ce0
A
981 task_list = (task_t *)kalloc(task_size);
982 if (task_list == NULL) {
983 if (thread_size != 0)
984 kfree(thread_list, thread_size);
985 return (KERN_RESOURCE_SHORTAGE);
986 }
987 }
1c79356b 988
3e170ce0
A
989 /* grow thread array */
990 if (thread_size_needed > thread_size) {
991 if (thread_size != 0)
992 kfree(thread_list, thread_size);
1c79356b 993
3e170ce0
A
994 assert(thread_size_needed > 0);
995 thread_size = thread_size_needed;
996
997 thread_list = (thread_t *)kalloc(thread_size);
998 if (thread_list == 0) {
999 if (task_size != 0)
1000 kfree(task_list, task_size);
1001 return (KERN_RESOURCE_SHORTAGE);
1002 }
1003 }
1004 }
91447636 1005
3e170ce0 1006 /* OK, have memory and the list locked */
2d21ac55 1007
3e170ce0
A
1008 /* If we need it, get the thread list */
1009 if (type == PSET_THING_THREAD) {
1010 for (thread = (thread_t)queue_first(&threads);
1011 !queue_end(&threads, (queue_entry_t)thread);
1012 thread = (thread_t)queue_next(&thread->threads)) {
1013#if defined(SECURE_KERNEL)
1014 if (thread->task != kernel_task) {
1015#endif
1016 thread_reference_internal(thread);
1017 thread_list[actual_threads++] = thread;
1018#if defined(SECURE_KERNEL)
1019 }
1020#endif
1021 }
1022 }
1023#if !CONFIG_MACF
1024 else {
1025#endif
1026 /* get a list of the tasks */
2d21ac55 1027 for (task = (task_t)queue_first(&tasks);
3e170ce0
A
1028 !queue_end(&tasks, (queue_entry_t)task);
1029 task = (task_t)queue_next(&task->tasks)) {
2d21ac55
A
1030#if defined(SECURE_KERNEL)
1031 if (task != kernel_task) {
1032#endif
1033 task_reference_internal(task);
3e170ce0 1034 task_list[actual_tasks++] = task;
2d21ac55
A
1035#if defined(SECURE_KERNEL)
1036 }
1037#endif
1c79356b 1038 }
3e170ce0 1039#if !CONFIG_MACF
91447636 1040 }
3e170ce0 1041#endif
2d21ac55 1042
b0d623f7 1043 lck_mtx_unlock(&tasks_threads_lock);
1c79356b 1044
3e170ce0 1045#if CONFIG_MACF
39037602
A
1046 unsigned int j, used;
1047
3e170ce0
A
1048 /* for each task, make sure we are allowed to examine it */
1049 for (i = used = 0; i < actual_tasks; i++) {
1050 if (mac_task_check_expose_task(task_list[i])) {
1051 task_deallocate(task_list[i]);
1052 continue;
1053 }
1054 task_list[used++] = task_list[i];
91447636 1055 }
3e170ce0
A
1056 actual_tasks = used;
1057 task_size_needed = actual_tasks * sizeof(void *);
91447636 1058
3e170ce0 1059 if (type == PSET_THING_THREAD) {
1c79356b 1060
3e170ce0
A
1061 /* for each thread (if any), make sure it's task is in the allowed list */
1062 for (i = used = 0; i < actual_threads; i++) {
1063 boolean_t found_task = FALSE;
1c79356b 1064
3e170ce0
A
1065 task = thread_list[i]->task;
1066 for (j = 0; j < actual_tasks; j++) {
1067 if (task_list[j] == task) {
1068 found_task = TRUE;
1c79356b 1069 break;
1c79356b 1070 }
1c79356b 1071 }
3e170ce0
A
1072 if (found_task)
1073 thread_list[used++] = thread_list[i];
1074 else
1075 thread_deallocate(thread_list[i]);
1c79356b 1076 }
3e170ce0
A
1077 actual_threads = used;
1078 thread_size_needed = actual_threads * sizeof(void *);
1079
1080 /* done with the task list */
1081 for (i = 0; i < actual_tasks; i++)
1082 task_deallocate(task_list[i]);
1083 kfree(task_list, task_size);
1084 task_size = 0;
1085 actual_tasks = 0;
1086 task_list = NULL;
1087 }
1088#endif
1c79356b 1089
3e170ce0
A
1090 if (type == PSET_THING_THREAD) {
1091 if (actual_threads == 0) {
1092 /* no threads available to return */
1093 assert(task_size == 0);
1094 if (thread_size != 0)
1095 kfree(thread_list, thread_size);
1096 *thing_list = NULL;
1097 *count = 0;
1098 return KERN_SUCCESS;
91447636 1099 }
3e170ce0
A
1100 size_needed = actual_threads * sizeof(void *);
1101 size = thread_size;
1102 addr = thread_list;
1103 } else {
1104 if (actual_tasks == 0) {
1105 /* no tasks available to return */
1106 assert(thread_size == 0);
1107 if (task_size != 0)
1108 kfree(task_list, task_size);
1109 *thing_list = NULL;
1110 *count = 0;
1111 return KERN_SUCCESS;
1112 }
1113 size_needed = actual_tasks * sizeof(void *);
1114 size = task_size;
1115 addr = task_list;
1116 }
1c79356b 1117
3e170ce0
A
1118 /* if we allocated too much, must copy */
1119 if (size_needed < size) {
1120 newaddr = kalloc(size_needed);
1121 if (newaddr == 0) {
1122 for (i = 0; i < actual_tasks; i++) {
1123 if (type == PSET_THING_THREAD)
1124 thread_deallocate(thread_list[i]);
1125 else
1126 task_deallocate(task_list[i]);
1127 }
1128 if (size)
1129 kfree(addr, size);
1130 return (KERN_RESOURCE_SHORTAGE);
91447636 1131 }
2d21ac55 1132
3e170ce0
A
1133 bcopy((void *) addr, (void *) newaddr, size_needed);
1134 kfree(addr, size);
1135
1136 addr = newaddr;
1137 size = size_needed;
1c79356b
A
1138 }
1139
3e170ce0
A
1140 *thing_list = (void **)addr;
1141 *count = (unsigned int)size / sizeof(void *);
1142
91447636 1143 return (KERN_SUCCESS);
1c79356b
A
1144}
1145
1146
1147/*
1148 * processor_set_tasks:
1149 *
1150 * List all tasks in the processor set.
1151 */
1152kern_return_t
1153processor_set_tasks(
1154 processor_set_t pset,
1155 task_array_t *task_list,
1156 mach_msg_type_number_t *count)
1157{
3e170ce0
A
1158 kern_return_t ret;
1159 mach_msg_type_number_t i;
1160
1161 ret = processor_set_things(pset, (void **)task_list, count, PSET_THING_TASK);
1162 if (ret != KERN_SUCCESS)
1163 return ret;
1164
1165 /* do the conversion that Mig should handle */
1166 for (i = 0; i < *count; i++)
1167 (*task_list)[i] = (task_t)convert_task_to_port((*task_list)[i]);
1168 return KERN_SUCCESS;
1c79356b
A
1169}
1170
1171/*
1172 * processor_set_threads:
1173 *
1174 * List all threads in the processor set.
1175 */
2d21ac55
A
1176#if defined(SECURE_KERNEL)
1177kern_return_t
1178processor_set_threads(
1179 __unused processor_set_t pset,
1180 __unused thread_array_t *thread_list,
1181 __unused mach_msg_type_number_t *count)
1182{
1183 return KERN_FAILURE;
1184}
5ba3f43e
A
1185#elif defined(CONFIG_EMBEDDED)
1186kern_return_t
1187processor_set_threads(
1188 __unused processor_set_t pset,
1189 __unused thread_array_t *thread_list,
1190 __unused mach_msg_type_number_t *count)
1191{
1192 return KERN_NOT_SUPPORTED;
1193}
2d21ac55 1194#else
1c79356b
A
1195kern_return_t
1196processor_set_threads(
1197 processor_set_t pset,
1198 thread_array_t *thread_list,
1199 mach_msg_type_number_t *count)
1200{
3e170ce0
A
1201 kern_return_t ret;
1202 mach_msg_type_number_t i;
1203
1204 ret = processor_set_things(pset, (void **)thread_list, count, PSET_THING_THREAD);
1205 if (ret != KERN_SUCCESS)
1206 return ret;
1207
1208 /* do the conversion that Mig should handle */
1209 for (i = 0; i < *count; i++)
1210 (*thread_list)[i] = (thread_t)convert_thread_to_port((*thread_list)[i]);
1211 return KERN_SUCCESS;
1c79356b 1212}
2d21ac55 1213#endif
1c79356b
A
1214
1215/*
1216 * processor_set_policy_control
1217 *
1218 * Controls the scheduling attributes governing the processor set.
1219 * Allows control of enabled policies, and per-policy base and limit
1220 * priorities.
1221 */
1222kern_return_t
1223processor_set_policy_control(
91447636
A
1224 __unused processor_set_t pset,
1225 __unused int flavor,
1226 __unused processor_set_info_t policy_info,
1227 __unused mach_msg_type_number_t count,
1228 __unused boolean_t change)
1c79356b
A
1229{
1230 return (KERN_INVALID_ARGUMENT);
1231}
2d21ac55
A
1232
1233#undef pset_deallocate
1234void pset_deallocate(processor_set_t pset);
1235void
1236pset_deallocate(
1237__unused processor_set_t pset)
1238{
1239 return;
1240}
1241
1242#undef pset_reference
1243void pset_reference(processor_set_t pset);
1244void
1245pset_reference(
1246__unused processor_set_t pset)
1247{
1248 return;
1249}
5ba3f43e
A
1250
1251pset_cluster_type_t
1252recommended_pset_type(thread_t thread)
1253{
1254 (void)thread;
1255 return PSET_SMP;
1256}