I am trying to update the kernel on board a Jetson Orin NX. I simply need the gs_usb driver installed in the kernel (or maybe it would be easier to compile the module and load it)?
I download the sources for 36.3 from here and follow the instructions.
I can get everything to build, but not sure how to customize it, or how to install it on the board.
Where do I put the config from the boards /proc/config.gz, and where (and how) do I run the compile commands? Once thats done, how do I install the new kernel?
Here is the bash script⊠everything compiles. How do I move the kernel module from the host to the target?
#!/bin/bash
## Step 0. Print some info
uname -r
head -n 1 /etc/nv_tegra_release
## Step 1. Ok, Lets download the necessary source and toolchain.
mkdir 36.3
cd 36.3
#make a folder for outputfiles and mod installs
mkdir kernel_out
mkdir -p rootfs/boot
#save our dirs
export SRC_PATH=$PWD
export OUT_PATH=$PWD/kernel_out
#download the source and extract other sources
wget https://developer.nvidia.com/downloads/embedded/l4t/r36_release_v3.0/sources/public_sources.tbz2
tar xf public_sources.tbz2
cd Linux_for_Tegra/source/
tar xf kernel_src.tbz2
tar xf kernel_oot_modules_src.tbz2
tar xf nvidia_kernel_display_driver_source.tbz2
# back to 36.3 Directory
cd $SRC_PATH
#download the tool chain and extract, only needed if cross compiling, but what the hey.
wget https://developer.nvidia.com/downloads/embedded/l4t/r36_release_v3.0/toolchain/aarch64--glibc--stable-2022.08-1.tar.bz2
tar xf aarch64--glibc--stable-2022.08-1.tar.bz2
export CROSS_COMPILE=$SRC_PATH/aarch64--glibc--stable-2022.08-1/bin/aarch64-buildroot-linux-gnu-
export ARCH=arm64
#get the current systems config file (Assuming you are on the target) and put it in the output directory
#the make command looks there for the .config
#zcat /proc/config.gz > jetson_config
#cp jetson_config $OUT_PATH/.config
#since we are going to cross_compile, lets say that our config is in the current dir we are running the script from
#You will need to copy it from the target to the host
cp $SRC_PATH/../config $OUT_PATH/.config
# Step 2. Ok, everything should be downloaded and environmental variables are set. Lets compile the kernel
cd $SRC_PATH/Linux_for_Tegra/source
#enable the RT patch bc we are cool.
./generic_rt_build.sh "enable"
# 2a. if you want to modify the config run this first, which stores the config in the OUT_PATH directory
#make O=$OUT_PATH -C $SRC_PATH/Linux_for_Tegra/source/kernel/kernel-jammy-src menuconfig
# 2b. if you want to build the config that is now in the OUT_PATH directory. We copied it over so we are just gunna go with it
make O=$OUT_PATH -C $SRC_PATH/Linux_for_Tegra/source/kernel/kernel-jammy-src
# 2c. If you just want to build in-tree modules, you can prepare the modules, then build just the modules
#youll need to run both these steps and dont need step 2b. Running 2b builds both kernel and modules
#make O=$OUT_PATH -C $SRC_PATH/Linux_for_Tegra/source/kernel/kernel-jammy-src modules_prepare
#make O=$OUT_PATH -C $SRC_PATH/Linux_for_Tegra/source/kernel/kernel-jammy-src modules
make O=$OUT_PATH -C $SRC_PATH/Linux_for_Tegra/source/kernel/kernel-jammy-src menuconfig
make O=$OUT_PATH -C $SRC_PATH/Linux_for_Tegra/source/kernel/kernel-jammy-src
#make O=$OUT_PATH -C $SRC_PATH/Linux_for_Tegra/source/kernel/kernel-jammy-src modules
#make O=$OUT_PATH -C $SRC_PATH/Linux_for_Tegra/source/kernel/kernel-jammy-src modules_install
These seem to running fine. There are some modules in root_fs/modules, nothing in root_fs boot.
When I run
sudo -E make install O=$OUT_PATH -C $SRC_PATH/Linux_for_Tegra/source/kernel/kernel-jammy-src
I get
sudo -E make install O=$OUT_PATH -C $SRC_PATH/Linux_for_Tegra/source/kernel/kernel-jammy-src
make: Entering directory '/home/~~~/Code/jetson_kern_dev/36.3/Linux_for_Tegra/source/kernel/kernel-jammy-src'
make[1]: Entering directory '/home/~~~/Code/jetson_kern_dev/36.3/kernel_out'
sh /home/~~~/Code/jetson_kern_dev/36.3/Linux_for_Tegra/source/kernel/kernel-jammy-src/arch/arm64/boot/install.sh 5.15.136-tegra \
arch/arm64/boot/Image System.map "/boot"
run-parts: executing /etc/kernel/postinst.d/dkms 5.15.136-tegra /boot/vmlinuz-5.15.136-tegra
* dkms: running auto installation service for kernel 5.15.136-tegra Error! Your kernel headers for kernel 5.15.136-tegra cannot be found.
Please install the linux-headers-5.15.136-tegra package or use the --kernelsourcedir option to tell DKMS where it's located.
[ OK ]
run-parts: executing /etc/kernel/postinst.d/initramfs-tools 5.15.136-tegra /boot/vmlinuz-5.15.136-tegra
update-initramfs: Generating /boot/initrd.img-5.15.136-tegra
W: missing /lib/modules/5.15.136-tegra
W: Ensure all necessary drivers are built into the linux image!
depmod: ERROR: could not open directory /lib/modules/5.15.136-tegra: No such file or directory
depmod: FATAL: could not search modules: No such file or directory
cat: /var/tmp/mkinitramfs_HLXh6r/lib/modules/5.15.136-tegra/modules.builtin: No such file or directory
W: Can't find modules.builtin.modinfo (for locating built-in drivers' firmware, supported in Linux >=5.2)
I: The initramfs will attempt to resume from /dev/dm-1
I: (/dev/mapper/ubuntu--vg-swap_1)
I: Set the RESUME variable to override this.
find: â/var/tmp/mkinitramfs_HLXh6r/lib/firmwareâ: No such file or directory
depmod: WARNING: could not open modules.order at /var/tmp/mkinitramfs_HLXh6r/lib/modules/5.15.136-tegra: No such file or directory
depmod: WARNING: could not open modules.builtin at /var/tmp/mkinitramfs_HLXh6r/lib/modules/5.15.136-tegra: No such file or directory
run-parts: executing /etc/kernel/postinst.d/unattended-upgrades 5.15.136-tegra /boot/vmlinuz-5.15.136-tegra
run-parts: executing /etc/kernel/postinst.d/update-notifier 5.15.136-tegra /boot/vmlinuz-5.15.136-tegra
run-parts: executing /etc/kernel/postinst.d/xx-update-initrd-links 5.15.136-tegra /boot/vmlinuz-5.15.136-tegra
run-parts: executing /etc/kernel/postinst.d/zz-shim 5.15.136-tegra /boot/vmlinuz-5.15.136-tegra
run-parts: executing /etc/kernel/postinst.d/zz-update-grub 5.15.136-tegra /boot/vmlinuz-5.15.136-tegra
Sourcing file `/etc/default/grub'
Sourcing file `/etc/default/grub.d/init-select.cfg'
Generating grub configuration file ...
Found linux image: /boot/vmlinuz-6.8.0-49-generic
Found initrd image: /boot/initrd.img-6.8.0-49-generic
Found linux image: /boot/vmlinuz-6.8.0-40-generic
Found initrd image: /boot/initrd.img-6.8.0-40-generic
Found linux image: /boot/vmlinuz-5.15.136-tegra
Found initrd image: /boot/initrd.img-5.15.136-tegra
Found linux image: /boot/vmlinuz-5.15.136-tegra.old
Found initrd image: /boot/initrd.img-5.15.136-tegra
Found linux image: /boot/vmlinuz-5.15.136
Found initrd image: /boot/initrd.img-5.15.136
Memtest86+ needs a 16-bit boot, that is not available on EFI, exiting
Warning: os-prober will not be executed to detect other bootable partitions.
Systems on them will not be added to the GRUB boot configuration.
Check GRUB_DISABLE_OS_PROBER documentation entry.
Adding boot menu entry for UEFI Firmware Settings ...
done
make[1]: Leaving directory '/home/~~~/Code/jetson_kern_dev/36.3/kernel_out'
make: Leaving directory '/home/~~~/Code/jetson_kern_dev/36.3/Linux_for_Tegra/source/kernel/kernel-jammy-src'
I am cross compiling on an x86 host. It found the newer kernel versionsâŠnot sure why its looking there.
Iâm not certain of all that you are trying to accomplish. Iâm going to list some information which might or might not apply, but you can ask more if you choose.
Official documentation centers on installing via setting up the host PCâs flash content.
It is trivial to not flash if you are only adding a module, and if that module is compatible with the current running kernel.
For a module to be compatible with the running kernel these are important:
Kernel source version must be the same.
The Image file (the actual kernel) determines the output of the command âuname -râ. This is used in locating modules. This is the base kernel source version, plus it appends the setting of CONFIG_LOCALVERSION at the time of compile. Usually you will see a Jetson output of this command to be named something with a kernel version and then â-tegraâ appended. That appended â-tegraâ means before compile CONFIG_LOCALVERSION was set to â-tegraâ. Check â/lib/modules/$(uname -r)/kernel/â.
Having a matching âuname -râ (same source version plus same CONFIG_LOCALVERSION) is necessary, but not the only requirement. The module picks up some configuration from the source code during build. This is why even if you build only one module you must first configure the kernel (the entire config used in building Image) to match the running kernel. It becomes possible to build only one module, but it is usually easier to just build them all and copy one to the right location.
Kernel features are enabled in an editor with either the m key or the y key. m is for module, y is to integrate the feature directly in the kernel Image. You canât have both. Some features (what I would call âsymbolsâ) cannot be a module, and some cannot be integrated, but most can. The context-aware editor (such as menuconfig or nconfig understands this and wonât let you break a dependency.
Official docs refer to how to cross compile, but other than not setting some environment, this will result in the same thing as natively compiling directly on a Jetson.
Official docs refer to how to install to the flash content, which is then flashed to the Jetson. You can also just take the output and put it on the Jetson.
The addition of only modules is a file copy, and telling the kernel it is there via âsudo depmod -aâ. Thatâs it.
The addition of a new âintegratedâ kernel Image is much more invasive. Always leave the original kernel in place as a backup. You will need a new CONFIG_LOCALVERSION if youâve changed the Image by adding or removing âintegratedâ (â=yâ) features. This implies the kernel will search for modules in a new location since âuname -râ changes. You must install 100% of all modules to this new location. When booted to the new kernel you would also want to run âsudo depmod -aâ once.
When adding a new âintegratedâ kernel Image file, letâs say you have a feature called âfooâ. You might use â-fooâ as the âCONFIG_LOCALVERSIONâ. Then, instead of overwriting the original Image, simply add your Image, but renamed Image-foo. Then edit boot entries in â/boot/extlinux/extlinux.confâ so you have both entries available: The original, and your new one. You can pick at boot time which to boot, and if something goes wrong, revert to the old one simply by picking it during boot.
When you replace the Image you must consider if you use some non-standard boot media. This is because there will be an initrd which contains a subset of your modules, and with the new kernel Image-foo not being able to use those modules, you would need that subset of modules added into the initrd. Example cases might be that you have an eMMC model of Jetson, and are booting to SD card (a dev kit with no eMMC wouldnât care, you could ignore that); or you boot an eMMC model to an NVMe or SSD (these would require an initrd, and âoftenâ any modules in this would now need a copy of the new kernelâs module subset).
What is it you wish to do? Install just new modules with a simple copy? Install a new kernel Image file, along with all else?
Do you wish to install instead by updating the flash content and flashing?
Ooookaay thank you, that clears things up for me now. As for what I am actually trying to accomplish, I simply need to build some in-tree modules that are not built in the 6.1 jetpack build. Specifically some can to usb and midi drivers.
So I have compiled everything, and have modules in the output rootfs folder and the kernel folder on a host machine, but can not get the âmake installâ command to run, but from what you are explaining, it appears that I do not need to do that, correct?
The addition of only modules is a file copy, and telling the kernel it is there via âsudo depmod -a â. Thatâs it.
So I would just copy the folder on the host from $INSTALL_MOD_PATH/lib/modules/5.15.136-tegra/kernel/drivers/net/can/usb to corresponding directory on the target platform, run chmod -R +755 usb on that directory to give it correct permissions, and then sudo depmod -a.
That seems to have loaded it and works on reboot, although I am not seeing any info in dmesg from the CAN device, but I do see a new CAN device with ip addr
Anything else I am missing in regards to the copying of files?
Is it correct that you set your âCONFIG_LOCALVERSIONâ to â-tegraâ before you built the modules? Did you also start with your original configuration, either with the âdefconfigâ target or some other method? Was the only change you made to add modules?
The path to copy the module files to directly should be correct. The use of depmod -a and a module loading seems to confirm it is all valid and correct.
Note that on devices which are not plug-n-play that manual steps have to be taken to tell the kernel driver the device is there, along with where to find it. Those cases use the device tree in many cases (not all cases). For example, a GPIO pin might need the device tree to tell it to use some alternate function, e.g., if it is a GPIO pin controlling something like a CANbus device, then even with the driver present the device tree would be required to tell it that the particular GPIO pin needs to be used like that (I donât know if this is the case for you, it is just a contrived example).
USB devices are in fact plug-n-play. When you plug a USB device in the device itself self-describes. USB broadcasts this, and a driver which can handle the device (if present) will take ownership. It is the loading of the driver in combination with specific hardware which cause the device special file to come into existence (that file is not a real file, but is instead something in RAM which is part of the driver pretending to be a file). If a file has been created by this, then it is very very likely that you have completed anything required for drivers or special configuration.
Once a device exists though, it is quite possible that you need user space software to work with it. When you set up a kernel driver and pair it to a device, that just makes it possible for system calls to work with the device. It would then be up to your other software to make use of it. dmesg logging might not show up if the driver doesnât announce itself in logs during normal creation; it is possible this would happen, but it is very likely that if a load failed, then this failure would be extremely likely to show up in logs.
Basically, I think you have completed everything you need with the kernel module(s). The way you have done this there is no need for âmake installâ (which would have copied a lot of files that already exist; only your driver module file mattered).