]>
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`. | |
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. | |
d9a64523 A |
193 | If you are adding the first header file in a directory, you will need to |
194 | create Makefile similar to `xnu/bsd/sys/Makefile`. | |
39037602 A |
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 | |
d9a64523 A |
216 | install lists which are used by build system to install the header files. There |
217 | are two types of install lists: machine-dependent and machine-independent. | |
218 | These lists are indicated by the presence of `MD` and `MI` in the build | |
219 | setting, respectively. If your header is architecture-specific, then you should | |
220 | use a machine-dependent install list (e.g. `INSTALL_MD_LIST`). If your header | |
221 | should be installed for all architectures, then you should use a | |
222 | machine-independent install list (e.g. `INSTALL_MI_LIST`). | |
39037602 A |
223 | |
224 | If the install list that you are interested does not exist, create it | |
225 | by adding the appropriate file lists. The default install lists, its | |
226 | member file lists and their default location are described below - | |
227 | ||
228 | a. `INSTALL_MI_LIST` : Installs header file to a location that is available to everyone in user level. | |
229 | Locations - | |
230 | $(DSTROOT)/usr/include | |
231 | Definition - | |
232 | INSTALL_MI_LIST = ${DATAFILES} | |
233 | ||
234 | b. `INSTALL_MI_LCL_LIST` : Installs header file to a location that is available | |
235 | for Apple internal in user level. | |
236 | Locations - | |
237 | $(DSTROOT)/System/Library/Frameworks/System.framework/PrivateHeaders | |
238 | Definition - | |
239 | INSTALL_MI_LCL_LIST = ${PRIVATE_DATAFILES} | |
240 | ||
241 | c. `INSTALL_KF_MI_LIST` : Installs header file to location that is available | |
242 | to everyone for kernel extensions. | |
243 | Locations - | |
244 | $(DSTROOT)/System/Library/Frameworks/Kernel.framework/Headers | |
245 | Definition - | |
246 | INSTALL_KF_MI_LIST = ${KERNELFILES} | |
247 | ||
248 | d. `INSTALL_KF_MI_LCL_LIST` : Installs header file to location that is | |
249 | available for Apple internal for kernel extensions. | |
250 | Locations - | |
251 | $(DSTROOT)/System/Library/Frameworks/Kernel.framework/PrivateHeaders | |
252 | Definition - | |
253 | INSTALL_KF_MI_LCL_LIST = ${KERNELFILES} ${PRIVATE_KERNELFILES} | |
254 | ||
5ba3f43e A |
255 | e. `EXPORT_MI_LIST` : Exports header file to all of xnu (bsd/, osfmk/, etc.) |
256 | for compilation only. Does not install anything into the SDK. | |
257 | Definition - | |
258 | EXPORT_MI_LIST = ${KERNELFILES} ${PRIVATE_KERNELFILES} | |
259 | ||
39037602 A |
260 | If you want to install the header file in a sub-directory of the paths |
261 | described in (1), specify the directory name using two variables | |
262 | `INSTALL_MI_DIR` and `EXPORT_MI_DIR` as follows - | |
263 | ||
264 | INSTALL_MI_DIR = dirname | |
265 | EXPORT_MI_DIR = dirname | |
266 | ||
267 | A single header file can exist at different locations using the steps | |
268 | mentioned above. However it might not be desirable to make all the code | |
269 | in the header file available at all the locations. For example, you | |
270 | want to export a function only to kernel level but not user level. | |
271 | ||
272 | You can use C language's pre-processor directive (#ifdef, #endif, #ifndef) | |
273 | to control the text generated before a header file is installed. The kernel | |
274 | only includes the code if the conditional macro is TRUE and strips out | |
275 | code for FALSE conditions from the header file. | |
276 | ||
277 | Some pre-defined macros and their descriptions are - | |
278 | ||
d9a64523 A |
279 | a. `PRIVATE` : If defined, enclosed definitions are considered System |
280 | Private Interfaces. These are visible within xnu and | |
281 | exposed in user/kernel headers installed within the AppleInternal | |
282 | "PrivateHeaders" sections of the System and Kernel frameworks. | |
283 | b. `KERNEL_PRIVATE` : If defined, enclosed code is available to all of xnu | |
284 | kernel and Apple internal kernel extensions and omitted from user | |
285 | headers. | |
286 | c. `BSD_KERNEL_PRIVATE` : If defined, enclosed code is visible exclusively | |
287 | within the xnu/bsd module. | |
288 | d. `MACH_KERNEL_PRIVATE`: If defined, enclosed code is visible exclusively | |
289 | within the xnu/osfmk module. | |
290 | e. `XNU_KERNEL_PRIVATE`: If defined, enclosed code is visible exclusively | |
291 | within xnu. | |
292 | f. `KERNEL` : If defined, enclosed code is available within xnu and kernel | |
293 | extensions and is not visible in user level header files. Only the | |
39037602 A |
294 | header files installed in following paths will have the code - |
295 | ||
296 | $(DSTROOT)/System/Library/Frameworks/Kernel.framework/Headers | |
297 | $(DSTROOT)/System/Library/Frameworks/Kernel.framework/PrivateHeaders | |
298 | ||
d9a64523 A |
299 | Conditional compilation |
300 | ======================= | |
301 | ||
302 | `xnu` offers the following mechanisms for conditionally compiling code: | |
303 | ||
304 | a. *CPU Characteristics* If the code you are guarding has specific | |
305 | characterstics that will vary only based on the CPU architecture being | |
306 | targeted, use this option. Prefer checking for features of the | |
307 | architecture (e.g. `__LP64__`, `__LITTLE_ENDIAN__`, etc.). | |
308 | b. *New Features* If the code you are guarding, when taken together, | |
309 | implements a feature, you should define a new feature in `config/MASTER` | |
310 | and use the resulting `CONFIG` preprocessor token (e.g. for a feature | |
311 | named `config_virtual_memory`, check for `#if CONFIG_VIRTUAL_MEMORY`). | |
312 | This practice ensures that existing features may be brought to other | |
313 | platforms by simply changing a feature switch. | |
314 | c. *Existing Features* You can use existing features if your code is | |
315 | strongly tied to them (e.g. use `SECURE_KERNEL` if your code implements | |
316 | new functionality that is exclusively relevant to the trusted kernel and | |
317 | updates the definition/understanding of what being a trusted kernel means). | |
318 | ||
319 | It is recommended that you avoid compiling based on the target platform. `xnu` | |
320 | does not define the platform macros from `TargetConditionals.h` | |
321 | (`TARGET_OS_OSX`, `TARGET_OS_IOS`, etc.). | |
322 | ||
323 | ||
324 | There is a `TARGET_OS_EMBEDDED` macro, but this should be avoided as it is in | |
325 | general too broad a definition for most functionality. | |
39037602 A |
326 | |
327 | How to add a new syscall | |
328 | ======================== | |
329 | ||
330 | ||
331 | ||
332 | ||
333 | Testing the kernel | |
334 | ================== | |
335 | ||
336 | XNU kernel has multiple mechanisms for testing. | |
337 | ||
338 | * Assertions - The DEVELOPMENT and DEBUG kernel configs are compiled with assertions enabled. This allows developers to easily | |
339 | test invariants and conditions. | |
340 | ||
341 | * XNU Power On Self Tests (`XNUPOST`): The XNUPOST config allows for building the kernel with basic set of test functions | |
342 | that are run before first user space process is launched. Since XNU is hybrid between MACH and BSD, we have two locations where | |
343 | tests can be added. | |
344 | ||
345 | xnu/osfmk/tests/ # For testing mach based kernel structures and apis. | |
346 | bsd/tests/ # For testing BSD interfaces. | |
347 | Please follow the documentation at [osfmk/tests/README.md](osfmk/tests/README.md) | |
348 | ||
349 | * User level tests: The `tools/tests/` directory holds all the tests that verify syscalls and other features of the xnu kernel. | |
350 | The make target `xnu_tests` can be used to build all the tests supported. | |
351 | ||
352 | $ make RC_ProjectName=xnu_tests SDKROOT=/path/to/SDK | |
353 | ||
354 | 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. | |
355 | Please read detailed documentation in [tools/tests/unit_tests/README.md](tools/tests/unit_tests/README.md) | |
356 | ||
357 | ||
358 | Kernel data descriptors | |
359 | ======================= | |
360 | ||
361 | XNU uses different data formats for passing data in its api. The most standard way is using syscall arguments. But for complex data | |
362 | it often relies of sending memory saved by C structs. This packaged data transport mechanism is fragile and leads to broken interfaces | |
363 | between user space programs and kernel apis. `libkdd` directory holds user space library that can parse custom data provided by the | |
364 | same version of kernel. The kernel chunked data format is described in detail at [libkdd/README.md](libkdd/README.md). | |
365 | ||
366 | ||
367 | Debugging the kernel | |
368 | ==================== | |
369 | ||
370 | The xnu kernel supports debugging with a remote kernel debugging protocol (kdp). Please refer documentation at [technical note] [TN2063] | |
371 | 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 | |
372 | over ethernet. For machines without ethernet port, this behavior can be altered with use of kernel boot-args. Following are some | |
373 | common options. | |
374 | ||
375 | * `debug=0x144` - setups debug variables to start kdp debugserver on panic | |
376 | * `-v` - print kernel logs on screen. By default XNU only shows grey screen with boot art. | |
377 | * `kdp_match_name=en1` - Override default port selection for kdp. Supported for ethernet, thunderbolt and serial debugging. | |
378 | ||
379 | To debug a panic'ed kernel, use llvm debugger (lldb) along with unstripped symbol rich kernel binary. | |
380 | ||
381 | sh$ lldb kernel.development.unstripped | |
382 | ||
383 | And then you can connect to panic'ed machine with `kdp_remote [ip addr]` or `gdb_remote [hostip : port]` commands. | |
384 | ||
385 | Each kernel is packaged with kernel specific debug scripts as part of the build process. For security reasons these special commands | |
386 | and scripts do not get loaded automatically when lldb is connected to machine. Please add the following setting to your `~/.lldbinit` | |
387 | if you wish to always load these macros. | |
388 | ||
389 | settings set target.load-script-from-symbol-file true | |
390 | ||
391 | The `tools/lldbmacros` directory contains the source for each of these commands. Please follow the [README.md](tools/lldbmacros/README.md) | |
392 | for detailed explanation of commands and their usage. | |
393 | ||
394 | [TN2118]: https://developer.apple.com/library/mac/technotes/tn2004/tn2118.html#//apple_ref/doc/uid/DTS10003352 "Kernel Core Dumps" | |
395 | [TN2063]: https://developer.apple.com/library/mac/technotes/tn2063/_index.html "Understanding and Debugging Kernel Panics" | |
396 | [Kernel Programming Guide]: https://developer.apple.com/library/mac/documentation/Darwin/Conceptual/KernelProgramming/build/build.html#//apple_ref/doc/uid/TP30000905-CH221-BABDGEGF |