# Compiling and Porting the Linux Kernel to the Beaglebone Black

This is Part 3 of this blog series, this is a continuation of the write-up for my assignment.

This blog is based on Bootlin's [Embedded Linux Course](https://bootlin.com/training/embedded-linux/) as well as [Frank Vasquez and Chris Simmonds Mastering Embedded Linux Programming](https://www.packtpub.com/product/mastering-embedded-linux-programming-third-edition/9781789530384), so you may have some success reading their materials alongside this blog.

In this section, we will be compiling, and configuring the Linux kernel and porting it to the Beaglebone Black.

If you haven't read [Part 1](https://blog.billvanleeuwen.ca/creating-a-cross-compiling-toolchain-for-beaglebone-black-with-crosstool-ng) and [Part 2](https://blog.billvanleeuwen.ca/porting-u-boot-onto-the-beaglebone) of this series, you may be lost.

## Fetching the source code

First, clone the Linux repository into an appropriate directory.

```bash
git clone https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux
```

This repository is, at the time of writing, 2.5GB, so go grab a coffee.

Now we have the Linux source code on our machine. However, these are the 'mainline' releases where we would be best off using the 'stable' releases. These are maintained in a separate repository. For more info on what this means, check out [This Page](https://www.kernel.org/category/releases.html) on the differences.

```bash
cd linux
git remote add stable https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux
git fetch stable
```

This again may take a while depending on your internet speed.

## Cross-compiling the kernel

At the time of writing, `remotes/stable/linux-6.1.y` is the latest stable release, you can check your branches with

```bash
git branch -a
```

You can check which kernel version the local repository is on with

```bash
make kernel version
```

My output was: `6.2.0-rc5`

*Aside* - This means [Linus Torvalds](https://en.wikipedia.org/wiki/Linus_Torvalds) is currently working on releasing Linux 6.2.0, and on Release Candidate #5. Again, check [This Page](https://www.kernel.org/category/releases.html) to learn more about what that means.

Let's choose the newest stable branch in an attempt to stay current.

```bash
git checkout remotes/stable/linux-6.1.y
```

Try `make kernelversion` again to see the difference.

Define some environment variables so Linux's make scripts know what we want to compile for an ARM board, and know what C compiler we want to use (make sure the cross-compiling toolchain we made in [Part 1](https://blog.billvanleeuwen.ca/creating-a-cross-compiling-toolchain-for-beaglebone-black-with-crosstool-ng) of this blog series is on the PATH).

```bash
export ARCH=arm
export CROSS_COMPILE=arm-training-linux-uclibcgnueabihf-
```

Run `make help`. Without exporting the variables above, or including them in the command, your output will look much different. This will show you all of the configurations Linux can build for. Ours for the Beaglebone is multi\_v7\_defconfig ([Frank Vasquez and Chris Simmonds Mastering Embedded Linux Programming](https://www.packtpub.com/product/mastering-embedded-linux-programming-third-edition/9781789530384) says to use this one, while [Bootlin](https://bootlin.com/training/embedded-linux/) says to use omap2plus\_defconfig, but both worked for me.)

Enter the configuration menu with `make menuconfig`

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1674525847163/2244d75c-a96e-412b-be97-7be8d99db6cc.png align="center")

In this menu, find and disable CONFIG\_GCC\_PLUGINS. Bootlin suggests this, as it will skip building special plugins which require extra dependencies, and we don't need them. You can find the location of this using typical vim commands. Enter `/` to search for this option.

Now, we're ready to compile the kernel!

```bash
# replace <n> with the amount of cores your CPU has to parallelize the build
make zImage -j<n>
```

Now sit back and wait for a bit. This will take a while depending on your CPU speed and core count.

Once the kernel compiles, you'll need to find two files and copy them to the `boot` partition of the SD card.

```plaintext
arch/arm/boot/zImage
arch/arm/boot/dts/am335x-boneblack.dtb
```

These are the kernel image, and the device tree file respectively.

Congratulations! You've compiled the kernel from source!

## Booting the Kernel

Plug in your USB to TTL cable, and start-up picocom to get a serial connection to the Beaglebone.

```bash
picocom -b 115200 /dev/ttyUSB0
```

We still want to boot from the SD card, rather than the bootloader on the eMMC. Be ready to press the space bar on your keyboard to avoid going through U-Boot's auto-boot sequence. Hold down the USR button, and plug in the cord to provide power to the Beaglebone.

Be sure you're greeted by your bootloader rather than the one on the eMMC. Check the date, like from [Part 2](https://blog.billvanleeuwen.ca/porting-u-boot-onto-the-beaglebone) of this series, and make sure it's the date in which you compiled U-Boot.

You should see the familiar prompt =&gt; on your picocom terminal.

Once the kernel boots up, we want it to send its output to its UART pins, which are the ones our USB to TTL converter are connected. Enter the following into your picocom terminal.

```bash
=> setenv bootargs console=ttyS0,115200n8
=> saveenv
```

Now we're going to load the kernel image, and device tree file into memory:

```bash
=> fatload mmc 0:1 0x80200000 zImage
=> fatload mmc 0:1 0x80f00000 am335x-boneblack.dtb
```

Let's boot this sucker!

```bash
=> bootz 0x80200000 - 0x80f00000
```

What you'll see in the output might look similar to:

```plaintext
[    0.000000] Booting Linux on physical CPU 0x0
[    0.000000] Linux version 6.1.7 (billsDesktop@fedora) (arm-linux-gcc (crosstool-NG 1.25.0.95_7622b49) 11.3.0, GNU ld (crosstool-NG 1.25.0.95_7622b49) 2.39) #2 SMP Mon Jan 23 20:25:30 EST 2023
[    0.000000] CPU: ARMv7 Processor [413fc082] revision 2 (ARMv7), cr=10c5387d
[    0.000000] CPU: PIPT / VIPT nonaliasing data cache, VIPT aliasing instruction cache
[    0.000000] OF: fdt: Machine model: TI AM335x BeagleBone Black

...

[    3.472852] Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0)
[    3.481165] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 6.1.7 #2
[    3.487037] Hardware name: Generic AM33XX (Flattened Device Tree)
[    3.493177]  unwind_backtrace from show_stack+0x10/0x14
[    3.498478]  show_stack from dump_stack_lvl+0x40/0x4c
[    3.503584]  dump_stack_lvl from panic+0x108/0x33c
[    3.508434]  panic from mount_block_root+0x168/0x208
[    3.513462]  mount_block_root from prepare_namespace+0x150/0x18c
[    3.519523]  prepare_namespace from kernel_init+0x18/0x12c
[    3.525061]  kernel_init from ret_from_fork+0x14/0x2c
[    3.530156] Exception stack(0xe0009fb0 to 0xe0009ff8)
[    3.535240] 9fa0:                                     00000000 00000000 00000000 00000000
[    3.543464] 9fc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[    3.551684] 9fe0: 00000000 00000000 00000000 00000000 00000013 00000000
[    3.558350] ---[ end Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0) ]---
```

This last section might be problematic for someone not in our shoes, but for us, this [Kernel Panic](https://www.makeuseof.com/tag/dont-panic-everything-you-need-to-know-about-kernel-panics/) is mentioning that we don't have a root file system mounted. That's OK, we'll get to that in the next blog series.

For now, let's be happy we've booted a cross-compiled Linux kernel on the Beaglebone!

Automate this process with a simple bootscript:

```bash
=> setenv bootcmd 'fatload mmc 0:1 0x80200000 zImage; fatload mmc 0:1 0x80f00000 am335x-boneblack.dtb; bootz 0x80200000 - 0x80f00000'
=> saveenv
```
