< Previous PageNext Page > Hide TOC

Hello Kernel: Creating a Kernel Extension With Xcode

This tutorial describes how to create and test a kernel extension (KEXT) for Mac OS X. In this tutorial, you’ll create a very simple kernel extension that prints text messages when loading and unloading. The tutorial assumes that you are working in a Mac OS X development environment.

Contents:

Anatomy of a KEXT
Roadmap
Create a new Project using Xcode
Build the Kernel Extension
Test the Kernel Extension
Where to Go Next


Anatomy of a KEXT

To better understand what you’re doing, it helps to know what’s inside a kernel extension. In Mac OS X, all kernel extensions are implemented as bundles — folders that the Finder treats as single entities. Kernel extensions have names ending in .kext. In addition, all kernel extensions contain the following:

Roadmap

In this tutorial, you’ll create, build, load, and run a simple kernel extension. Here are the steps you will follow:

  1. “Create a new Project using Xcode”

  2. “Build the Kernel Extension”

  3. “Test the Kernel Extension”

You’ll use the Xcode application to create and build your KEXT. You’ll use the Terminal application to type the commands to load and test your KEXT and view the results.

If you have never used Xcode before, you may also wish to read Xcode Quick Tour for Mac OS X.

Create a new Project using Xcode

A project is a document that contains all your files and targets. Targets are the things you can build from your project’s files. A simple project has just one target that builds an application. A complex project may contain several targets.

The parts of your project can be found later on your disk. These include the source files as well as the targets (your KEXT). Xcode does not store these files in any special format, so you can view or edit the source files with another editing program if you wish. For now, we recommend using Xcode.

Here’s how you’ll create the kernel extension project:

  1. “Create a Kernel Extension Project”

  2. “Implement the Needed Methods”

  3. “Edit the KEXT’s Settings”

The examples below assume that you will be logging in as an administrator of your machine. The account name in the examples is admin. If you use a different login account, be sure to substitute accordingly. Some of the commands you will be using require root privileges so you will be using the sudo command. The sudo command allows permitted users (such as an admin user) to execute a given command with root privileges. If you use a different login account, make sure it has administrative access.

Create a Kernel Extension Project

Kernel extensions are created and edited in Xcode, Apple’s Integrated Development Environment (IDE).

From a Desktop Finder window, locate and launch the Xcode application, found at /Developer/Applications/Xcode. If this is the first time you’ve run Xcode, you’ll see the new user Assistant. The Assistant asks you to make some decisions about your environment. For now, choose the defaults.

When you have finished with the Assistant, choose New Project from the File menu. In the New Project Assistant, scroll down to the Kernel Extension section and choose Generic Kernel Extension. Click Next.

For the Project Name, enter “HelloKernel”. The default location is your home directory; however, if you create many projects, you should make a directory to hold them. Edit the Location to specify a “Projects” subdirectory, for example:

 
/Users/admin/Projects
 

When you click Finish, Xcode creates the new project and displays its project window. The new project contains several files already, including a default source file, HelloKernel.c.

Implement the Needed Methods

If necessary, select HelloKernel in the Groups & Files pane. Double-click the HelloKernel.c in the detail view to display the source code in a separate editor window. Figure 1 shows where you will find the HelloKernel.c file in the project window.

The default source file does nothing but return a successful status; you’ll need to add some additional code. In particular, you will need to implement the initialization and termination code for your KEXT. The default template merely contains suggestions for these routines, as a place for you to begin.


Figure 1  Viewing source code in Xcode


Change the contents of HelloKernel.c to match the code in Listing 1.

Listing 1  HelloKernel.c

 
#include <sys/systm.h>
#include <mach/mach_types.h>
 
kern_return_t HelloKernel_start (kmod_info_t * ki, void * d)
{
 printf("KEXT has loaded!\n");
 return KERN_SUCCESS;
}
 
kern_return_t HelloKernel_stop (kmod_info_t * ki, void * d)
{
 printf("KEXT will be unloaded\n");
 return KERN_SUCCESS;
}
 

Save your changes by choosing File > Save. Close the separate editor window by clicking the red close button in the upper left.

Notice that HelloKernel.c includes two header files, sys/systm.h and mach/mach_types.h. Both header files reside in Kernel.framework. When you develop your own KEXT, be sure only to include header files from Kernel.framework (in addition to any header files you create) because only these files have meaning in the kernel environment. If you include headers from outside Kernel.framework, your KEXT might compile, but the functions and services those headers define will not be available in the kernel.

Edit the KEXT’s Settings

Your kernel extension contains a property list, or plist, that tells the operating system what your KEXT contains and what it needs. If viewed from a text editor, the property list would be in XML (Extended Markup Language) format. However, you will be viewing and editing the plist information from within Xcode.

By default, Xcode allows you to edit your KEXT’s property list as plain XML text in the Xcode editor window. However, it’s easier to view and edit the property list file with the Property List Editor application. You can tell Xcode to open property list files using Property List Editor by following these steps:

  1. Choose Xcode > Preferences and click the File Types icon. The File Types pane lists all the folder and file types that Xcode handles and the preferred editor for each type.

  2. Click the disclosure triangle for file. Then click the disclosure triangle for text.

  3. Select text.xml and click Default (Plain Text File) in the Preferred Editor column.

  4. Choose External Editor and select Other from the menu that appears.

  5. Select Property List Editor in /Developer/Applications/Utilities/Property List Editor and click OK.

  6. Now Xcode lists External Editor (Currently Property List Editor) in the Preferred Editor column for text.xml. Click OK to close the Xcode Preferences window.

Now you can edit your KEXT’s Info.plist file using Property List Editor:

  1. Select HelloKernel in the Groups & Files view. Double-click Info.plist in the Xcode project window. Xcode starts Property List Editor, which displays the Info.plist file. (If Property List Editor displays a second editing window named Untitled, dismiss it by clicking the red close button in the upper left.)

    If this doesn’t work due to a misconfigured project, you can control-click the name of the file and choose “Open with Finder” from the resulting contextual menu. This should have the same effect.

  2. In Property List Editor, click the disclosure triangle next to Root. You should see the elements of the property list file, as shown in Figure 2.

    Figure 2  HelloKernel property list

  3. Change the value of the CFBundleIdentifier property from the default chosen by Xcode.

    Apple has adopted a “reverse-DNS” naming convention to avoid namespace collisions. This is important because all kernel extensions share a single “flat” namespace.

    By default, Xcode names a new KEXT com.yourcompany.kext.<projname>, where <projname> is the name you chose for your project. You should replace the first two parts of this name with your actual reverse-DNS prefix, (for example: com.apple, edu.ucsd, and so forth). For this tutorial, you will use the prefix com.MyTutorial.

    On the line for CFBundleIdentifier, double-click on com.yourcompany.kext.HelloKernel in the Value field. Double-click on yourcompany and change this string to MyTutorial.

  4. The CFBundleVersion property contains the version number of your kernel extension in the ’vers’ resource style (for more information on this, see http://developer.apple.com/documentation/mac/Toolbox/Toolbox-454.html and Technical Note TN1132).

    By default, Xcode assigns new kernel extensions the version number 1.0.0d1. You can change this value if you wish, but your KEXT must declare some version in the ’vers’ resource style to be loaded successfully. To change the version value of your KEXT, click on the line for CFBundleVersion and double-click on 1.0.0d1 in the Value field.

    For this tutorial, leave the CFBundleVersion property with the default value 1.0.0d1.

  5. Mac OS X requires a KEXT that depends on other loadable extensions or on in-kernel components to declare its dependencies in its plist. This information must be contained in the OSBundleLibraries dictionary at the top level of the plist.

    You need to determine which loadable extensions or in-kernel components your KEXT depends on. You should examine the #include directives in your kernel extension’s code and find the corresponding KEXTs in “Kernel Extension Dependencies.” In this tutorial, “HelloKernel” includes sys/systm.h and mach/mach_types.h so you will create an entry for com.apple.kernel.bsd and an entry for com.apple.kernel.mach.

    Click on the line for OSBundleLibraries and click on the disclosure triangle at the beginning of the line. The button previously labeled New Sibling should change to New Child. It not, check to be sure the disclosure triangle next to OSBundleLibraries is pointing down.

    Click the button that now says New Child (as soon as you do, it will change back to New Sibling). A new item will appear below OSBundleLibraries. Change the name from New item to com.apple.kernel.bsd. Double-click on the value field and enter 6.9.9.

    Click the New Sibling button and change the name from New item to com.apple.kernel.mach. Double-click on the value field and enter 6.9.9.

  6. Save your changes by choosing File > Save from the Property List Editor menu. You won’t be making any more changes to your KEXT’s Info.plist file in this tutorial, so you can quit the Property List Editor application and return to Xcode by choosing Property List Editor > Quit Property List Editor.

Xcode also allows you to modify or create build settings for your KEXT. These settings define information that will be compiled into the kernel extension’s executable.

  1. On the left, in the Groups & Files view, click the disclosure triangle next to Targets and select HelloKernel (you don’t have to click the disclosure triangle next to HelloKernel).

  2. Click the Get Info button in the tool bar (it’s the round blue button with an “i” in the middle).

  3. Select the Build view and scroll down to the bottom of the Customized Settings list. Change the name of the module from the default chosen by Xcode (the value of the MODULE_NAME setting).

    Click on the line for MODULE_NAME and double-click on com.yourcompany.kext.HelloKernel in the Value field. Double-click on yourcompany and change this string to MyTutorial. Be sure that the MODULE_NAME value matches the value of the CFBundleIdentifier you entered in your kernel extension’s Info.plist file or your KEXT will not run.

  4. The MODULE_START and MODULE_STOP variables contain the names of your KEXT’s initialization and termination routines. Be sure that these variables have the values used in your HelloKernel.c file. That is, for this tutorial, be sure these variables have the values HelloKernel_start and HelloKernel_stop, respectively. If you changed the names of the initialization and termination routines when entering the code in the previous section, make sure that the values for these variables match the names you used! Otherwise, your KEXT will not run.

  5. The value of the MODULE_VERSION variable is in the ’vers’ resource style and must be numerically identical to the CFBundleVersion value in the kernel extension’s Info.plist file or your KEXT may not load. For this tutorial, make sure the MODULE_VERSION variable has the value 1.0.0d1.

Build the Kernel Extension

Here’s how you’ll build the kernel extension:

  1. “Build the Project”

  2. “Fix Any Errors”

  3. “If There Were No Errors”

  4. “Build the Project Again”

Build the Project

Click the Build button in the upper left corner of the editor window or select Build from the Build menu. The Build button looks like a hammer and is illustrated in Figure 3.


Figure 3  The build button looks like a hammer


If Xcode asks you whether to save some modified files, select all the files and click “Save All”. Figure 4 shows the Save dialog.


Figure 4  Save before building


Xcode starts building your project. It stops if it reaches an error in the code.

Fix Any Errors

If you made any errors typing in the code, Xcode will stop and show you the errors in both the editor window (if you haven’t closed it) and the main project window. In the project window, click the disclosure triangle next to Errors and Warnings in the Groups & Files view to reveal the files that contain errors. If you select a file listed under Errors and Warnings, Xcode lists the errors in that file, each accompanied by a short description of the problem. Double-click the file name to open an editor window and edit the source code. The source code with the error will appear in the editing window, as shown in Figure 5.


Figure 5  Xcode shows code errors


You can edit the source code inside the editing window. Correct the error, save your changes, and build the project again.

If There Were No Errors

If you didn’t have any errors, you can insert one so that you can try out the error-handling facility. Try removing the semicolon at the end of one of the lines of code, as shown in Listing 2.

Listing 2  HelloKernel.c with error

 
#include <sys/systm.h>
#include <mach/mach_types.h>
 
kern_return_t HelloKernel_start (kmod_info_t * ki, void * d)
{
 printf("KEXT has loaded!\n") // <--ERROR! Missing semicolon!
 return KERN_SUCCESS;
}
 
kern_return_t HelloKernel_stop (kmod_info_t * ki, void * d)
{
 printf("KEXT will be unloaded\n");
 return KERN_SUCCESS;
}
 

Build the Project Again

Click the Build button. If Xcode asks you whether to save some modified files, select all the files and click “Save All”.

Xcode starts building your project again. If there is an error, fix the error as described above in “Fix Any Errors.” Otherwise, if the build succeeds, you can move on to loading the extension.

Test the Kernel Extension

This section shows how to test the kernel extension. You’ll load your KEXT with the kextload command, you’ll use the kextstat command to see that it’s loaded, and finally, you’ll unload your KEXT from the kernel with the kextunload command.

You’ll use the Terminal application to type the commands to load and unload your KEXT. You’ll view the results as they are written to the system log file, /var/log/system.log.

Note: This tutorial uses the “%” prompt when it shows the commands you type in the Terminal application. This is the default prompt of the tcsh shell. If you’re using a different shell, you may see a different prompt. For example, the prompt in the bash shell, which is the default shell in Mac OS X version 10.3, is “$”.

Here’s how you’ll test your KEXT:

  1. “Getting Root Privileges”

  2. “Start the Terminal Application”

  3. “Load the KEXT Binary”

Getting Root Privileges

To use the kextload and kextunload commands you must have root or super user privileges. Instead of logging in as root, for this tutorial you will use the sudo command which gives permitted users the ability to execute a given command as root.

By default, Mac OS X allows admin and root users to use the sudo command, so make sure you are currently logged in to an admin account before using sudo. An admin user is a user who has “Allow user to administer this computer” checked in the Security view of the Accounts system preference.

Start the Terminal Application

  1. Start the Terminal application. From a Desktop Finder window, locate and launch the Terminal application, found at /Applications/Utilities/Terminal.

  2. To view the system log file, enter the following command at the Terminal prompt:

    % tail -f /var/log/system.log
  3. Open a second window in the Terminal application. Choose File > New Shell from the Terminal menu. Position this window so that you can view both windows easily. You will load your KEXT from the second window.

  4. In the second Terminal window, move to the directory that contains your KEXT. Xcode stores your KEXT in the Debug folder of the build directory of your project location (unless you’ve set a different location for build products using Xcode’s Preferences dialog).

    Use the cd command to move to the appropriate directory. For example:

     
    % cd Projects/HelloKernel/build/Debug
     

    This directory contains your KEXT. You can use the ls command to view the contents of this directory. For example:

    % ls
    HelloKernel.kext

    Your KEXT should have the name HelloKernel.kext. Note that this name is formed from the project name and a suffix, .kext.

    Important:  For purposes of packaging, distribution, and installation, the filename of the KEXT (apart from the suffix) does not matter. However, the name of the KEXT binary (stored in the KEXT’s property list) should be unique, using the recommended “reverse-DNS” naming convention.

    From a Desktop Finder window, a KEXT appears as a single file (look for it from the Desktop if you like). From the Terminal application, however, a KEXT appears as a directory. The KEXT directory contains the contents of your KEXT, including the plist (Contents/Info.plist) and the KEXT binary (Contents/MacOS/HelloKernel).

  5. View the contents of the KEXT directory. Use the find command.

    For example:

    % find HelloKernel.kext
    HelloKernel.kext
    HelloKernel.kext/Contents
    HelloKernel.kext/Contents/Info.plist
    HelloKernel.kext/Contents/MacOS
    HelloKernel.kext/Contents/MacOS/HelloKernel
    HelloKernel.kext/Contents/Resources
    HelloKernel.kext/Contents/Resources/English.lproj
    HelloKernel.kext/Contents/Resources/English.lproj/InfoPlist.strings
     

You are now ready to load and run (and then unload) your KEXT.

Load the KEXT Binary

Because kernel extensions contain code and data that are loaded into the kernel, the most protected environment in the operating system, their file ownership and permissions must be set to prevent unauthorized tampering. All KEXT bundles (all files and folders in the KEXT, including the KEXT binary) must be owned by the user root and the group wheel. In addition, the folders and files of the KEXT bundle must have their permissions set so that they are not writable by any user other than the super user.

For development purposes, however, you can make a root-owned copy of your KEXT binary to load and test. You should not change the ownership and permissions of any of your KEXT files in your own directory, because you will no longer be able to save them after working on them. For this tutorial, you will use the sudo command to copy the KEXT binary (HelloKernel.kext) to the /tmp directory and load and unload the KEXT from there. Using sudo to copy the KEXT binary gives the KEXT the super user’s ownership and permissions and leaves the original KEXT alone so you can revise and save it as you choose.

Note: Every time you make changes to your KEXT and rebuild it, you need to repeat the following steps to copy the new version to the /tmp directory to load and test it.

  1. At the prompt, you’ll use the cp -R command with the sudo command to copy your KEXT to /tmp. The cp command copies files from one place to another and the -R option tells cp to copy a directory and its entire subtree (like HelloKernel.kext). When prompted for a password, enter your admin password. (Note that nothing is displayed as you type the password.)

    !

    Warning:  If you use tab-completion to avoid typing all of HelloKernel.kext, you’ll get a “/” after the KEXT name. Be sure to delete this slash before you press Return. If you don’t, the cp command will copy only the contents of the HelloKernel.kext directory to /tmp, instead of copying the directory and its entire subtree.

    Type the following to copy your KEXT to /tmp:

     
    % sudo cp -R HelloKernel.kext /tmp
    Password:
     

    Check the ownership and permissions of your KEXT by moving to the /tmp directory and using the ls -l command:

     
        % cd /tmp
        % ls -l
        drwxr-xr-x 3 root wheel 102 Jun 19 10:30 HelloKernel.kext
     

    The -l makes the ls command display extra information about the files in a directory.

  2. From the /tmp directory, use the kextload command with the sudo command; this loads your KEXT and runs its initialization (start) function. Note that you may not have to re-enter your password this time. This is because you’re allowed to continue to use sudo for a short period (usually about 5 minutes) without reauthenticating.

    For example:

     
    % sudo kextload -v HelloKernel.kext
    kextload: extension HelloKernel.kext appears to be valid
    kextload: loading extension HelloKernel.kext
    kextload: sending 1 personality to the kernel
    kextload: HelloKernel.kext loaded successfully
     

    The -v is optional; it makes kextload provide more verbose information.

  3. In the other Terminal window, view the system log. In a few moments, this line will appear:

     
    localhost kernel: KEXT has loaded!
  4. Use the kextstat command to check the status of the KEXT. This command displays the status of all dynamically-loaded KEXTs. Enter the command:

     
    % kextstat
     

    You’ll see several lines of output, including a line for your KEXT at the end.

     
    Id Refs Address Size Wired Name (Version) <Linked Against>
     1 0 0x4b94000 0x17000 0x16000 ATIR128 (0.1)
     2 2 0x4bbb000 0x10000 0xf000 com.apple.IOAudioFamily (0.1a)
     3 1 0x4bcb000 0x1e000 0x1d000 com.apple.IOFireWireFamily (0.1a)
    ...
    10 0 0x4d18000 0x7000 0x6000 SIP-NKE (0.1a)
    11 0 0x5047000 0x3000 0x2000 com.MyTutorial.kext.HelloKernel...
  5. Unload the KEXT binary. Use the kextunload command with the sudo command. This command unloads your KEXT and runs its termination (stop) function.

    For example, from the /tmp directory:

    % sudo kextunload HelloKernel.kext
    kextunload: unload kext HelloKernel.kext succeeded

    Note that you may have to enter your admin password this time if it’s been more than a few minutes since the last time you entered your password.

  6. View the system log. In a few moments, several lines will appear, including:

    localhost kernel: KEXT will be unloaded
  7. Stop the system log display. The tail -f command you used to view the system log will continue to run until you stop it.

    In the Terminal window displaying the system log, press the control key and the c key at the same time.

Using Console Mode

As an alternative to the Terminal application, you can load and test your KEXT from console mode. In console mode, all system messages (such as this kernel extension’s message “KEXT has loaded!”) are written directly to your monitor screen. Messages appear much more quickly than when they are written to the system log file.

However, you should keep in mind that console mode is not as flexible as the Terminal application. There are no windows, you cannot view your code in Xcode or run other applications at the same time, and you cannot use copy or paste.

To use console mode, follow these steps:

  1. Log out of your account.

    From the Desktop, choose Log Out from the Finder menu.

  2. From the login screen, log in to console mode.

    Type >console as the user name, leave the password blank, and press Return. Be sure to include the > character at the beginning of the name. The screen turns black and looks like an old ASCII “glass terminal”. This is console mode.

  3. At the prompt, log in to your admin account.

  4. Move to the directory that contains your KEXT binary. Use the cd command.

    For example:

     
    cd /Users/admin/Projects/HelloKernel/build
     
  5. Follow the instructions given in “Load the KEXT Binary.” Remember that the console messages will come directly to your screen; you do not need to view the system log file.

  6. When you have finished, log out of console mode by entering the command logout.

Where to Go Next

Congratulations! You’ve now written, built, loaded, and unloaded your own kernel extension. In the next tutorial in this series, “Hello I/O Kit: Creating a Device Driver With Xcode,” you’ll learn how to create a device driver, a special kind of KEXT that allows the kernel to interact with devices.

If you’re interested, you can use the man command to read the manual pages for kextload, kextstat, and kextunload. For example, from a Terminal window, enter the command

man kextstat

More information about the ‘vers’ resource can be found in the “Finder Interface” chapter of Inside Macintosh—Files, or online at http://developer.apple.com/documentation/mac/Toolbox/Toolbox-454.html.

Additional useful reference material can be found in Core Foundation Documentation. Look here for documentation about Bundles, Property Lists, Collections (such as Dictionaries) and more.

As you become more experienced in KEXT development, you should also read the articles in this document that cover more advanced topics, such as how to declare dependencies so that your KEXT targets the appropriate version of Mac OS X. The following articles provide more information on KEXT-related topics:



< Previous PageNext Page > Hide TOC


© 2003, 2007 Apple Inc. All Rights Reserved. (Last updated: 2007-10-31)


Did this document help you?
Yes: Tell us what works for you.
It’s good, but: Report typos, inaccuracies, and so forth.
It wasn’t helpful: Tell us what would have helped.