Complete beginner attempting to build/edit kernels

I have just made the move to ubuntu/linux after spending all my computing life in windows and everything here is new to me.

This is everything I’ve done so far :

I have just formatted my SD card and flashed the sd card image found here : https://developer.nvidia.com/embedded/learn/get-started-jetson-nano-devkit#write . Upon setting up my account, I went to the JetsonHacksNano github, https://github.com/JetsonHacksNano/buildKernelAndModules , to get the scripts for building the kernels and modules.

I am trying to get my LTE modem to work for a school project on drones and I came across this website: https://github.com/etu/gentoo-hardware-notes/blob/master/12d1:1506_Huawei_Technologies_Co._Ltd._Modem_Networkcard.org . In this guide, they mention something about kernel configs required to get the device working.

In the git clone I got from JetsonHacksNano, there was an editConfig.sh script which I was able to utilize to configure/turn on the required kernels to get my modem to work. However, I don’t know where the config file was saved to.

The config script looks like this:

#!/bin/bash
# Edit the kernel configuration for NVIDIA Jetson Nano Developer Kit, L4T
# Copyright (c) 2016-19 Jetsonhacks 
# MIT License

SOURCE_TARGET="/usr/src"
KERNEL_RELEASE="4.9"

function usage
{
    echo "usage: ./editConfig.sh [[-d directory ] | [-h]]"
    echo "-d | --directory Directory path to parent of kernel"
    echo "-h | --help  This message"
}

# Iterate through command line inputs
while [ "$1" != "" ]; do
    case $1 in
        -d | --directory )      shift
                                SOURCE_TARGET=$1
                                ;;
        -h | --help )           usage
                                exit
                                ;;
        * )                     usage
                                exit 1
    esac
    shift
done

LAST="${SOURCE_TARGET: -1}"
if [ $LAST != '/' ] ; then
   SOURCE_TARGET="$SOURCE_TARGET""/"
fi

# Check to see if source tree is already installed
PROPOSED_SRC_PATH="$SOURCE_TARGET""kernel/kernel-"$KERNEL_RELEASE
echo "Proposed source path: ""$PROPOSED_SRC_PATH"
if [ ! -d "$PROPOSED_SRC_PATH" ]; then
  tput setaf 1
  echo "==== Cannot find kernel source! =============== "
  tput sgr0
  echo "The kernel source does not appear to be installed at: "
  echo "   ""$PROPOSED_SRC_PATH"
  echo "Unable to edit kernel configuration."
  exit 1
fi

cd "$PROPOSED_SRC_PATH"
sudo make menuconfig
~                                                                               
~                                                                               
~

Once I set the required configs, and I save the file, does the system automatically detect and reconfigure itself to the configs I have selected/enabled? Or do I still need to do some tweaking?

Another issue I have is that there are so many kernel files in my usr/src folder:

root@gan-desktop:/usr/src# ls
cudnn_samples_v7                                 nvidia
hardware                                         public_sources
kernel                                           public_sources.tbz2
linux-headers-4.9.140-tegra-linux_x86_64         tensorrt
linux-headers-4.9.140-tegra-ubuntu18.04_aarch64

Is it supposed to be like this?

Thank you for the help! Greatly appriciate it

I haven’t used that script and can only provide some base information related to this.

First, if you run the command “which ls” you may find that “ls” is an alias for “ls” plus some other options. Many default “ls” setups do not show “hidden files”.

Hidden files are not really hidden like in Windows. These are just files starting with a “.” instead of any other character. It is tradition to not clutter up ls with all of the “.” files. For example, “.” is also the name of the current directory, and “…” is the name of the parent directory. Very few people care to run “ls” against the parent directory and only want the content of the current directory, not the directory name itself.

If you were to run “which ls” and it were to show “ls” is really “/usr/bin/ls” with options, then you could see all files by using the full path to ls with the “-A” option (or “-a”, but for your purposes “-A” might be better).

The config file used in a compile is always named “.config”. Wherever that file is, you won’t find it with “ls” unless it is showing “hidden” files, e.g., with “/usr/bin/ls -A” (sometimes the aliased “ls” will accept “-A” or “-a” and work correctly without naming the full path to ls, but I use the full path because it guarantees “-A” or “-a” will work to show files starting with “.” in the name).

If you compile the kernel right in the location where the source code is (very highly discouraged), then the “.config” will be at the base of the kernel source there. If you’ve compiled with “O=/some/where” to make temporary content show up there instead of polluting the actual kernel source, then this is where “.config” will appear.

I usually advise people building kernels to save a safe copy of the original configuration prior to changing anything. The file “/proc/config.gz” is not actually on the file system, but is instead content in RAM which the kernel is providing to tell you what its config is (other than CONFIG_LOCALVERSION this is an exact match to the currently running system). If you were to save “config.gz” somewhere, gunzip it to decompress, and copy to your kernel compile output location as “.config”, then other than CONFIG_LOCALVERSION you would get an exact clone of that configuration. I consider this the best starting config, and running “make O=/some/where nconfig” (you might need to “sudo apt-get install libncurses5-dev”) would result in the initial config from your config.gz being what the config editor starts with (every option you initially see in any config editor would start with the “.config” which is from “config.gz”).

The “make tegra_defconfig” target will be close to starting with this config. This produces a “.config” in your temporary output location (or the current source tree if compiling directly there without the “O=” option). This is not a guarantee of a match of what you already have. This should work, but might not always be what you expect.

Hi linuxdev,

Thank you for the detailed reply! I really appreciate the help. :)

Here are screenshots of me editing the kernel: https://imgur.com/a/TfdsJz4 using the ./editConfig.sh

I am still a little unsure of whether the config file I edited was saved correctly or if I had done something wrong.

Also, if I understood correctly, the config file in proc/config.gz is like a backup of all the config files? So is it safe to say that by editing the proc/config.gz file, it would not take effect on my nano?

Another doubt I have is that, in the kernel configuration, does it matter if I enable the kernel as a kernel(*) or module(M)?

Thank you!

JetsonHacksNano github script is good for understanding the procedure of building, but not good for real work.

My suggestion:

  1. highly recommend using another X86_64 server to build the kernel. it is quicker and you may find yourself much better status for debugging the issues.
  2. do not mess up with system folder. Put everything under your home account. (cross compiler and kernel source code)
  3. setup environment parameters as instruction before your building.
  4. maybe not good idea using “manuconfig” (or ./editConfig.sh). the issue is: it is very hard to locate your device in the huge device tree. located .config file, search your device and change it.
  5. everything you need actually is included in official kernel development document.

You cannot directly edit “/proc/config.gz”. You must copy it to some other location, and then you can edit this (the actual “/proc/config.gz” is output from a driver and is not writable). This file should be copied to a safe location prior to making any kernel changes…this file is an exact specification of the currently running system, and if something goes wrong, then this is one way to put it back to how it was. Backup purposes, but the file on the running system is itself not really a file. Once you copy this somewhere, then the copy becomes a backup.

The editor in your image would save a “.config” file by default when clicking the “Save” button, or click to save on exit.

If you do a verbose “ls” (which is “ls -l .config” for your example), then the date and time of last modification is shown. If you use the “O=/some/where”, then the “.config” would be there, and you could cd to that location, then “ls -l .config” to see the last change time. If you do not use the “O=/some/where”, then it is from the location you ran the menu editor (if you use “O=/some/where”, then you must be careful to use it in all of your “make” commands).

The actual command which brings up that config editor would be either “make menuconfig”, or “make O=/some/where menuconfig”. There are many different editors, and they all operate the same…some people will prefer one over the other, the one you are using is the most commonly cited editor in tutorials. This in fact does edit the “.config”.

I don’t know what the script does. The script is probably not a bad idea, and scripts are human readable, so you could see what is in the script by doing something like this from the directory with the script:

cat ./editConfig.sh
# Or with a pager:
cat ./editConfig.sh | less

When convenience scripts like this are published it is usually because many people have run into some task which leads to questions. If you read the commands from the script, then this is a good way to learn what it is trying to accomplish. Quite often you can edit the script and use it with your own customizations. Whether this is good or bad for your case I couldn’t say, but I always consider it good to try to understand what the content of the script is doing.

Note that config editors are aware of dependencies. If you edit a “.config” manually, and for example add a feature with “…=m”, then it is possible prerequisites will be missed, or that you will try to build a module for a feature which only works with the “…=y” choice. When you edit with menuconfig or other editor, then this will never be an issue. The only thing I edit by hand in the “.config” is the “CONFIG_LOCALVERSION”, but I already know there are no dependencies and I know that this must always be customized with this for a default Jetson:

CONFIG_LOCALVERSION="-tegra"

(this is a special case feature and is just more convenient for me to edit this way)

Note: Module format (“m”) can be installed without risk as a simple file copy to the right location. Integrated format (“y”) requires the kernel Image itself to be replaced. This can be a problem if you’ve made an error…the system might not be bootable. Not every feature can be a module, but if it can, then the menu editor will allow the “m” setting and your life will be simplified. Even if I build a module I still build the whole kernel Image as an acid test prior to building the module…but then I wouldn’t actually install the Image, I’d only install the module.