]>
Commit | Line | Data |
---|---|---|
39037602 A |
1 | What is XNU? |
2 | =========== | |
3 | ||
a39ff7e2 | 4 | XNU kernel is part of the Darwin operating system for use in macOS and iOS operating systems. XNU is an acronym for X is Not Unix. |
d9a64523 | 5 | XNU is a hybrid kernel combining the Mach kernel developed at Carnegie Mellon University with components from FreeBSD and a C++ API for writing drivers called IOKit. |
a39ff7e2 | 6 | XNU runs on x86_64 for both single processor and multi-processor configurations. |
39037602 A |
7 | |
8 | XNU Source Tree | |
9 | =============== | |
10 | ||
11 | * `config` - configurations for exported apis for supported architecture and platform | |
12 | * `SETUP` - Basic set of tools used for configuring the kernel, versioning and kextsymbol management. | |
13 | * `EXTERNAL_HEADERS` - Headers sourced from other projects to avoid dependency cycles when building. These headers should be regularly synced when source is updated. | |
14 | * `libkern` - C++ IOKit library code for handling of drivers and kexts. | |
15 | * `libsa` - kernel bootstrap code for startup | |
16 | * `libsyscall` - syscall library interface for userspace programs | |
17 | * `libkdd` - source for user library for parsing kernel data like kernel chunked data. | |
18 | * `makedefs` - top level rules and defines for kernel build. | |
19 | * `osfmk` - Mach kernel based subsystems | |
20 | * `pexpert` - Platform specific code like interrupt handling, atomics etc. | |
21 | * `security` - Mandatory Access Check policy interfaces and related implementation. | |
22 | * `bsd` - BSD subsystems code | |
23 | * `tools` - A set of utilities for testing, debugging and profiling kernel. | |
24 | ||
25 | How to build XNU | |
26 | ================ | |
27 | ||
28 | Building `DEVELOPMENT` kernel | |
29 | ----------------------------- | |
30 | ||
31 | The xnu make system can build kernel based on `KERNEL_CONFIGS` & `ARCH_CONFIGS` variables as arguments. | |
32 | Here is the syntax: | |
33 | ||
34 | make SDKROOT=<sdkroot> ARCH_CONFIGS=<arch> KERNEL_CONFIGS=<variant> | |
35 | ||
36 | Where: | |
37 | ||
a39ff7e2 | 38 | * \<sdkroot>: path to macOS SDK on disk. (defaults to `/`) |
39037602 | 39 | * \<variant>: can be `debug`, `development`, `release`, `profile` and configures compilation flags and asserts throughout kernel code. |
a39ff7e2 | 40 | * \<arch> : can be valid arch to build for. (E.g. `X86_64`) |
39037602 A |
41 | |
42 | To build a kernel for the same architecture as running OS, just type | |
43 | ||
44 | $ make | |
45 | $ make SDKROOT=macosx.internal | |
46 | ||
47 | Additionally, there is support for configuring architectures through `ARCH_CONFIGS` and kernel configurations with `KERNEL_CONFIGS`. | |
48 | ||
49 | $ make SDKROOT=macosx.internal ARCH_CONFIGS=X86_64 KERNEL_CONFIGS=DEVELOPMENT | |
50 | $ make SDKROOT=macosx.internal ARCH_CONFIGS=X86_64 KERNEL_CONFIGS="RELEASE DEVELOPMENT DEBUG" | |
51 | ||
52 | ||
53 | Note: | |
54 | * By default, architecture is set to the build machine architecture, and the default kernel | |
55 | config is set to build for DEVELOPMENT. | |
56 | ||
57 | ||
58 | This will also create a bootable image, kernel.[config], and a kernel binary | |
59 | with symbols, kernel.[config].unstripped. | |
60 | ||
61 | ||
62 | * To build with RELEASE kernel configuration | |
63 | ||
64 | make KERNEL_CONFIGS=RELEASE SDKROOT=/path/to/SDK | |
65 | ||
66 | ||
67 | Building FAT kernel binary | |
68 | -------------------------- | |
69 | ||
70 | Define architectures in your environment or when running a make command. | |
71 | ||
a39ff7e2 | 72 | $ make ARCH_CONFIGS="X86_64" exporthdrs all |
39037602 A |
73 | |
74 | Other makefile options | |
75 | ---------------------- | |
76 | ||
77 | * $ make MAKEJOBS=-j8 # this will use 8 processes during the build. The default is 2x the number of active CPUS. | |
78 | * $ make -j8 # the standard command-line option is also accepted | |
79 | * $ make -w # trace recursive make invocations. Useful in combination with VERBOSE=YES | |
80 | * $ make BUILD_LTO=0 # build without LLVM Link Time Optimization | |
81 | * $ make REMOTEBUILD=user@remotehost # perform build on remote host | |
82 | * $ make BUILD_JSON_COMPILATION_DATABASE=1 # Build Clang JSON Compilation Database | |
83 | ||
5ba3f43e A |
84 | The XNU build system can optionally output color-formatted build output. To enable this, you can either |
85 | set the `XNU_LOGCOLORS` environment variable to `y`, or you can pass `LOGCOLORS=y` to the make command. | |
39037602 A |
86 | |
87 | ||
88 | Debug information formats | |
89 | ========================= | |
90 | ||
91 | By default, a DWARF debug information repository is created during the install phase; this is a "bundle" named kernel.development.\<variant>.dSYM | |
92 | To select the older STABS debug information format (where debug information is embedded in the kernel.development.unstripped image), set the BUILD_STABS environment variable. | |
93 | ||
94 | $ export BUILD_STABS=1 | |
95 | $ make | |
96 | ||
97 | ||
98 | Building KernelCaches | |
99 | ===================== | |
100 | ||
101 | To test the xnu kernel, you need to build a kernelcache that links the kexts and | |
102 | kernel together into a single bootable image. | |
103 | To build a kernelcache you can use the following mechanisms: | |
104 | ||
105 | * Using automatic kernelcache generation with `kextd`. | |
cb323159 | 106 | The kextd daemon keeps watching for changing in `/System/Library/Extensions` directory. |
39037602 A |
107 | So you can setup new kernel as |
108 | ||
109 | $ cp BUILD/obj/DEVELOPMENT/X86_64/kernel.development /System/Library/Kernels/ | |
110 | $ touch /System/Library/Extensions | |
111 | $ ps -e | grep kextd | |
112 | ||
113 | * Manually invoking `kextcache` to build new kernelcache. | |
114 | ||
115 | $ kextcache -q -z -a x86_64 -l -n -c /var/tmp/kernelcache.test -K /var/tmp/kernel.test /System/Library/Extensions | |
116 | ||
117 | ||
118 | ||
119 | Running KernelCache on Target machine | |
120 | ===================================== | |
121 | ||
122 | The development kernel and iBoot supports configuring boot arguments so that we can safely boot into test kernel and, if things go wrong, safely fall back to previously used kernelcache. | |
123 | Following are the steps to get such a setup: | |
124 | ||
125 | 1. Create kernel cache using the kextcache command as `/kernelcache.test` | |
126 | 2. Copy exiting boot configurations to alternate file | |
127 | ||
128 | $ cp /Library/Preferences/SystemConfiguration/com.apple.Boot.plist /next_boot.plist | |
129 | ||
130 | 3. Update the kernelcache and boot-args for your setup | |
131 | ||
132 | $ plutil -insert "Kernel Cache" -string "kernelcache.test" /next_boot.plist | |
133 | $ plutil -replace "Kernel Flags" -string "debug=0x144 -v kernelsuffix=test " /next_boot.plist | |
134 | ||
135 | 4. Copy the new config to `/Library/Preferences/SystemConfiguration/` | |
136 | ||
137 | $ cp /next_boot.plist /Library/Preferences/SystemConfiguration/boot.plist | |
138 | ||
139 | 5. Bless the volume with new configs. | |
140 | ||
141 | $ sudo -n bless --mount / --setBoot --nextonly --options "config=boot" | |
142 | ||
143 | The `--nextonly` flag specifies that use the `boot.plist` configs only for one boot. | |
144 | So if the kernel panic's you can easily power reboot and recover back to original kernel. | |
145 | ||
146 | ||
147 | ||
148 | ||
149 | Creating tags and cscope | |
150 | ======================== | |
151 | ||
152 | Set up your build environment and from the top directory, run: | |
153 | ||
154 | $ make tags # this will build ctags and etags on a case-sensitive volume, only ctags on case-insensitive | |
155 | $ make TAGS # this will build etags | |
156 | $ make cscope # this will build cscope database | |
157 | ||
158 | ||
0a7de745 A |
159 | Code Style |
160 | ========== | |
39037602 | 161 | |
0a7de745 A |
162 | Source files can be reformatted to comply with the xnu code style using the "restyle" make target invoked from the |
163 | top-level project directory. | |
39037602 | 164 | |
0a7de745 | 165 | $ make restyle # re-format all source files to be xnu code style conformant. |
39037602 | 166 | |
0a7de745 | 167 | Compliance can be checked using the "checkstyle" make target. |
39037602 | 168 | |
0a7de745 | 169 | $ make checkstyle # Check all relevant source files for xnu code style conformance. |
39037602 A |
170 | |
171 | How to install a new header file from XNU | |
172 | ========================================= | |
173 | ||
174 | To install IOKit headers, see additional comments in [iokit/IOKit/Makefile](). | |
175 | ||
176 | XNU installs header files at the following locations - | |
177 | ||
178 | a. $(DSTROOT)/System/Library/Frameworks/Kernel.framework/Headers | |
179 | b. $(DSTROOT)/System/Library/Frameworks/Kernel.framework/PrivateHeaders | |
180 | c. $(DSTROOT)/usr/include/ | |
cb323159 A |
181 | d. $(DSTROOT)/System/DriverKit/usr/include/ |
182 | e. $(DSTROOT)/System/Library/Frameworks/System.framework/PrivateHeaders | |
39037602 A |
183 | |
184 | `Kernel.framework` is used by kernel extensions.\ | |
185 | The `System.framework` and `/usr/include` are used by user level applications. \ | |
cb323159 | 186 | `/System/DriverKit/usr/include` is used by userspace drivers. \ |
39037602 A |
187 | The header files in framework's `PrivateHeaders` are only available for ** Apple Internal Development **. |
188 | ||
189 | The directory containing the header file should have a Makefile that | |
190 | creates the list of files that should be installed at different locations. | |
d9a64523 A |
191 | If you are adding the first header file in a directory, you will need to |
192 | create Makefile similar to `xnu/bsd/sys/Makefile`. | |
39037602 A |
193 | |
194 | Add your header file to the correct file list depending on where you want | |
195 | to install it. The default locations where the header files are installed | |
196 | from each file list are - | |
197 | ||
198 | a. `DATAFILES` : To make header file available in user level - | |
199 | `$(DSTROOT)/usr/include` | |
200 | ||
cb323159 A |
201 | b. `DRIVERKIT_DATAFILES` : To make header file available to DriverKit userspace drivers - |
202 | `$(DSTROOT)/System/DriverKit/usr/include` | |
203 | ||
204 | c. `PRIVATE_DATAFILES` : To make header file available to Apple internal in | |
39037602 A |
205 | user level - |
206 | `$(DSTROOT)/System/Library/Frameworks/System.framework/PrivateHeaders` | |
207 | ||
cb323159 | 208 | d. `KERNELFILES` : To make header file available in kernel level - |
39037602 A |
209 | `$(DSTROOT)/System/Library/Frameworks/Kernel.framework/Headers` |
210 | `$(DSTROOT)/System/Library/Frameworks/Kernel.framework/PrivateHeaders` | |
211 | ||
cb323159 | 212 | e. `PRIVATE_KERNELFILES` : To make header file available to Apple internal |
39037602 A |
213 | for kernel extensions - |
214 | `$(DSTROOT)/System/Library/Frameworks/Kernel.framework/PrivateHeaders` | |
215 | ||
216 | The Makefile combines the file lists mentioned above into different | |
d9a64523 A |
217 | install lists which are used by build system to install the header files. There |
218 | are two types of install lists: machine-dependent and machine-independent. | |
219 | These lists are indicated by the presence of `MD` and `MI` in the build | |
220 | setting, respectively. If your header is architecture-specific, then you should | |
221 | use a machine-dependent install list (e.g. `INSTALL_MD_LIST`). If your header | |
222 | should be installed for all architectures, then you should use a | |
223 | machine-independent install list (e.g. `INSTALL_MI_LIST`). | |
39037602 A |
224 | |
225 | If the install list that you are interested does not exist, create it | |
226 | by adding the appropriate file lists. The default install lists, its | |
227 | member file lists and their default location are described below - | |
228 | ||
229 | a. `INSTALL_MI_LIST` : Installs header file to a location that is available to everyone in user level. | |
230 | Locations - | |
231 | $(DSTROOT)/usr/include | |
232 | Definition - | |
233 | INSTALL_MI_LIST = ${DATAFILES} | |
234 | ||
cb323159 A |
235 | b. `INSTALL_DRIVERKIT_MI_LIST` : Installs header file to a location that is |
236 | available to DriverKit userspace drivers. | |
237 | Locations - | |
238 | $(DSTROOT)/System/DriverKit/usr/include | |
239 | Definition - | |
240 | INSTALL_DRIVERKIT_MI_LIST = ${DRIVERKIT_DATAFILES} | |
241 | ||
242 | c. `INSTALL_MI_LCL_LIST` : Installs header file to a location that is available | |
39037602 A |
243 | for Apple internal in user level. |
244 | Locations - | |
245 | $(DSTROOT)/System/Library/Frameworks/System.framework/PrivateHeaders | |
246 | Definition - | |
247 | INSTALL_MI_LCL_LIST = ${PRIVATE_DATAFILES} | |
248 | ||
cb323159 | 249 | d. `INSTALL_KF_MI_LIST` : Installs header file to location that is available |
39037602 A |
250 | to everyone for kernel extensions. |
251 | Locations - | |
252 | $(DSTROOT)/System/Library/Frameworks/Kernel.framework/Headers | |
253 | Definition - | |
254 | INSTALL_KF_MI_LIST = ${KERNELFILES} | |
255 | ||
cb323159 | 256 | e. `INSTALL_KF_MI_LCL_LIST` : Installs header file to location that is |
39037602 A |
257 | available for Apple internal for kernel extensions. |
258 | Locations - | |
259 | $(DSTROOT)/System/Library/Frameworks/Kernel.framework/PrivateHeaders | |
260 | Definition - | |
261 | INSTALL_KF_MI_LCL_LIST = ${KERNELFILES} ${PRIVATE_KERNELFILES} | |
262 | ||
cb323159 | 263 | f. `EXPORT_MI_LIST` : Exports header file to all of xnu (bsd/, osfmk/, etc.) |
5ba3f43e A |
264 | for compilation only. Does not install anything into the SDK. |
265 | Definition - | |
266 | EXPORT_MI_LIST = ${KERNELFILES} ${PRIVATE_KERNELFILES} | |
267 | ||
39037602 A |
268 | If you want to install the header file in a sub-directory of the paths |
269 | described in (1), specify the directory name using two variables | |
270 | `INSTALL_MI_DIR` and `EXPORT_MI_DIR` as follows - | |
271 | ||
272 | INSTALL_MI_DIR = dirname | |
273 | EXPORT_MI_DIR = dirname | |
274 | ||
275 | A single header file can exist at different locations using the steps | |
276 | mentioned above. However it might not be desirable to make all the code | |
277 | in the header file available at all the locations. For example, you | |
278 | want to export a function only to kernel level but not user level. | |
279 | ||
280 | You can use C language's pre-processor directive (#ifdef, #endif, #ifndef) | |
281 | to control the text generated before a header file is installed. The kernel | |
282 | only includes the code if the conditional macro is TRUE and strips out | |
283 | code for FALSE conditions from the header file. | |
284 | ||
285 | Some pre-defined macros and their descriptions are - | |
286 | ||
d9a64523 A |
287 | a. `PRIVATE` : If defined, enclosed definitions are considered System |
288 | Private Interfaces. These are visible within xnu and | |
289 | exposed in user/kernel headers installed within the AppleInternal | |
290 | "PrivateHeaders" sections of the System and Kernel frameworks. | |
291 | b. `KERNEL_PRIVATE` : If defined, enclosed code is available to all of xnu | |
292 | kernel and Apple internal kernel extensions and omitted from user | |
293 | headers. | |
294 | c. `BSD_KERNEL_PRIVATE` : If defined, enclosed code is visible exclusively | |
295 | within the xnu/bsd module. | |
296 | d. `MACH_KERNEL_PRIVATE`: If defined, enclosed code is visible exclusively | |
297 | within the xnu/osfmk module. | |
298 | e. `XNU_KERNEL_PRIVATE`: If defined, enclosed code is visible exclusively | |
299 | within xnu. | |
300 | f. `KERNEL` : If defined, enclosed code is available within xnu and kernel | |
301 | extensions and is not visible in user level header files. Only the | |
39037602 A |
302 | header files installed in following paths will have the code - |
303 | ||
304 | $(DSTROOT)/System/Library/Frameworks/Kernel.framework/Headers | |
305 | $(DSTROOT)/System/Library/Frameworks/Kernel.framework/PrivateHeaders | |
cb323159 A |
306 | g. `DRIVERKIT`: If defined, enclosed code is visible exclusively in the |
307 | DriverKit SDK headers used by userspace drivers. | |
39037602 | 308 | |
d9a64523 A |
309 | Conditional compilation |
310 | ======================= | |
311 | ||
312 | `xnu` offers the following mechanisms for conditionally compiling code: | |
313 | ||
314 | a. *CPU Characteristics* If the code you are guarding has specific | |
315 | characterstics that will vary only based on the CPU architecture being | |
316 | targeted, use this option. Prefer checking for features of the | |
317 | architecture (e.g. `__LP64__`, `__LITTLE_ENDIAN__`, etc.). | |
318 | b. *New Features* If the code you are guarding, when taken together, | |
319 | implements a feature, you should define a new feature in `config/MASTER` | |
320 | and use the resulting `CONFIG` preprocessor token (e.g. for a feature | |
321 | named `config_virtual_memory`, check for `#if CONFIG_VIRTUAL_MEMORY`). | |
322 | This practice ensures that existing features may be brought to other | |
323 | platforms by simply changing a feature switch. | |
324 | c. *Existing Features* You can use existing features if your code is | |
325 | strongly tied to them (e.g. use `SECURE_KERNEL` if your code implements | |
326 | new functionality that is exclusively relevant to the trusted kernel and | |
327 | updates the definition/understanding of what being a trusted kernel means). | |
328 | ||
329 | It is recommended that you avoid compiling based on the target platform. `xnu` | |
330 | does not define the platform macros from `TargetConditionals.h` | |
331 | (`TARGET_OS_OSX`, `TARGET_OS_IOS`, etc.). | |
332 | ||
333 | ||
cb323159 A |
334 | There is a deprecated `TARGET_OS_EMBEDDED` macro, but this should be avoided |
335 | as it is in general too broad a definition for most functionality. | |
336 | Please refer to TargetConditionals.h for a full picture. | |
39037602 A |
337 | |
338 | How to add a new syscall | |
339 | ======================== | |
340 | ||
341 | ||
342 | ||
343 | ||
344 | Testing the kernel | |
345 | ================== | |
346 | ||
347 | XNU kernel has multiple mechanisms for testing. | |
348 | ||
349 | * Assertions - The DEVELOPMENT and DEBUG kernel configs are compiled with assertions enabled. This allows developers to easily | |
350 | test invariants and conditions. | |
351 | ||
352 | * XNU Power On Self Tests (`XNUPOST`): The XNUPOST config allows for building the kernel with basic set of test functions | |
353 | that are run before first user space process is launched. Since XNU is hybrid between MACH and BSD, we have two locations where | |
354 | tests can be added. | |
355 | ||
356 | xnu/osfmk/tests/ # For testing mach based kernel structures and apis. | |
357 | bsd/tests/ # For testing BSD interfaces. | |
358 | Please follow the documentation at [osfmk/tests/README.md](osfmk/tests/README.md) | |
359 | ||
360 | * User level tests: The `tools/tests/` directory holds all the tests that verify syscalls and other features of the xnu kernel. | |
361 | The make target `xnu_tests` can be used to build all the tests supported. | |
362 | ||
363 | $ make RC_ProjectName=xnu_tests SDKROOT=/path/to/SDK | |
364 | ||
365 | These tests are individual programs that can be run from Terminal and report tests status by means of std posix exit codes (0 -> success) and/or stdout. | |
366 | Please read detailed documentation in [tools/tests/unit_tests/README.md](tools/tests/unit_tests/README.md) | |
367 | ||
368 | ||
369 | Kernel data descriptors | |
370 | ======================= | |
371 | ||
372 | XNU uses different data formats for passing data in its api. The most standard way is using syscall arguments. But for complex data | |
373 | it often relies of sending memory saved by C structs. This packaged data transport mechanism is fragile and leads to broken interfaces | |
374 | between user space programs and kernel apis. `libkdd` directory holds user space library that can parse custom data provided by the | |
375 | same version of kernel. The kernel chunked data format is described in detail at [libkdd/README.md](libkdd/README.md). | |
376 | ||
377 | ||
378 | Debugging the kernel | |
379 | ==================== | |
380 | ||
381 | The xnu kernel supports debugging with a remote kernel debugging protocol (kdp). Please refer documentation at [technical note] [TN2063] | |
382 | By default the kernel is setup to reboot on a panic. To debug a live kernel, the kdp server is setup to listen for UDP connections | |
383 | over ethernet. For machines without ethernet port, this behavior can be altered with use of kernel boot-args. Following are some | |
384 | common options. | |
385 | ||
386 | * `debug=0x144` - setups debug variables to start kdp debugserver on panic | |
387 | * `-v` - print kernel logs on screen. By default XNU only shows grey screen with boot art. | |
388 | * `kdp_match_name=en1` - Override default port selection for kdp. Supported for ethernet, thunderbolt and serial debugging. | |
389 | ||
390 | To debug a panic'ed kernel, use llvm debugger (lldb) along with unstripped symbol rich kernel binary. | |
391 | ||
392 | sh$ lldb kernel.development.unstripped | |
cb323159 | 393 | |
39037602 A |
394 | And then you can connect to panic'ed machine with `kdp_remote [ip addr]` or `gdb_remote [hostip : port]` commands. |
395 | ||
396 | Each kernel is packaged with kernel specific debug scripts as part of the build process. For security reasons these special commands | |
397 | and scripts do not get loaded automatically when lldb is connected to machine. Please add the following setting to your `~/.lldbinit` | |
398 | if you wish to always load these macros. | |
399 | ||
400 | settings set target.load-script-from-symbol-file true | |
401 | ||
402 | The `tools/lldbmacros` directory contains the source for each of these commands. Please follow the [README.md](tools/lldbmacros/README.md) | |
403 | for detailed explanation of commands and their usage. | |
404 | ||
405 | [TN2118]: https://developer.apple.com/library/mac/technotes/tn2004/tn2118.html#//apple_ref/doc/uid/DTS10003352 "Kernel Core Dumps" | |
406 | [TN2063]: https://developer.apple.com/library/mac/technotes/tn2063/_index.html "Understanding and Debugging Kernel Panics" | |
407 | [Kernel Programming Guide]: https://developer.apple.com/library/mac/documentation/Darwin/Conceptual/KernelProgramming/build/build.html#//apple_ref/doc/uid/TP30000905-CH221-BABDGEGF |