> ## Documentation Index
> Fetch the complete documentation index at: https://docs.avert.ldeo.columbia.edu/llms.txt
> Use this file to discover all available pages before exploring further.

# Updating the Linux kernel

In some instances, we have found that changes to the Linux kernel may be required in order to connect particular instruments to the system. The challenge for the embeddedTS-7970 SBC is the limited memory space available on the onboard SPI flash—8 MiB. The entire kernel, as well as U-boot (the bootloader that initialises the system), must fit in the available space.

EmbeddedTS maintain a version of the Linux kernel source with many of the required module flags enabled in the default config. This config can then be adjusted to enable any additional drivers, providing these drivers do not cause the final kernel image to exceed the aforementioned size.

It is easiest to build the kernel image on same system to which it will be deployed, but it is also possible to cross-compile the kernel using a different system. In this tutorial, we will assume you are building the new kernel image on an embeddedTS-7970 single-board computer.

## Pre-requisites

In order to build a new kernel image, you will need the following:

* an SD card with an already functioning version of the Linux kernel and an OS such as Debian 12 (bookworm);
* the ability to connect to the device, either in headless mode via serial or ethernet or by attaching peripherals (monitor, keyboard, mouse) to the board;
* an internet connection (see section on networking if you need to set this up) if you wish to clone the kernel sourcecode from the online repository (alternatively, you could copy the source repository onto the SD card before mounting to the board);
* the following packages installed from the Debian package repository: `u-boot-tools`, `<FIND FULL LIST>`.

## Building the new kernel image

### Get the kernel source

If you did not copy the source repository to the SD card, you will need to clone the repository containing the tuned Linux kernel from the embeddedTS GitHub:

```bash theme={null}
git clone https://github.com/embeddedts/linux-lts
```

This may take some time, as it is a few GB.

### Create a staging directory

Rather than building everything directly inside the cloned repository, we will specify a new directory to collect the outputs of each stage of the kernel build. This helps to keep everything organised in case you need to rebuild the kernel in the future.

```bash theme={null}
mkdir kernel-build<suffix>
export KERNEL_BUILD_OUT=~/kernel-build<suffix>
```

where you should replace `<suffix>` with some unique identifier for the kernel build, e.g., `-avert`. This suffix will be used again when configuring the kernel.

<Note>
  If, for any reason, you do not complete all of these steps in a single
  session, you may need to re-export the `KERNEL_BUILD_OUT` variable.
</Note>

### Create an initial configuration file

Navigate to the directory containing the kernel source code (likely `~/linux-lts`). Create a new config for the specific i.MX6 processor used on the TS board:

```bash theme={null}
cd ~/linux-lts
make O=$KERNEL_BUILD_OUT tsimx6_defconfig
```

### Edit the configuration file

This is the point when you can select which additional modules/utilities you would like to enable in the kernel. In addition, you should specify the `CONFIG_LOCALVERSION` here to match the suffix you chose above (e.g., `-avert`).

```bash theme={null}
make O=$KERNEL_BUILD_OUT nconfig
```

This will open up a menu in the terminal window that you can navigate with the arrow keys. You can use the search function to find relevant modules to enable/disable (using the function keys as specified at the bottom of the terminal).

With the configuration now set, we can propagate these changes. This isn't strictly necessary, as we will be building the entire kernel from scratch, but for completeness, run the following:

```bash theme={null}
make O=$KERNEL_BUILD_OUT modules_prepare
```

### Build the kernel image and modules

This stage can take a significant amount of time (> 1 hour). In order to ensure this proceeds as quickly as possible, be sure to include the `-j` flag, which sets the number of cores to be used while compiling the image. For example, for the quad-core model of the 7970, we can use `-j 4`.

```bash theme={null}
make O=$KERNEL_BUILD_OUT -j 4 Image
```

Once complete, we have our new kernel image, which can be found at `$KERNEL_BUILD_OUT/arch/arm/boot/Image`. However, this image is both too large and not directly compatible with U-boot. In order to get the required uImage (and zImage), run:

```bash theme={null}
make O=$KERNEL_BUILD_OUT -j 4 uImage LOADADDR=0x12000000
```

The important thing here is to specify the `LOADADDR`, which is a memory address used by the U-boot bootloader to find the image. This can be checked by booting into U-boot (hold down the reset pin while powering the 7970).

Repeat the process to build the modules:

```bash theme={null}
make O=$KERNEL_BUILD_OUT -j 4 modules
```

### Install the new image and modules

Once complete, you should have everything needed, the last thing to do is to install the new image and modules. Navigate to the directory containing the freshly built image and modules and install with elevated privileges:

```bash theme={null}
cd ~/$KERNEL_BUILD_OUT
sudo make modules_install
sudo make install
```

This installs everything except the `uImage`/`zImage` files. Make a backup of the current files (found in `/boot`), then copy the two files with elevated privileges:

```bash theme={null}
mkdir ~/image-backups
sudo cp /boot/zImage ~/image-backups/.
sudo cp /boot/uImage ~/image-backups/.
sudo cp ~/$KERNEL_BUILD_OUT/arch/arm/boot/zImage /boot/.
sudo cp ~/$KERNEL_BUILD_OUT/arch/arm/boot/uImage /boot/.
```

Finally—reboot the system. Any issues can be diagnosed over the serial connection. If the system fails to boot, you can revert back to the previous kernel image by mounting the SD card on another Linux system and manually moving the `uImage` and `zImage` files back to the `/boot` directory.

If everything boots, you can check the new kernel has been correctly loaded by running:

```bash theme={null}
uname -r
```

This should return the kernel version with the suffix defined in `CONFIG_LOCALVERSION`.
