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