This question has a lot of assumptions in it.
Here are some reasons.
The kernel interface is not stable so a module for one version may not compile for a different version.
The kernel may not expose a required facility.
The kernel may expose a required facility but not in a way that is acceptable, for example requiring the module to have a particular license.
The people writing the code found it quicker to write the code this way.
As to your options if you need a newer kernel.
- find someone else who has already ported the code
- port it yourself
- pay someone else to port it (may not need money, beer, flattery and curiosity may work).
So if I want my rootfs to be in RAM, I need to set CONFIG_INITRAMFS_SOURCE to point to my rootfs (in cpio format presumably).
That's one way to do it, yes, but it is not the only way.
If you have a bootloader that can be configured to load the kernel and the initramfs as separate files, you don't need to use CONFIG_INITRAMFS_SOURCE
while building the kernel. It is enough to have CONFIG_BLK_DEV_INITRD
set in kernel configuration. (Before initramfs there was an older version of the technique named initrd
, and the old name still appears at some places.) The bootloader will load the initramfs file, and then fill in some information about its memory location and size into a data structure in a specific location of the already-loaded kernel image. The kernel has built-in routines that will use that information to find the initramfs in the system RAM and uncompress it.
Having the initramfs as a separate file will allow you to modify the initramfs file more easily, and if your bootloader can accept input from the user, perhaps specify another initramfs file to be loaded instead of the regular one at boot time. (That's very handy if you try and create a customized initramfs and get some things wrong. Been there, done that.)
For a traditional BIOS-based x86 system, you'll find information about these details in (kernel source)/Documentation/x86/boot.txt. UEFI-based systems do it a bit differently (also described in the same file), and other architectures like ARM have their own sets of details about passing information from the bootloader to the kernel.
Furthermore, what if I want my rootfs to be on physical storage (like eMMC, flash drive, etc.) and not in RAM?
In regular non-embedded systems, the initramfs will usually only contain enough functionality to activate the essential sub-systems. In a regular PC, those would usually be the drivers for the keyboard, display and the driver for the storage controller for your root filesystem, plus any kernel modules and tools required to activate subsystems like LVM, disk encryption, and/or software RAID, if you use those features.
Once the essential sub-systems are active and the root filesystem is accessible, the initramfs will typically do a pivot_root(8)
operation to switch from initramfs to the real root filesystem. But an embedded system, or a specialized utility like DBAN, could package everything it needs into the initramfs and just never do the pivot_root
operation.
Usually, the scripts and/or tools within the initramfs will get the necessary information to locate the real root filesystem from the options on the kernel command line. But you don't have to do that: with a customized initramfs, you could do something like switching to a different root filesystem if a specific key or mouse button is held down at a specific time in the boot sequence.
With a complex storage configuration (e.g. encrypted LVM on top of a software RAID, on a system that uses redundant multipathed SAN storage), all the information needed to activate the root filesystem might not fit onto the kernel command line, so you could include the bigger pieces into initramfs.
Modern distributions usually use an initramfs generator to build a tailored initramfs for each installed kernel. Different distributions used to have their own initramfs generators: RedHat used mkinitrd
while Debian had update-initramfs
. But after the introduction of systemd
it looks like many distributions are standardizing on dracut
as an initramfs generator.
A modern initramfs file can be a concatenation of multiple .cpio
archives, and each part may or may not be compressed. A typical initramfs file on a modern x86_64 system might have an "early microcode update" file as a first component (usually just a single file in an uncompressed cpio archive, as the microcode file is typically encrypted and so not very compressible. After that comes the regular initramfs content, as a compressed .cpio
file.
To gain a deeper understanding of your system, I would encourage you to extract an initramfs file to a temporary directory and then examine its contents. On Debian, there is an unmkinitramfs(8)
tool that can be used to extract an initramfs file in a straightforward manner. On RedHat 7, you might need to use /usr/lib/dracut/skipcpio <initramfs file>
to skip the microcode update file, and then pipe the resulting output to gzcat
and onward to cpio -i -d
to extract the initramfs contents to the current working directory. Ubuntu might use lzcat
in place of gzcat
.
Best Answer
It's pretty straight forward, although we should distinguish between "driver" and "module". A driver may or may not be a module. If it is not, then it is built into the kernel loaded by the bootloader.
If it is a module, then it is in a filesystem hierarchy rooted at
/lib/modules/[kernel-release]
.1 Note that it is possible to boot a kernel together with a small preliminary root filesystem (an "initramfs") which may contain such a repository as well. This is normal with generic kernels so they can decide what modular drivers they need to load in order to access the real filesystem, since if they can't do that, they can't access any modules there.Yes.
Where else should they be stored before they are loaded? The kernel doesn't contain the rootfs within itself (except WRT some forms of initramfs), it's just the gatekeeper.
No. If you compile a driver in, the kernel will not bother to check
/lib/modules
for it. I'm not sure what happens if you then ask it explicitly to load such a driver anyway, presumably it will just say no.1. As Celada hints at with
$(uname -r)
, this release string is not necessarily just the version number. You can have multiple kernels with the same version and different release strings therefore separate module stores. Likewise, you can have multiple kernels with the same release string, therefore the same module store.