]> git.saurik.com Git - apple/xnu.git/blob - osfmk/kern/startup.h
bd574100a73df7e5d846fae93df2e72652f0af9b
[apple/xnu.git] / osfmk / kern / startup.h
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_LOCKS_EARLY, /**< early locking, before zalloc */
62 STARTUP_SUB_KPRINTF, /**< kprintf initialization */
63
64 STARTUP_SUB_PMAP_STEAL, /**< to perform various pmap carveouts */
65 STARTUP_SUB_VM_KERNEL, /**< once the kernel VM is ready */
66 STARTUP_SUB_KMEM, /**< once kmem is ready */
67 STARTUP_SUB_KMEM_ALLOC, /**< once kmem_alloc is ready */
68 STARTUP_SUB_ZALLOC, /**< initialize zalloc and kalloc */
69 STARTUP_SUB_PERCPU, /**< initialize the percpu subsystem */
70 STARTUP_SUB_LOCKS, /**< various subsystem locks */
71
72 STARTUP_SUB_CODESIGNING, /**< codesigning subsystem */
73 STARTUP_SUB_OSLOG, /**< oslog and kernel loggging */
74 STARTUP_SUB_MACH_IPC, /**< Mach IPC */
75 STARTUP_SUB_EARLY_BOOT, /**< interrupts/premption are turned on */
76
77 STARTUP_SUB_LOCKDOWN = ~0u, /**< reserved for the startup subsystem */
78 });
79
80 /*!
81 * Stores the last subsystem to have been fully initialized;
82 */
83 extern startup_subsystem_id_t startup_phase;
84
85 /*!
86 * @enum startup_debug_t
87 *
88 * @abstract
89 * Flags set in the @c startup_debug global to configure startup debugging.
90 */
91 __options_decl(startup_debug_t, uint32_t, {
92 STARTUP_DEBUG_NONE = 0x00000000,
93 STARTUP_DEBUG_VERBOSE = 0x00000001,
94 });
95
96 #if DEBUG || DEVELOPMENT
97 extern startup_debug_t startup_debug;
98 #else
99 #define startup_debug STARTUP_DEBUG_NONE
100 #endif
101
102 /*!
103 * @enum startup_rank
104 *
105 * @abstract
106 * Specifies in which rank a given initializer runs within a given section
107 * to register initializers for a specific rank within the subsystem.
108 *
109 * @description
110 * A startup function, declared with @c STARTUP or @c STARTUP_ARG, can specify
111 * an rank within the subsystem they initialize.
112 *
113 * @c STARTUP_RANK_NTH(n) will let callbacks be run at stage @c n (0-based).
114 *
115 * @c STARTUP_RANK_FIRST, @c STARTUP_RANK_SECOND, @c STARTUP_RANK_THIRD and
116 * @c STARTUP_RANK_FOURTH are given as conveniency names for these.
117 *
118 * @c STARTUP_RANK_MIDDLE is a reserved value that will let startup functions
119 * run after all the @c STARTUP_RANK_NTH(n) ones have.
120 *
121 * @c STARTUP_RANK_NTH_LATE_NTH(n) will let callbacks be run then in @c n rank
122 * after the @c STARTUP_RANK_MIDDLE ones (0-based).
123 *
124 * @c STARTUP_RANK_LAST callbacks will run absolutely last after everything
125 * else did for this subsystem.
126 */
127 __enum_decl(startup_rank_t, uint32_t, {
128 #define STARTUP_RANK_NTH(n) \
129 (enum startup_rank)(n)
130 STARTUP_RANK_FIRST = 0,
131 STARTUP_RANK_SECOND = 1,
132 STARTUP_RANK_THIRD = 2,
133 STARTUP_RANK_FOURTH = 3,
134
135 STARTUP_RANK_MIDDLE = 0x7fffffff,
136
137 #define STARTUP_RANK_LATE_NTH(n) \
138 (enum startup_rank)(STARTUP_RANK_MIDDLE + 1 + (n))
139
140 STARTUP_RANK_LAST = 0xffffffff,
141 });
142
143 #if KASAN
144 /*
145 * The use of weird sections that get unmapped confuse the hell out of kasan,
146 * so for KASAN leave things in regular __TEXT/__DATA segments
147 */
148 #define STARTUP_CODE_SEGSECT "__TEXT,__text"
149 #define STARTUP_DATA_SEGSECT "__DATA,__init"
150 #define STARTUP_HOOK_SEGMENT "__DATA"
151 #define STARTUP_HOOK_SECTION "__init_entry_set"
152 #elif defined(__x86_64__)
153 /* Intel doesn't have a __BOOTDATA but doesn't protect __KLD */
154 #define STARTUP_CODE_SEGSECT "__TEXT,__text"
155 #define STARTUP_DATA_SEGSECT "__KLD,__init"
156 #define STARTUP_HOOK_SEGMENT "__KLD"
157 #define STARTUP_HOOK_SECTION "__init_entry_set"
158 #else
159 /* arm protects __KLD early, so use __BOOTDATA for data */
160 #define STARTUP_CODE_SEGSECT "__TEXT,__text"
161 #define STARTUP_DATA_SEGSECT "__BOOTDATA,__init"
162 #define STARTUP_HOOK_SEGMENT "__BOOTDATA"
163 #define STARTUP_HOOK_SECTION "__init_entry_set"
164 #endif
165
166 /*!
167 * @macro __startup_func
168 *
169 * @abstract
170 * Attribute to place on functions used only during the kernel startup phase.
171 *
172 * @description
173 * Code marked with this attribute will be unmapped after kernel lockdown.
174 */
175 #define __startup_func \
176 __PLACE_IN_SECTION(STARTUP_CODE_SEGSECT) \
177 __attribute__((noinline, visibility("hidden")))
178
179 /*!
180 * @macro __startup_data
181 *
182 * @abstract
183 * Attribute to place on globals used during the kernel startup phase.
184 *
185 * @description
186 * Data marked with this attribute will be unmapped after kernel lockdown.
187 */
188 #define __startup_data \
189 __PLACE_IN_SECTION(STARTUP_DATA_SEGSECT)
190
191 /*!
192 * @macro STARTUP
193 *
194 * @abstract
195 * Declares a kernel startup callback.
196 */
197 #define STARTUP(subsystem, rank, func) \
198 __STARTUP(func, __LINE__, subsystem, rank, func)
199
200 /*!
201 * @macro STARTUP_ARG
202 *
203 * @abstract
204 * Declares a kernel startup callback that takes an argument.
205 */
206 #define STARTUP_ARG(subsystem, rank, func, arg) \
207 __STARTUP_ARG(func, __LINE__, subsystem, rank, func, arg)
208
209 /*!
210 * @macro TUNABLE
211 *
212 * @abstract
213 * Declares a read-only kernel tunable that is read from a boot-arg with
214 * a default value, without further processing.
215 *
216 * @param type_t
217 * Should be an integer type or bool.
218 *
219 * @param var
220 * The name of the C variable to use for storage.
221 *
222 * @param key
223 * The name of the boot-arg to parse for initialization
224 *
225 * @param default_value
226 * The default value for the tunable if the boot-arg is absent.
227 */
228 #define TUNABLE(type_t, var, key, default_value) \
229 SECURITY_READ_ONLY_LATE(type_t) var = default_value; \
230 __TUNABLE(type_t, var, key)
231
232 /*!
233 * @macro TUNABLE_WRITEABLE
234 *
235 * @abstract
236 * Declares a writeable kernel tunable that is read from a boot-arg with
237 * a default value, without further processing.
238 *
239 * @param type_t
240 * Should be an integer type or bool.
241 *
242 * @param var
243 * The name of the C variable to use for storage.
244 *
245 * @param key
246 * The name of the boot-arg to parse for initialization
247 *
248 * @param default_value
249 * The default value for the tunable if the boot-arg is absent.
250 */
251 #define TUNABLE_WRITEABLE(type_t, var, key, default_value) \
252 type_t var = default_value; \
253 __TUNABLE(type_t, var, key)
254
255 #pragma mark - internals
256
257 #define __TUNABLE(type_t, var, key) \
258 static __startup_data char __startup_TUNABLES_name_ ## var[] = key; \
259 static __startup_data struct startup_tunable_spec \
260 __startup_TUNABLES_spec_ ## var = { \
261 .name = __startup_TUNABLES_name_ ## var, \
262 .var_addr = &var, \
263 .var_len = sizeof(type_t), \
264 .var_is_bool = __builtin_types_compatible_p(bool, type_t), \
265 }; \
266 __STARTUP_ARG(var, __LINE__, TUNABLES, STARTUP_RANK_FIRST, \
267 kernel_startup_tunable_init, &__startup_TUNABLES_spec_ ## var)
268
269
270 #define __STARTUP1(name, line, subsystem, rank, func, a, b) \
271 __PLACE_IN_SECTION(STARTUP_HOOK_SEGMENT "," STARTUP_HOOK_SECTION) \
272 static const struct startup_entry \
273 __startup_ ## subsystem ## _entry_ ## name ## _ ## line = { \
274 STARTUP_SUB_ ## subsystem, \
275 rank, (typeof(func(a))(*)(const void *))func, b, \
276 }
277
278 #define __STARTUP(name, line, subsystem, rank, func) \
279 __STARTUP1(name, line, subsystem, rank, func, , NULL)
280
281 #define __STARTUP_ARG(name, line, subsystem, rank, func, arg) \
282 __STARTUP1(name, line, subsystem, rank, func, arg, arg)
283
284 struct startup_entry {
285 startup_subsystem_id_t subsystem;
286 startup_rank_t rank;
287 void (*func)(const void *);
288 const void *arg;
289 };
290
291 struct startup_tunable_spec {
292 const char *name;
293 void *var_addr;
294 int var_len;
295 bool var_is_bool;
296 };
297
298 /*
299 * Kernel and machine startup declarations
300 */
301
302 /* Initialize kernel */
303 extern void kernel_startup_bootstrap(void);
304 extern void kernel_startup_initialize_upto(startup_subsystem_id_t upto);
305 extern void kernel_startup_tunable_init(const struct startup_tunable_spec *);
306 extern void kernel_bootstrap(void);
307
308 /* Initialize machine dependent stuff */
309 extern void machine_init(void);
310
311 extern void slave_main(void *machine_param);
312
313 /*
314 * The following must be implemented in machine dependent code.
315 */
316
317 /* Slave cpu initialization */
318 extern void slave_machine_init(void *machine_param);
319
320 /* Device subystem initialization */
321 extern void device_service_create(void);
322
323 #ifdef MACH_BSD
324
325 /* BSD subsystem initialization */
326 extern void bsd_init(void);
327 extern void bsd_early_init(void);
328
329 #endif /* MACH_BSD */
330
331 #pragma GCC visibility pop
332
333 __END_DECLS
334
335 #endif /* _KERN_STARTUP_H_ */
336
337 #endif /* XNU_KERNEL_PRIVATE */