Re: Understanding kexts in the early boot process
Re: Understanding kexts in the early boot process
- Subject: Re: Understanding kexts in the early boot process
- From: David Elliott <email@hidden>
- Date: Tue, 16 Jun 2009 08:25:47 -0400
On Jun 14, 2009, at 5:51 PM, Shantonu Sen wrote:
On Jun 14, 2009, at 2:38 PM, Thomas Tempelmann wrote:
What I haven't seen yet is the part that links the kexts (apparently
loaded by the boot loader) to the kernel. Does the boot_args struct
have a new parameter (not doc'd in Amit's book) which passes a
pointer
to a list of loaded kexts to the kernel, or how does this work?
<http://opensource.apple.com/source/xnu/xnu-1228.12.14/libsa/catalogue.cpp
>
This is definitely the file to start with.
Background is this: It appears that a 3rd party boot loader is able
to
load two sets of kexts from different locations and get them used by
the kernel. I try to understand how that works, because so far all I
learned was that there's only one single group of kexts that the
kernel sees, not several.
You'd probably have to ask the maintainer of that boot loader.
Well, I'm not sure what bootloader exactly he's referring to, but I
can be reasonably sure that it's a derivative of mine which is in turn
a derivative of the traditional Darwin x86 "boot".[1]
You can find info (outdated, sorry) on it here:
http://tgwbd.org/darwin/boot.html
The public SVN tree is also available (can be used with SVN client or
the latest revision can be browsed online):
http://tgwbd.org/svn/Darwin/boot/branches/public/
Another interesting resource is the BootX bootloader used on PowerPC
Macs. As the Apple guys mentioned, the kext or mkext are loaded from
disk (or network, but not working in "boot") by the bootloader be it
BootX, boot, or boot.efi. The pointers to the in memory blobs are
then passed into the kernel through entries in the device tree. These
entries are the same regardless of platform.
At any rate, the answer to the question is that the kernel doesn't
really see it specifically as "two sets" of kernel extensions. If you
look at libsa/catalogue.cpp you will find that it enumerates "/chosen/
memory-map" in gIODTPlane (the device tree plane is a plane that
starts out initialized by the bootloader).
A good place to start is the recordStartupExtensions function. For
every child node whose name begins with "Driver-" it treats it as a
kext bundle whose contents were read into memory by the bootloader and
records it. For every child node whose name begins with
"DriversPackage-" it treats it as an mkext bundle.
This happens in a loop until all Driver-* and DriversPackage-* entries
have been enumerated. So although normally the bootloader with either
pass in one DriversPackage-* entry (i.e. Extensions.mkext was
determined to be up to date) or multiple Driver-* entries (i.e.
Extensions.mkext does not exist or was determined to be out of date)
there is no specific requirement kernel-side that this be the case.
You can mix and match all you want.
Now, for a little bit of background.
In order to get OS X guest support working with Fusion we needed a way
to add some extensions beyond those provided by Apple. Modifying the
DVD was not even considered. The final product would have to be able
to boot a retail boxed DVD. No tricks of any kind like modifying the
filesystem behind the user's back.
As I recall (and it's been a while now), one idea we almost settled on
was to unpack the Extensions.mkext within the bootloader and pass the
individual drivers to the kernel, removing some we didn't want, adding
extras we did want, and modifying plists for some to make them drive
more hardware[2]. I worked on this very early and at the time Fusion
didn't even have a USB keyboard so if you wanted to type anything you
needed PS/2 support in the guest.
So as I began to research how I would implement this I took a look at
the way the booter was passing the extensions in, both when it passed
in a single mkext and also when it passed in individual drivers. I
quickly released that essentially it was just forming a list of the in-
memory blobs and passing pointers to the blobs to the kernel through
the IODeviceTree.
This led me to the libsa/catalogue.cpp file which revealed to me that
the kernel is perfectly happy with any combination of kext (Driver-*)
and mkext (DriversPackage-*). I realized I could pass in
Extensions.mkext from the root device and still add in extra kexts or
even a second mkext. All I needed to do was simply add the additional
entries to the device tree. Of course using this method I could only
add extra extensions. Modifying existing extensions would not be
possible nor would removing them be possible. But removing them isn't
really possible anyway if they are present on the root device because
eventually kextd will run and will load them.
I would say I probably spent more time discovering this useful tidbit
of information than I actually spent implementing it. Once I knew how
the kernel interpreted the information the implementation was really
rather trivial.
Hopefully that provides a little bit of background on how the
extension loading process works and how extra extensions came to be.
One thing to be aware of is that the bootloader does NOT do hardware
detection to determine which extensions to load. As the Apple guys
have mentioned, it uses OSBundleRequired.[3] This is buried in the
source somewhere. The "Extra" extensions are loaded exactly the same
way that the main ones are. So if .../Extra/Extensions.mkext is
determined to be valid it loads. Otherwise .../Extra/Extensions is
enumerated for kexts with an appropriate OSBundleRequired. That is in
fact why it's Extra/Extensions and not ExtraExtensions or
Extra_Extensions. It allowed me to use the same well-exercised code
path.
Personally I felt it was quite a hack to be able to load extra
extensions beyond those present on the root device. But perhaps I
need to choose my language more carefully and explain that that means
I thought it was clever, lest I find myself in a room with an ignorant
lawyer working for Apple asking me stupid questions again.
Shakespeare was right.
-Dave
Footnotes:
1. Apple's boot in turn contains a fair amount of code very clearly
derived from BSD and Mach. A fair amount of the support code hasn't
changed in decades.
2. Somewhere around the time I figured out how to add extra kernel
extensions I also figured out that the CFBundleIdentifier property of
a personality can perfectly well refer to some other extension. So it
became possible to add support for VMware's PIIX4 by putting the
personality dictionary's from the Darwin release of AppleIntelPIIXATA
into a new kext's Info.plist (one with a different top-level
CFBundleIdentifier). By leaving the CFBundleIdentifier of the
personalities themselves set to com.apple.driver.AppleIntelPIIXATA the
kernel will load AppleIntelPIIXATA when one of these personalities
matches. Assuming AppleIntelPIIXATA's probe method doesn't check for
this case and fail probe. And assuming that it is capable of driving
the hardware. This allowed me to add support for the PIIX4 by adding
a new kext (with no real binary code) with the personalities rather
than modifying the plist of the existing extension to add the
personalities.
3. It's not particularly interesting except from an archeological
standpoint, but there are remnants of code in the booter from an
earlier time when it did apparently do some hardware detection to
determine which extensions to load. It looks like this may have died
with DriverKit which is the Objective-C precursor to the C++ IOKit.
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Darwin-kernel mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden