Some background might help…
The kernel basically is what talks to the “bare metal”. It talks directly to hardware, e.g., to the disk controller. Without that there can be no software to “abstract” other drivers. In this case “SATA” is the abstraction, and another set of software (linked to this) talks directly to the disk controller. The software for either the disk controller or the SATA abstraction (abstraction meaning it provides some “standardized” interface where anything knowing that abstraction can also talk to the same hardware) can be put into the kernel in either of two ways. That’s what the solution is about…those two different ways of putting the software in.
The Linux kernel has most of its functionality in a single file, and on the Jetson, that’s usually “
/boot/Image”. Anything in that file could be considered “integrated” directly into the kernel. However, sometimes it is nice to be able to load other drivers or parts at a later time since not everyone uses those features or drivers.
For example, everyone needs certain types of memory and memory management. This is always integrated. Other people might need a driver for some obscure satellite radio. Why clutter up the system with that obscure driver by default? It is better if something like that can be “loaded dynamically” (indeed, it is a “loadable module”…a separate file which is only installed at a later time when the kernel is already up and running). Currently you have a loadable module for the ATA driver.
During boot the boot software eventually gets to a point where it puts the integrated kernel into memory. Anything that kernel can do (any feature or driver present in the kernel) is now functional. However, modules are not yet functional because they have not been loaded (including the ATA driver; this is one of the abstractions to make disk drive access available with a common interface; this beats everyone writing a different custom driver for their disk or controller). One has to load the ATA driver module before the controller can look for a disk.
Suppose the kernel module (a separate file not in the “
/boot” directory; it is somewhere under “
/lib/modules/$(uname -r)/kernel”) is itself on a disk. But ATA is needed to find the disk. All you have to do is load the driver from the ATA disk in order to read the ATA disk. Trouble in paradise (or at least in modules)!
It is easy to load the kernel itself (the integrated kernel
Image). The bootloader has methods to do so. If the modules were on the same disk as the kernel, then everyone would be happy. However, the ATA driver is on the external drive and not on the same drive the kernel is on. You get the proverbial “catch 22”.
You have two choices in how to get that module loaded in this case. The more complicated choice is to use an initial ramdisk (initrd) which basically has a miniature filesystem containing the module, and the bootloader starts with that, followed by switching over to the real filesystem after the module is loaded (which is the part which gives the kernel the knowledge to know how to do so).
The simpler choice is to move the feature out of the module and instead into the kernel
Image file itself. Then there is no need for the initial ramdisk. The boot software already knows how to load the kernel
Image file (the integrated kernel).
The gist is that a kernel has a bunch of optional features, and you need to find the existing set of features, and match that before building a kernel. Then you use a proper configuration editor, and simply switch the ATA driver from being built as a module to instead being built as an integrated feature. In a menu editor (there are several, it is a matter of preference), when you first start, you simply load a configuration copy. You then find the ATA driver. The install status will show as “
m” since it is built as a module. You simply switch it to “
y” (for “yes, build this into the kernel”). Then you build that kernel. The result is a kernel which matches the original features, but the ATA driver is now in the kernel
Image file rather than being a module.
After that you only need to install the kernel. You should probably ask about this rather than simply installing it once you have it. There are actually two methods by which the kernel
Image can be installed, and one is vastly simpler than the other. Also, when you rebuild a kernel, sometimes you must rebuild all of the modules as well. Those modules tend to require being arranged correctly, and that might arrange differently when you change the integrated kernel.
The URLs I gave before are a way to learn more, but you can always ask questions at any step. To get you started though, here are some details:
- Which release of L4T is your Jetson currently flashed with? See “
head -n 1 /etc/nv_tegra_release”.
- Go to that L4T release via https://developer.nvidia.com/linux-tegra (your particular JetPack release ties to this release).
- For the kernel source, download the “Driver Package (BSP) Sources”, which produces a file “
- That file has several things in it. The goal is to unpack the one which is “
- To unpack just that file:
tar -jxf public_sources.tbz2 'Linux_for_Tegra/source/public/kernel_src.tbz2'
- If you have that file you can now delete
- You now have to unpack the file you just unpacked:
tar xvfj kernel_src.tbz2
- You could (if you want) now delete “
kernel_src.tbz2”. It might be useful to keep this around until you are done just so you can easily start over, although using the right build options means you’ll never need to unpack this again unless you want to move to a different location.
- Go to the location where most build commands will be from:
- Often this will be referred to as the “top” directory location…the root of the kernel file build. If you want to temporarily memorize this location for that particular terminal you are working from (logout or going to a new terminal will erase this):
# and verify:
- Most documentation will simply say “
TOP” or “
$TOP” (the “
$” means the data pointed to by environment variable “
- Now read any documentation on configuration. The “
make” command target “
tegra_defconfig” will be found in many NVIDIA docs. This is the default configuration the Jetson will ship with. Alternatively, the kernel will reflect its current configuration in file “
/proc/config.gz”. Mostly the two will match, but if you are ever in doubt, and if the current modules will be reused, then refer to a copy of the “
/proc/config.gz” (the other URLs I gave talk more about this).
- Pay special attention in any documents to the feature “
CONFIG_LOCALVERSION”. This is not preserved in either “
make tegra_defconfig” or in “
/proc/config.gz”. If you run the command “
uname -r”, then the suffix is what “
CONFIG_LOCALVERSION” was set to during the build of the running kernel. This almost always defaults to “
-tegra”. If you are installing modules as well as changing the integrated kernel, then you might want to change this, e.g., to “
-tegra2” or “
-test”; if not, then you’d want this to remain an exact match with “
If you will build this on the host PC it isn’t a problem. Just install the tools in the documents which come with that release for “kernel customization”. Build steps will be the same other than some different environment variables, e.g., for cross compile you’ll see an “
export” of “
ARCH” and “
CROSS_COMPILE”; for natively compiling (directly on the Jetson) you wouldn’t use those.
The Jetson itself is unlikely to have enough disk space for this. Any temporary external media is useful for this, e.g., you could use a USB thumb drive to build on. Or just build it on the PC with those slightly different environment variables. Those other URLs should provide where to continue once you get that kernel source, but just ask if anything needs clarification. Definitely ask more before installing any kernel or module to the Jetson.