xref: /xnu-8019.80.24/osfmk/kern/startup.h (revision a325d9c4a84054e40bbe985afedcb50ab80993ea)
1 /*
2  * Copyright (c) 2000-2020 Apple Inc. All rights reserved.
3  *
4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5  *
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.
14  *
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
20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
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.
25  *
26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27  */
28 /*
29  * @OSF_COPYRIGHT@
30  */
31 
32 #ifdef  XNU_KERNEL_PRIVATE
33 
34 #ifndef _KERN_STARTUP_H_
35 #define _KERN_STARTUP_H_
36 
37 #include <stdbool.h>
38 #include <stdint.h>
39 
40 #include <libkern/section_keywords.h>
41 
42 __BEGIN_DECLS
43 
44 #pragma GCC visibility push(hidden)
45 
46 /*!
47  * @enum startup_subsystem_id_t
48  *
49  * @abstract
50  * Represents a stage of kernel intialization, ubnd allows for subsystems
51  * to register initializers for a specific stage.
52  *
53  * @discussion
54  * Documentation of each subsystem initialization sequence exists in
55  * @file doc/startup.md.
56  */
57 __enum_decl(startup_subsystem_id_t, uint32_t, {
58 	STARTUP_SUB_NONE = 0,         /**< reserved for the startup subsystem  */
59 
60 	STARTUP_SUB_TUNABLES,         /**< support for the tunables subsystem  */
61 	STARTUP_SUB_TIMEOUTS,         /**< configurable machine timeouts       */
62 	STARTUP_SUB_LOCKS_EARLY,      /**< early locking, before zalloc        */
63 	STARTUP_SUB_KPRINTF,          /**< kprintf initialization              */
64 
65 	STARTUP_SUB_PMAP_STEAL,       /**< to perform various pmap carveouts   */
66 	STARTUP_SUB_VM_KERNEL,        /**< once the kernel VM is ready         */
67 	STARTUP_SUB_KMEM,             /**< once kmem is ready                  */
68 	STARTUP_SUB_KMEM_ALLOC,       /**< once kmem_alloc is ready            */
69 	STARTUP_SUB_ZALLOC,           /**< initialize zalloc and kalloc        */
70 	STARTUP_SUB_PERCPU,           /**< initialize the percpu subsystem     */
71 	STARTUP_SUB_LOCKS,            /**< various subsystem locks             */
72 
73 	STARTUP_SUB_CODESIGNING,      /**< codesigning subsystem               */
74 	STARTUP_SUB_OSLOG,            /**< oslog and kernel loggging           */
75 	STARTUP_SUB_MACH_IPC,         /**< Mach IPC                            */
76 	STARTUP_SUB_THREAD_CALL,      /**< Thread calls                        */
77 	STARTUP_SUB_SYSCTL,           /**< registers sysctls                   */
78 	STARTUP_SUB_EARLY_BOOT,       /**< interrupts/premption are turned on  */
79 
80 	STARTUP_SUB_LOCKDOWN = ~0u,   /**< reserved for the startup subsystem  */
81 });
82 
83 /*!
84  * Stores the last subsystem to have been fully initialized;
85  */
86 extern startup_subsystem_id_t startup_phase;
87 
88 /*!
89  * @enum startup_debug_t
90  *
91  * @abstract
92  * Flags set in the @c startup_debug global to configure startup debugging.
93  */
94 __options_decl(startup_debug_t, uint32_t, {
95 	STARTUP_DEBUG_NONE    = 0x00000000,
96 	STARTUP_DEBUG_VERBOSE = 0x00000001,
97 });
98 
99 extern startup_debug_t startup_debug;
100 
101 /*!
102  * @enum startup_rank
103  *
104  * @abstract
105  * Specifies in which rank a given initializer runs within a given section
106  * to register initializers for a specific rank within the subsystem.
107  *
108  * @description
109  * A startup function, declared with @c STARTUP or @c STARTUP_ARG, can specify
110  * an rank within the subsystem they initialize.
111  *
112  * @c STARTUP_RANK_NTH(n) will let callbacks be run at stage @c n (0-based).
113  *
114  * @c STARTUP_RANK_FIRST, @c STARTUP_RANK_SECOND, @c STARTUP_RANK_THIRD and
115  * @c STARTUP_RANK_FOURTH are given as conveniency names for these.
116  *
117  * @c STARTUP_RANK_MIDDLE is a reserved value that will let startup functions
118  * run after all the @c STARTUP_RANK_NTH(n) ones have.
119  *
120  * @c STARTUP_RANK_NTH_LATE_NTH(n) will let callbacks be run then in @c n rank
121  * after the @c STARTUP_RANK_MIDDLE ones (0-based).
122  *
123  * @c STARTUP_RANK_LAST callbacks will run absolutely last after everything
124  * else did for this subsystem.
125  */
126 __enum_decl(startup_rank_t, uint32_t, {
127 #define STARTUP_RANK_NTH(n) \
128 	(enum startup_rank)(n)
129 	STARTUP_RANK_FIRST          = 0,
130 	STARTUP_RANK_SECOND         = 1,
131 	STARTUP_RANK_THIRD          = 2,
132 	STARTUP_RANK_FOURTH         = 3,
133 
134 	STARTUP_RANK_MIDDLE         = 0x7fffffff,
135 
136 #define STARTUP_RANK_LATE_NTH(n) \
137 	(enum startup_rank)(STARTUP_RANK_MIDDLE + 1 + (n))
138 
139 	STARTUP_RANK_LAST           = 0xffffffff,
140 });
141 
142 #if KASAN
143 /*
144  * The use of weird sections that get unmapped confuse the hell out of kasan,
145  * so for KASAN leave things in regular __TEXT/__DATA segments
146  */
147 #define STARTUP_CODE_SEGSECT "__TEXT,__text"
148 #define STARTUP_DATA_SEGSECT "__DATA,__init"
149 #define STARTUP_HOOK_SEGMENT "__DATA"
150 #define STARTUP_HOOK_SECTION "__init_entry_set"
151 #elif defined(__x86_64__)
152 /* Intel doesn't have a __BOOTDATA but doesn't protect __KLD */
153 #define STARTUP_CODE_SEGSECT "__TEXT,__text"
154 #define STARTUP_DATA_SEGSECT "__KLDDATA,__init"
155 #define STARTUP_HOOK_SEGMENT "__KLDDATA"
156 #define STARTUP_HOOK_SECTION "__init_entry_set"
157 #else
158 /* arm protects __KLD early, so use __BOOTDATA for data */
159 #define STARTUP_CODE_SEGSECT "__TEXT,__text"
160 #define STARTUP_DATA_SEGSECT "__BOOTDATA,__init"
161 #define STARTUP_HOOK_SEGMENT "__BOOTDATA"
162 #define STARTUP_HOOK_SECTION "__init_entry_set"
163 #endif
164 
165 /*!
166  * @macro __startup_func
167  *
168  * @abstract
169  * Attribute to place on functions used only during the kernel startup phase.
170  *
171  * @description
172  * Code marked with this attribute will be unmapped after kernel lockdown.
173  */
174 #define __startup_func \
175 	__PLACE_IN_SECTION(STARTUP_CODE_SEGSECT) \
176 	__attribute__((cold, visibility("hidden")))
177 
178 /*!
179  * @macro __startup_data
180  *
181  * @abstract
182  * Attribute to place on globals used during the kernel startup phase.
183  *
184  * @description
185  * Data marked with this attribute will be unmapped after kernel lockdown.
186  */
187 #define __startup_data \
188 	__PLACE_IN_SECTION(STARTUP_DATA_SEGSECT)
189 
190 /*!
191  * @macro STARTUP
192  *
193  * @abstract
194  * Declares a kernel startup callback.
195  */
196 #define STARTUP(subsystem, rank, func) \
197 	__STARTUP(func, __LINE__, subsystem, rank, func)
198 
199 /*!
200  * @macro STARTUP_ARG
201  *
202  * @abstract
203  * Declares a kernel startup callback that takes an argument.
204  */
205 #define STARTUP_ARG(subsystem, rank, func, arg) \
206 	__STARTUP_ARG(func, __LINE__, subsystem, rank, func, arg)
207 
208 /*!
209  * @macro TUNABLE
210  *
211  * @abstract
212  * Declares a read-only kernel tunable that is read from a boot-arg with
213  * a default value, without further processing.
214  *
215  * @param type_t
216  * Should be an integer type or bool.
217  *
218  * @param var
219  * The name of the C variable to use for storage.
220  *
221  * @param boot_arg
222  * The name of the boot-arg to parse for initialization
223  *
224  * @param default_value
225  * The default value for the tunable if the boot-arg is absent.
226  */
227 #define TUNABLE(type_t, var, boot_arg, default_value) \
228 	SECURITY_READ_ONLY_LATE(type_t) var = default_value; \
229 	__TUNABLE(type_t, var, boot_arg)
230 
231 /*!
232  * @macro TUNABLE_WRITEABLE
233  *
234  * @abstract
235  * Declares a writeable kernel tunable that is read from a boot-arg with
236  * a default value, without further processing.
237  *
238  * @param type_t
239  * Should be an integer type or bool.
240  *
241  * @param var
242  * The name of the C variable to use for storage.
243  *
244  * @param boot_arg
245  * The name of the boot-arg to parse for initialization
246  *
247  * @param default_value
248  * The default value for the tunable if the boot-arg is absent.
249  */
250 #define TUNABLE_WRITEABLE(type_t, var, boot_arg, default_value) \
251 	type_t var = default_value; \
252 	__TUNABLE(type_t, var, boot_arg)
253 
254 #if DEBUG || DEVELOPMENT
255 #define TUNABLE_DEV_WRITEABLE(type_t, var, boot_arg, default_value) \
256 	TUNABLE_WRITEABLE(type_t, var, boot_arg, default_value)
257 #else
258 #define TUNABLE_DEV_WRITEABLE(type_t, var, boot_arg, default_value) \
259 	TUNABLE(type_t, var, boot_arg, default_value)
260 #endif
261 
262 /*!
263  * @macro TUNABLE_STR
264  *
265  * @abstract
266  * Declares a read-only kernel tunable that is read from a boot-arg with
267  * a default value, without further processing.
268  *
269  * @param var
270  * The name of the C variable to use for storage.
271  *
272  * @param count
273  * The number of bytes in the buffer.
274  *
275  * @param boot_arg
276  * The name of the boot-arg to parse for initialization
277  *
278  * @param default_value
279  * The default value for the tunable if the boot-arg is absent.
280  */
281 #define TUNABLE_STR(var, count, boot_arg, default_value) \
282 	char __security_const_late var[count] = default_value; \
283 	__TUNABLE_STR(var, boot_arg)
284 
285 /*!
286  * @enum tunable_dt_flags_t
287  *
288  * @abstract
289  * Flags used with the @c TUNABLE_DT* macros.
290  *
291  * @description
292  * If TUNABLE_DT_CHECK_CHOSEN is set, a value in
293  * /chosen/<dt_base>/<dt_name> takes precedence over any value in
294  * /<dt_base>/<dt_name>. /chosen is by convention the area where
295  * synthesized values not coming from the serialized device tree are
296  * being added, so this provides a way for e.g. the boot-loader to
297  * set/override tunables.
298  */
299 __options_decl(tunable_dt_flags_t, uint32_t, {
300 	TUNABLE_DT_NONE         = 0x00000000,
301 	TUNABLE_DT_CHECK_CHOSEN = 0x00000001,
302 });
303 
304 /*!
305  * @macro TUNABLE_DT
306  *
307  * @abstract
308  * Like TUNABLE, but gets the initial value from both Device Tree and
309  * boot-args. The order in which the initial value is resolved is as
310  * follows, with later steps overriding previous ones (if they are
311  * specified):
312  *
313  * 1. Device Tree Entry "/<dt_base>/<dt_name>",
314  * 2. If TUNABLE_DT_CHECK_CHOSEN is set, Device Tree Entry
315  *    "/chosen/<dt_base>/<dt_name>" (see the description for
316  *    @c tunable_dt_flags_t),
317  * 3. boot-args.
318  *
319  * @param type_t
320  * Should be an integer type or bool.
321  *
322  * @param var
323  * The name of the C variable to use for storage.
324  *
325  * @param dt_base
326  * The name of the DT node containing the property.
327  *
328  * @param dt_name
329  * The name of the DT property containing the default value.
330  *
331  * @param boot_arg
332  * The name of the boot-arg overriding the initial value from the DT.
333  *
334  * @param default_value
335  * The default value for the tunable if both DT entry and boot-arg are
336  * absent.
337  *
338  * @param flags
339  * See the description for @c tunable_dt_flags_t.
340  */
341 #define TUNABLE_DT(type_t, var, dt_base, dt_name, boot_arg, default_value, flags) \
342 	SECURITY_READ_ONLY_LATE(type_t) var = default_value; \
343 	__TUNABLE_DT(type_t, var, dt_base, dt_name, boot_arg, flags)
344 
345 /*!
346  * @macro TUNABLE_DT_WRITEABLE
347  *
348  * @abstract
349  * Like TUNABLE_WRITEABLE, but gets the initial value from both Device
350  * Tree and boot-args. The order in which the initial value is
351  * resolved is as follows, with later steps overriding previous ones
352  * (if they are specified):
353  *
354  * 1. Device Tree Entry "/<dt_base>/<dt_name>",
355  * 2. If TUNABLE_DT_CHECK_CHOSEN is set, Device Tree Entry
356  *    "/chosen/<dt_base>/<dt_name>" (see the description for
357  *    @c tunable_dt_flags_t),
358  * 3. boot-args.
359  *
360  * @param type_t
361  * Should be an integer type or bool.
362  *
363  * @param var
364  * The name of the C variable to use for storage.
365  *
366  * @param dt_base
367  * The name of the DT node containing the property.
368  *
369  * @param dt_name
370  * The name of the DT property containing the default value.
371  *
372  * @param boot_arg
373  * The name of the boot-arg overriding the initial value from the DT.
374  *
375  * @param default_value
376  * The default value for the tunable if both DT entry and boot-arg are
377  * absent.
378  *
379  * @param flags
380  * See the description for @c tunable_dt_flags_t.
381  */
382 #define TUNABLE_DT_WRITEABLE(type_t, var, dt_base, dt_name, boot_arg, default_value, flags) \
383 	type_t var = default_value; \
384 	__TUNABLE_DT(type_t, var, dt_base, dt_name, boot_arg, flags)
385 
386 /*
387  * Machine Timeouts
388  *
389  * Machine Timeouts are timeouts for low level kernel code manifesting
390  * as _Atomic uint64_t variables, whose default value can be
391  * overridden and scaled via the device tree and boot-args.
392  *
393  * Each timeout has a name, looked up directly as the property name in
394  * the device tree in both the "/machine-timeouts" and
395  * "/chosen/machine-timeouts" nodes. The "chosen" property always
396  * overrides the other one. This allows fixed per-device timeouts in
397  * the device tree to be overridden by iBoot in "chosen".
398  *
399  * Additionally, the same name with "-scale" appended is looked up as
400  * properties for optional scale factors. Scale factors are not
401  * overridden by chosen, instead all scale factors (including global
402  * and/or boot-arg scale factors) combine by multiplication.
403  *
404  * The special name "global-scale" provides a scale that applies to
405  * every timeout.
406  *
407  * All property names can be used as boot-args by prefixing
408  * "ml-timeout-", e.g. th global scale is available as the
409  * "ml-timeout-global-scale" boot-arg.
410  *
411  * By convention, if the timeout value resolves to 0, the timeout
412  * should be disabled.
413  */
414 
415 /*
416  * Machine Timeouts types. See the next section for what unit
417  * they are in.
418  *
419  * We use _Atomic, but only with relaxed ordering: This is just to
420  * make sure all devices see consistent values all the time.  Since
421  * the actual timeout value will be seen as 0 before initializaton,
422  * relaxed ordering means that code that runs concurrently with
423  * initialization only risks to see a disabled timeout during early
424  * boot.
425  *
426  * On 64bit devices, _Atomic with relaxed should have no effect.  On
427  * 32bit devices, _Atomic uint64_t will incur synchronization, so it
428  * might be better to use machine_timeout32_t instead.
429  */
430 typedef _Atomic uint64_t machine_timeout_t;
431 typedef _Atomic uint32_t machine_timeout32_t;
432 
433 /*
434  * Units
435  *
436  * Machine Timeouts are ALWAYS in picoseconds in the device tree or
437  * boot-args, to avoid confusion when changing or comparing timeouts
438  * as a user, but the actual storage value might contain the same
439  * duration in another unit, calculated by the initialization code.
440  *
441  * This is done because otherwise we would likely introduce another
442  * multiplication in potentially hot code paths, given that code that
443  * actually uses the timeout storage variable is unlikely to work with
444  * picosecond values when comparing against the timeout deadline.
445  *
446  * This unit scale is *only* applied during initialization at early
447  * boot, and only if the timeout's default value was overridden
448  * through the device tree or a boot-arg.
449  */
450 #define MACHINE_TIMEOUT_UNIT_PSEC 1
451 #define MACHINE_TIMEOUT_UNIT_NSEC 1000
452 #define MACHINE_TIMEOUT_UNIT_USEC (1000*1000)
453 #define MACHINE_TIMEOUT_UNIT_MSEC (1000*1000*1000)
454 // Special unit for timebase ticks (usually 1/24MHz)
455 #define MACHINE_TIMEOUT_UNIT_TIMEBASE 0
456 
457 // DT property names are limited to 31 chars, minus "-global" suffix
458 #define MACHINE_TIMEOUT_MAX_NAME_LEN 25
459 struct machine_timeout_spec {
460 	void *ptr;
461 	uint64_t default_value;
462 	uint64_t unit_scale;
463 	bool is32;
464 	char name[MACHINE_TIMEOUT_MAX_NAME_LEN + 1];
465 	bool (*skip_predicate)(struct machine_timeout_spec const *);
466 };
467 
468 extern void
469 machine_timeout_init_with_suffix(const struct machine_timeout_spec *spec, char const *phase_suffix);
470 
471 extern void
472 machine_timeout_init(const struct machine_timeout_spec *spec);
473 
474 // Late timeout (re-)initialization, at the end of bsd_init()
475 extern void
476 machine_timeout_bsd_init(void);
477 
478 /*!
479  * @macro MACHINE_TIMEOUT and MACHINE_TIMEOUT_WRITEABLE
480  *
481  * @abstract
482  * Defines a Machine Timeout that can be overridden and
483  * scaled through the device tree and boot-args.
484  *
485  * The variant with the _WRITEABLE suffix does not mark the timeout as
486  * SECURITY_READ_ONLY_LATE, so that e.g. machine_timeout_init_with_suffix
487  * or sysctls can change it after lockdown.
488  *
489  * @param var
490  * The name of the C variable to use for storage. If the storage value
491  * contains 0, the timeout is considered disabled by convention.
492  *
493  * @param timeout_name
494  * The name of the timeout, used for property and boot-arg names. See
495  * the general description of Machine Timeouts above for how this name
496  * ends up being used.
497  *
498  * @param timeout_default
499  * The default value for the timeout if not specified through device
500  * tree or boot-arg. Will still be scaled if a scale factor exists.
501  *
502  * @param var_unit
503  * The unit that the storage variable is in. Note that timeout values
504  * must always be specified as picoseconds in the device tree and
505  * boot-args, but timeout initialization will convert the value to the
506  * unit specified here before writing it to the storage variable.
507  *
508  * @param skip_predicate
509  * Optionally, a function to call to decide whether the timeout should
510  * be set or not.  If NULL, the timeout will always be set (if
511  * specified anywhere). A predicate has the following signature:
512  *     bool skip_predicate (struct machine_timeout_spec const *)
513  */
514 
515 #define _MACHINE_TIMEOUT(var, timeout_name, timeout_default, var_unit, var_is32, skip_pred) \
516 	struct machine_timeout_spec \
517 	__machine_timeout_spec_ ## var = { \
518 	        .ptr = &var, \
519 	        .default_value = timeout_default, \
520 	        .unit_scale = var_unit, \
521 	        .is32 = var_is32, \
522 	        .name = timeout_name, \
523 	        .skip_predicate = skip_pred, \
524 	}; \
525 	__STARTUP_ARG(var, __LINE__, TIMEOUTS, STARTUP_RANK_FIRST, \
526 	    machine_timeout_init, &__machine_timeout_spec_ ## var)
527 
528 #define MACHINE_TIMEOUT(var, name, default, unit, skip_predicate)       \
529 	SECURITY_READ_ONLY_LATE(machine_timeout_t) var = 0;                                     \
530 	_MACHINE_TIMEOUT(var, name, default, unit, false, skip_predicate)
531 
532 #define MACHINE_TIMEOUT32(var, name, default, unit, skip_predicate)     \
533 	SECURITY_READ_ONLY_LATE(machine_timeout32_t) var = 0;                           \
534 	_MACHINE_TIMEOUT(var, name, default, unit, true, skip_predicate)
535 
536 #define MACHINE_TIMEOUT_WRITEABLE(var, name, default, unit, skip_predicate)       \
537 	machine_timeout_t var = 0; \
538 	_MACHINE_TIMEOUT(var, name, default, unit, false, skip_predicate)
539 
540 #define MACHINE_TIMEOUT32_WRITEABLE(var, name, default, unit, skip_predicate)     \
541 	machine_timeout32_t var = 0; \
542 	_MACHINE_TIMEOUT(var, name, default, unit, true, skip_predicate)
543 
544 /*!
545  * @macro MACHINE_TIMEOUT_SPEC_REF
546  *
547  * @abstract
548  * References a previously defined MACHINE_TIMEOUT or
549  * MACHINE_TIMEOUT32.  This is primarily useful for overriding
550  * individual timeouts at arbitrary times (even after boot), by
551  * manually calling machine_timeout_init_with_suffix() with this macro
552  * as first argument, and a suffix to apply to both device tree and
553  * boot-arg as second argument.
554  *
555  * @param var
556  * The name of the C variable used for storage, as it was specified
557  * in MACHINE_TIMEOUT or MACHINE_TIMEOUT32.
558  */
559 #define MACHINE_TIMEOUT_SPEC_REF(var) (&__machine_timeout_spec_ ## var)
560 
561 /*!
562  * @macro MACHINE_TIMEOUT_SPEC_DECL
563  *
564  * @abstract
565  * Declaration of machine timeout spec, mostly useful to make it known
566  * for MACHINE_TIMEOUT_SPEC_REF.
567  *
568  * @param var
569  * The name of the C variable used for storage, as it was specified
570  * in MACHINE_TIMEOUT or MACHINE_TIMEOUT32.
571  */
572 #define MACHINE_TIMEOUT_SPEC_DECL(var) extern struct machine_timeout_spec __machine_timeout_spec_ ## var
573 
574 #if DEBUG || DEVELOPMENT
575 
576 /*!
577  * @macro SYSCTL_TEST_REGISTER
578  *
579  * @abstract
580  * Declares a test that will appear under @c debug.test.${name}.
581  *
582  * @param name
583  * An indentifier that will be stringified to form the sysctl test name.
584  *
585  * @param cb
586  * The callback to run, of type:
587  * <code>
588  *     int (callback *)(int64_t value, int64_t *);
589  * </code>
590  */
591 #define SYSCTL_TEST_REGISTER(name, cb) \
592 	static __startup_data struct sysctl_test_setup_spec \
593 	__startup_SYSCTL_TEST_ ## name = { \
594 	        .st_name = #name, \
595 	        .st_func = &cb, \
596 	}; \
597 	STARTUP_ARG(SYSCTL, STARTUP_RANK_MIDDLE, \
598 	    sysctl_register_test_startup, &__startup_SYSCTL_TEST_ ## name)
599 
600 #endif /* DEBUG || DEVELOPMENT */
601 #pragma mark - internals
602 
603 __END_DECLS
604 
605 #ifdef __cplusplus
606 template <typename T>
607 struct __startup_tunable {
608 	static const bool value  = false;
609 };
610 
611 template <>
612 struct __startup_tunable <bool>{
613 	static const bool value = true;
614 };
615 #define __startup_type_is_bool(type_t) __startup_tunable<type_t>::value
616 #else
617 #define __startup_type_is_bool(type_t) __builtin_types_compatible_p(bool, type_t)
618 #endif
619 
620 __BEGIN_DECLS
621 
622 #define __TUNABLE(type_t, var, key) \
623 	static __startup_data char __startup_TUNABLES_name_ ## var[] = key; \
624 	static __startup_data struct startup_tunable_spec \
625 	__startup_TUNABLES_spec_ ## var = { \
626 	        .name = __startup_TUNABLES_name_ ## var, \
627 	        .var_addr = (void *)&var, \
628 	        .var_len = sizeof(type_t), \
629 	        .var_is_bool = __startup_type_is_bool(type_t), \
630 	}; \
631 	__STARTUP_ARG(var, __LINE__, TUNABLES, STARTUP_RANK_FIRST, \
632 	    kernel_startup_tunable_init, &__startup_TUNABLES_spec_ ## var)
633 
634 #define __TUNABLE_STR(var, key) \
635 	static __startup_data char __startup_TUNABLES_name_ ## var[] = key; \
636 	static __startup_data struct startup_tunable_spec \
637 	__startup_TUNABLES_spec_ ## var = { \
638 	        .name = __startup_TUNABLES_name_ ## var, \
639 	        .var_addr = (void *)&var, \
640 	        .var_len = sizeof(var), \
641 	        .var_is_str = true, \
642 	}; \
643 	__STARTUP_ARG(var, __LINE__, TUNABLES, STARTUP_RANK_FIRST, \
644 	    kernel_startup_tunable_init, &__startup_TUNABLES_spec_ ## var)
645 
646 #define __TUNABLE_DT(type_t, var, dt_base_key, dt_name_key, boot_arg_key, flags) \
647 	static __startup_data char __startup_TUNABLES_dt_base_ ## var[] = dt_base_key; \
648 	static __startup_data char __startup_TUNABLES_dt_name_ ## var[] = dt_name_key; \
649 	static __startup_data char __startup_TUNABLES_name_ ## var[] = boot_arg_key; \
650 	static __startup_data struct startup_tunable_dt_spec \
651 	__startup_TUNABLES_DT_spec_ ## var = { \
652 	        .dt_base = __startup_TUNABLES_dt_base_ ## var, \
653 	        .dt_name = __startup_TUNABLES_dt_name_ ## var, \
654 	        .dt_chosen_override = (bool)((flags) & TUNABLE_DT_CHECK_CHOSEN), \
655 	        .boot_arg_name = __startup_TUNABLES_name_ ## var, \
656 	        .var_addr = (void *)&var, \
657 	        .var_len = sizeof(type_t), \
658 	        .var_is_bool = __startup_type_is_bool(type_t), \
659 	}; \
660 	__STARTUP_ARG(var, __LINE__, TUNABLES, STARTUP_RANK_FIRST, \
661 	    kernel_startup_tunable_dt_init, &__startup_TUNABLES_DT_spec_ ## var)
662 
663 #ifdef __cplusplus
664 #define __STARTUP_FUNC_CAST(func, a) \
665 	    (void(*)(const void *))func
666 #else
667 #define __STARTUP_FUNC_CAST(func, a) \
668 	    (typeof(func(a))(*)(const void *))func
669 #endif
670 
671 
672 #define __STARTUP1(name, line, subsystem, rank, func, a, b) \
673 	__PLACE_IN_SECTION(STARTUP_HOOK_SEGMENT "," STARTUP_HOOK_SECTION) \
674 	static const struct startup_entry \
675 	__startup_ ## subsystem ## _entry_ ## name ## _ ## line = { \
676 	    STARTUP_SUB_ ## subsystem, \
677 	    rank, __STARTUP_FUNC_CAST(func, a), b, \
678 	}
679 
680 #define __STARTUP(name, line, subsystem, rank, func) \
681 	__STARTUP1(name, line, subsystem, rank, func, , NULL)
682 
683 #define __STARTUP_ARG(name, line, subsystem, rank, func, arg) \
684 	__STARTUP1(name, line, subsystem, rank, func, arg, arg)
685 
686 struct startup_entry {
687 	startup_subsystem_id_t subsystem;
688 	startup_rank_t         rank;
689 	void                 (*func)(const void *);
690 	const void            *arg;
691 };
692 
693 struct startup_tunable_spec {
694 	const char *name;
695 	void       *var_addr;
696 	int         var_len;
697 	bool        var_is_bool;
698 	bool        var_is_str;
699 };
700 
701 struct startup_tunable_dt_spec {
702 	const char *dt_base;
703 	const char *dt_name;
704 	bool        dt_chosen_override;
705 	const char *boot_arg_name;
706 	void       *var_addr;
707 	int         var_len;
708 	bool        var_is_bool;
709 };
710 
711 #if DEBUG || DEVELOPMENT
712 struct sysctl_test_setup_spec {
713 	const char *st_name;
714 	int (*st_func)(int64_t, int64_t *);
715 };
716 
717 extern void sysctl_register_test_startup(
718 	struct sysctl_test_setup_spec *spec);
719 #endif /* DEBUG || DEVELOPMENT */
720 
721 /*
722  * Kernel and machine startup declarations
723  */
724 
725 /* Initialize kernel */
726 extern void kernel_startup_bootstrap(void);
727 extern void kernel_startup_initialize_upto(startup_subsystem_id_t upto);
728 extern void kernel_startup_tunable_init(const struct startup_tunable_spec *);
729 extern void kernel_startup_tunable_dt_init(const struct startup_tunable_dt_spec *);
730 extern void kernel_bootstrap(void);
731 
732 /* Initialize machine dependent stuff */
733 extern void machine_init(void);
734 
735 extern void slave_main(void *machine_param);
736 
737 /*
738  * The following must be implemented in machine dependent code.
739  */
740 
741 /* Slave cpu initialization */
742 extern void slave_machine_init(void *machine_param);
743 
744 /* Device subystem initialization */
745 extern void device_service_create(void);
746 
747 #ifdef  MACH_BSD
748 
749 /* BSD subsystem initialization */
750 extern void bsd_init(void);
751 
752 #endif  /* MACH_BSD */
753 
754 #pragma GCC visibility pop
755 
756 __END_DECLS
757 
758 #endif  /* _KERN_STARTUP_H_ */
759 
760 #endif  /* XNU_KERNEL_PRIVATE */
761