]>
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. |
39037602 | 5 | XNU is a hybrid kernel combining the Mach kernel developed at Carnegie Mellon University with components from FreeBSD and 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`. | |
106 | The kextd daemon keeps watching for changing in `/System/Library/Extensions` directory. | |
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 | ||
159 | Coding styles (Reindenting files) | |
160 | ================================= | |
161 | ||
162 | Source files can be reindented using clang-format setup in .clang-format. | |
163 | XNU follows a variant of WebKit style for source code formatting. | |
164 | Please refer to format styles at [WebKit website](http://www.webkit.org/coding/coding-style.html). | |
165 | Further options about style options is available at [clang docs](http://clang.llvm.org/docs/ClangFormatStyleOptions.html) | |
166 | ||
167 | Note: clang-format binary may not be part of base installation. It can be compiled from llvm clang sources and is reachable in $PATH. | |
168 | ||
169 | From the top directory, run: | |
170 | ||
171 | $ make reindent # reindent all source files using clang format. | |
172 | ||
173 | ||
174 | ||
175 | How to install a new header file from XNU | |
176 | ========================================= | |
177 | ||
178 | To install IOKit headers, see additional comments in [iokit/IOKit/Makefile](). | |
179 | ||
180 | XNU installs header files at the following locations - | |
181 | ||
182 | a. $(DSTROOT)/System/Library/Frameworks/Kernel.framework/Headers | |
183 | b. $(DSTROOT)/System/Library/Frameworks/Kernel.framework/PrivateHeaders | |
184 | c. $(DSTROOT)/usr/include/ | |
185 | d. $(DSTROOT)/System/Library/Frameworks/System.framework/PrivateHeaders | |
186 | ||
187 | `Kernel.framework` is used by kernel extensions.\ | |
188 | The `System.framework` and `/usr/include` are used by user level applications. \ | |
189 | The header files in framework's `PrivateHeaders` are only available for ** Apple Internal Development **. | |
190 | ||
191 | The directory containing the header file should have a Makefile that | |
192 | creates the list of files that should be installed at different locations. | |
193 | If you are adding first header file in a directory, you will need to | |
194 | create Makefile similar to xnu/bsd/sys/Makefile. | |
195 | ||
196 | Add your header file to the correct file list depending on where you want | |
197 | to install it. The default locations where the header files are installed | |
198 | from each file list are - | |
199 | ||
200 | a. `DATAFILES` : To make header file available in user level - | |
201 | `$(DSTROOT)/usr/include` | |
202 | ||
203 | b. `PRIVATE_DATAFILES` : To make header file available to Apple internal in | |
204 | user level - | |
205 | `$(DSTROOT)/System/Library/Frameworks/System.framework/PrivateHeaders` | |
206 | ||
207 | c. `KERNELFILES` : To make header file available in kernel level - | |
208 | `$(DSTROOT)/System/Library/Frameworks/Kernel.framework/Headers` | |
209 | `$(DSTROOT)/System/Library/Frameworks/Kernel.framework/PrivateHeaders` | |
210 | ||
211 | d. `PRIVATE_KERNELFILES` : To make header file available to Apple internal | |
212 | for kernel extensions - | |
213 | `$(DSTROOT)/System/Library/Frameworks/Kernel.framework/PrivateHeaders` | |
214 | ||
215 | The Makefile combines the file lists mentioned above into different | |
216 | install lists which are used by build system to install the header files. | |
217 | ||
218 | If the install list that you are interested does not exist, create it | |
219 | by adding the appropriate file lists. The default install lists, its | |
220 | member file lists and their default location are described below - | |
221 | ||
222 | a. `INSTALL_MI_LIST` : Installs header file to a location that is available to everyone in user level. | |
223 | Locations - | |
224 | $(DSTROOT)/usr/include | |
225 | Definition - | |
226 | INSTALL_MI_LIST = ${DATAFILES} | |
227 | ||
228 | b. `INSTALL_MI_LCL_LIST` : Installs header file to a location that is available | |
229 | for Apple internal in user level. | |
230 | Locations - | |
231 | $(DSTROOT)/System/Library/Frameworks/System.framework/PrivateHeaders | |
232 | Definition - | |
233 | INSTALL_MI_LCL_LIST = ${PRIVATE_DATAFILES} | |
234 | ||
235 | c. `INSTALL_KF_MI_LIST` : Installs header file to location that is available | |
236 | to everyone for kernel extensions. | |
237 | Locations - | |
238 | $(DSTROOT)/System/Library/Frameworks/Kernel.framework/Headers | |
239 | Definition - | |
240 | INSTALL_KF_MI_LIST = ${KERNELFILES} | |
241 | ||
242 | d. `INSTALL_KF_MI_LCL_LIST` : Installs header file to location that is | |
243 | available for Apple internal for kernel extensions. | |
244 | Locations - | |
245 | $(DSTROOT)/System/Library/Frameworks/Kernel.framework/PrivateHeaders | |
246 | Definition - | |
247 | INSTALL_KF_MI_LCL_LIST = ${KERNELFILES} ${PRIVATE_KERNELFILES} | |
248 | ||
5ba3f43e A |
249 | e. `EXPORT_MI_LIST` : Exports header file to all of xnu (bsd/, osfmk/, etc.) |
250 | for compilation only. Does not install anything into the SDK. | |
251 | Definition - | |
252 | EXPORT_MI_LIST = ${KERNELFILES} ${PRIVATE_KERNELFILES} | |
253 | ||
39037602 A |
254 | If you want to install the header file in a sub-directory of the paths |
255 | described in (1), specify the directory name using two variables | |
256 | `INSTALL_MI_DIR` and `EXPORT_MI_DIR` as follows - | |
257 | ||
258 | INSTALL_MI_DIR = dirname | |
259 | EXPORT_MI_DIR = dirname | |
260 | ||
261 | A single header file can exist at different locations using the steps | |
262 | mentioned above. However it might not be desirable to make all the code | |
263 | in the header file available at all the locations. For example, you | |
264 | want to export a function only to kernel level but not user level. | |
265 | ||
266 | You can use C language's pre-processor directive (#ifdef, #endif, #ifndef) | |
267 | to control the text generated before a header file is installed. The kernel | |
268 | only includes the code if the conditional macro is TRUE and strips out | |
269 | code for FALSE conditions from the header file. | |
270 | ||
271 | Some pre-defined macros and their descriptions are - | |
272 | ||
273 | a. `PRIVATE` : If true, code is available to all of the xnu kernel and is | |
274 | not available in kernel extensions and user level header files. The | |
275 | header files installed in all the paths described above in (1) will not | |
276 | have code enclosed within this macro. | |
277 | ||
d190cdc3 A |
278 | b. `KERNEL_PRIVATE` : If true, code is available to all of the xnu kernel and Apple |
279 | internal kernel extensions. | |
39037602 A |
280 | |
281 | c. `BSD_KERNEL_PRIVATE` : If true, code is available to the xnu/bsd part of | |
282 | the kernel and is not available to rest of the kernel, kernel extensions | |
283 | and user level header files. The header files installed in all the | |
284 | paths described above in (1) will not have code enclosed within this macro. | |
285 | ||
286 | d. `KERNEL` : If true, code is available only in kernel and kernel | |
287 | extensions and is not available in user level header files. Only the | |
288 | header files installed in following paths will have the code - | |
289 | ||
290 | $(DSTROOT)/System/Library/Frameworks/Kernel.framework/Headers | |
291 | $(DSTROOT)/System/Library/Frameworks/Kernel.framework/PrivateHeaders | |
292 | ||
293 | you should check [Testing the kernel][] for details. | |
294 | ||
295 | ||
296 | How to add a new syscall | |
297 | ======================== | |
298 | ||
299 | ||
300 | ||
301 | ||
302 | Testing the kernel | |
303 | ================== | |
304 | ||
305 | XNU kernel has multiple mechanisms for testing. | |
306 | ||
307 | * Assertions - The DEVELOPMENT and DEBUG kernel configs are compiled with assertions enabled. This allows developers to easily | |
308 | test invariants and conditions. | |
309 | ||
310 | * XNU Power On Self Tests (`XNUPOST`): The XNUPOST config allows for building the kernel with basic set of test functions | |
311 | that are run before first user space process is launched. Since XNU is hybrid between MACH and BSD, we have two locations where | |
312 | tests can be added. | |
313 | ||
314 | xnu/osfmk/tests/ # For testing mach based kernel structures and apis. | |
315 | bsd/tests/ # For testing BSD interfaces. | |
316 | Please follow the documentation at [osfmk/tests/README.md](osfmk/tests/README.md) | |
317 | ||
318 | * User level tests: The `tools/tests/` directory holds all the tests that verify syscalls and other features of the xnu kernel. | |
319 | The make target `xnu_tests` can be used to build all the tests supported. | |
320 | ||
321 | $ make RC_ProjectName=xnu_tests SDKROOT=/path/to/SDK | |
322 | ||
323 | 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. | |
324 | Please read detailed documentation in [tools/tests/unit_tests/README.md](tools/tests/unit_tests/README.md) | |
325 | ||
326 | ||
327 | Kernel data descriptors | |
328 | ======================= | |
329 | ||
330 | XNU uses different data formats for passing data in its api. The most standard way is using syscall arguments. But for complex data | |
331 | it often relies of sending memory saved by C structs. This packaged data transport mechanism is fragile and leads to broken interfaces | |
332 | between user space programs and kernel apis. `libkdd` directory holds user space library that can parse custom data provided by the | |
333 | same version of kernel. The kernel chunked data format is described in detail at [libkdd/README.md](libkdd/README.md). | |
334 | ||
335 | ||
336 | Debugging the kernel | |
337 | ==================== | |
338 | ||
339 | The xnu kernel supports debugging with a remote kernel debugging protocol (kdp). Please refer documentation at [technical note] [TN2063] | |
340 | 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 | |
341 | over ethernet. For machines without ethernet port, this behavior can be altered with use of kernel boot-args. Following are some | |
342 | common options. | |
343 | ||
344 | * `debug=0x144` - setups debug variables to start kdp debugserver on panic | |
345 | * `-v` - print kernel logs on screen. By default XNU only shows grey screen with boot art. | |
346 | * `kdp_match_name=en1` - Override default port selection for kdp. Supported for ethernet, thunderbolt and serial debugging. | |
347 | ||
348 | To debug a panic'ed kernel, use llvm debugger (lldb) along with unstripped symbol rich kernel binary. | |
349 | ||
350 | sh$ lldb kernel.development.unstripped | |
351 | ||
352 | And then you can connect to panic'ed machine with `kdp_remote [ip addr]` or `gdb_remote [hostip : port]` commands. | |
353 | ||
354 | Each kernel is packaged with kernel specific debug scripts as part of the build process. For security reasons these special commands | |
355 | and scripts do not get loaded automatically when lldb is connected to machine. Please add the following setting to your `~/.lldbinit` | |
356 | if you wish to always load these macros. | |
357 | ||
358 | settings set target.load-script-from-symbol-file true | |
359 | ||
360 | The `tools/lldbmacros` directory contains the source for each of these commands. Please follow the [README.md](tools/lldbmacros/README.md) | |
361 | for detailed explanation of commands and their usage. | |
362 | ||
363 | [TN2118]: https://developer.apple.com/library/mac/technotes/tn2004/tn2118.html#//apple_ref/doc/uid/DTS10003352 "Kernel Core Dumps" | |
364 | [TN2063]: https://developer.apple.com/library/mac/technotes/tn2063/_index.html "Understanding and Debugging Kernel Panics" | |
365 | [Kernel Programming Guide]: https://developer.apple.com/library/mac/documentation/Darwin/Conceptual/KernelProgramming/build/build.html#//apple_ref/doc/uid/TP30000905-CH221-BABDGEGF |