# How to Build Linux kernel for BeagleBone Black
# Pre-requisite
### Host Machine Environment
```bash
$ uname -a
Linux elinlinux 5.4.0-169-generic #187-Ubuntu SMP Thu Nov 23 14:53:38 UTC 2023 aarch64 aarch64 aarch64 GNU/Linux
```
### Target Machine Environment
- Board: BeagleBone Black
- processor: Sitara XAM3359AZCZ100 Cortex A8 ARM
### FTDI USB to Serial cable
<img src="https://hackmd.io/_uploads/H1L74Xysp.png" width=50% height=50%>
Which can be found at: [http://www.ftdichip.com/Support/Documents/DataSheets/Cables/DS_TTL-232R_CABLES.pdf](http://www.ftdichip.com/Support/Documents/DataSheets/Cables/DS_TTL-232R_CABLES.pdf)
# Toolchain
### Create workspace
Create a working area to place the tools and components of the system.
```makefile
cd ~
mkdir beaglebone_workspace
cd beaglebone_workspace
```
### Install require packages
Make sure that your host machine is up to date and install the essential tools, and other tools required for cross compilation.
```makefile
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install build-essential
sudo apt-get install flex bison
sudo apt-get install lzop
sudo apt-get install u-boot-tools
```
### GCC Cross Compiler
```bash
sudo apt-get install gcc-arm-linux-gnueabihf
```
### GCC libc source
```bash
mkdir arm-toolchain
cd arm-toolchain
wget -c https://releases.linaro.org/components/toolchain/binaries/latest-7/arm-linux-gnueabihf/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz
tar xf gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz
```
### Partition Manager
```bash
sudo apt-get install gparted
```
# BootLoader (U-boot)
### Das U-boot source
[https://github.com/u-boot/u-boot](https://github.com/u-boot/u-boot)
### Download u-boot (u-boot-2023.10)
Choose a u-boot version to download.
```makefile
wget -c https://github.com/u-boot/u-boot/archive/refs/tags/v2023.10.tar.gz
```
### Configure U-Boot
```makefile
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- am335x_boneblack_vboot_defconfig
```
### Compile U-boot
```makefile
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j4
```
> Refer [U-Boot: Building with GCC](https://docs.u-boot.org/en/latest/build/gcc.html) for more information.
### `MLO` and `u-boot.img`
After the `BootLoader` has been compiled, run the `ls` command to make sure that you have the executables `MLO` and `u-boot.img`. The `MLO` file is the **first stage BootLoader**, and `u-boot.img` is the **second stage BootLoader** also known as the **Bootstrap Loader**.
# Configure `Linux Kernel` for `BeagleBone Black`
### Beaglebone Linux Kernel source
[https://github.com/beagleboard/linux](https://github.com/beagleboard/linux)
### Download Linux kernel
Choose a linux kernel version on your demand.
```makefile
wget -c https://github.com/beagleboard/linux/archive/refs/tags/5.10.168-ti-r76.tar.gz
tar -xvf 5.10.168-ti-r76.tar.gz
```
### Kernel Configuration for BeagleBone Black
```bash
sudo make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- bb.org_defconfig
```
### Build the Kernel
```bash
sudo make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- uImage dtbs LOADADDR=0x80008000 -j4
```
### Result
![build_kernel_result](https://hackmd.io/_uploads/Bk98QQkjT.png)
### Build modules
```bash
sudo make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j4 modules
```
> Refer [admin-guide](https://github.com/beagleboard/linux/tree/v5.19/Documentation/admin-guide) for more information.
>
# Preparing the MicroSD Card
### Create two partitions
> One partition for booting the kernel, and another one for the `Root File System`.
* Use `gparted` for partitioning.
* Create a new partition with 50 MiB for the size. Change the file system type to fat32 and label it boot.
* Add a second partition with 1000 MiB for the size, label it rootfs, and make sure that the file type is ext4.
![partition](https://hackmd.io/_uploads/HJ5CzQyoT.png)
# Root File System
### Download Busybox
```bash
cd ~/beaglebone_workspace
wget -c https://github.com/mirror/busybox/archive/refs/tags/1_36_0.tar.gz
tar -xvf 1_36_0.tar.gz
```
### Configure BusyBox
```bash
cd busybox-1_36_0
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- defconfig
```
```bash
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig
```
### Enable Build static binary (no shared libs) option
![menuconfig](https://hackmd.io/_uploads/BkR0-QJop.png)
### Build BusyBox
Install Busybox into the rootfs partition of your SD card
> The build automatically generates a file "busybox.links", which is used by 'make install' to create symlinks to the BusyBox binary for all compiled in commands. This uses the CONFIG_PREFIX environment variable to specify where to install, and installs hardlinks or symlinks depending on the configuration preferences. (You can also manually run the install script at "applets/install.sh").
>
> Refer [busybox: readme](https://github.com/mirror/busybox/blob/master/README) for more information.
```bash
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- CONFIG_PREFIX=/media/<username>/rootfs/ install
```
### Create required directories and files
create directories and files required by the `Linux Kernel` to boot the system
### dev/
```bash
mkdir dev
sudo mknod dev/console c 5 1
sudo mknod dev/null c 1 3
sudo mknod dev/zero c 1 5
```
### lib/ and usr/lib/
Copy the libraries from the arm toolchain into the root file system lib.
```bash
sudo cp -r ~/beaglebone_workspace/arm-toolchain/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/libc/lib/* ./lib/
```
```bash
sudo cp -r ~/beaglebone_workspace/arm-toolchain/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/libc/lib/* ./lib/
```
Create additional directories for mounting virtual file systems.
```bash
sudo mkdir proc sys root
```
### etc/
```bash
sudo mkdir etc etc/init.d
```
### etc/inittab
After the kernel boots, it spawns the first user process, called the `init`. `init` is a background process that runs unitil the system is shut down. This process requires a configuration file called `etc/inittab`, which contains actions the system needs to perform at a given runlevel.
```bash
sudo vi etc/inittab
```
Copy the following into the `etc/inittab` file:
```
::sysinit:/etc/init.d/rcS
::respawn:-/bin/sh
::askfirst:-/bin/sh
```
> For more setting options, please refer [IBM: inittab File](https://www.ibm.com/docs/en/aix/7.1?topic=files-inittab-file).
### etc/fstab
```bash
vi etc/fstab
```
Copy the following into `etc/fstab`:
```
proc /proc proc defaults 0 0
sysfs /sys sysfs defaults 0 0
```
> For more setting options, please refer [man: fstab](https://man7.org/linux/man-pages/man5/fstab.5.html).
### etc/hostname and etc/passwd
Write hostname into it.
```bash
sudo vi etc/hostname
```
```bash
sudo vi etc/passwd
```
Copy `root::0:0:root:/root:/bin/sh` into it.
### init.d/rcS
Create the file `init.d/rcS` to setup the system.
```bash
sudo vi etc/init.d/rcS
```
```bash
#!/bin/sh
# ---------------------------------------------
# Common settings
# ---------------------------------------------
# Replace <YOUR_HOSTNAME> with your hostname!
HOSTNAME=<YOUR_HOSTNAME>
VERSION=1.0.0
hostname $HOSTNAME
# ---------------------------------------------
# Prints execution status.
#
# arg1 : Execution status
# arg2 : Continue (0) or Abort (1) on error
# ---------------------------------------------
status ()
{
if [ $1 -eq 0 ] ; then
echo "[SUCCESS]"
else
echo "[FAILED]"
if [ $2 -eq 1 ] ; then
echo "... System init aborted."
exit 1
fi
fi
}
# ---------------------------------------------
# Get verbose
# ---------------------------------------------
echo ""
echo " System initialization..."
echo ""
echo " Hostname : $HOSTNAME"
echo " Filesystem : v$VERSION"
echo ""
echo ""
echo " Kernel release : `uname -s` `uname -r`"
echo " Kernel version : `uname -v`"
echo ""
# ---------------------------------------------
# MDEV Support
# (Requires sysfs support in the kernel)
# ---------------------------------------------
echo -n " Mounting /proc : "
mount -n -t proc /proc /proc
status $? 1
echo -n " Mounting /sys : "
mount -n -t sysfs sysfs /sys
status $? 1
echo -n " Mounting /dev : "
mount -n -t tmpfs mdev /dev
status $? 1
echo -n " Mounting /dev/pts : "
mkdir /dev/pts
mount -t devpts devpts /dev/pts
status $? 1
echo -n " Enabling hot-plug : "
echo "/sbin/mdev" > /proc/sys/kernel/hotplug
status $? 0
echo -n " Populating /dev : "
mkdir /dev/input
mkdir /dev/snd
mdev -s
status $? 0
# ---------------------------------------------
# Mount the default file systems
# ---------------------------------------------
echo -n " Mounting other filesystems : "
mount -a
status $? 0
# ---------------------------------------------
# Set PATH
# ---------------------------------------------
export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin
# ---------------------------------------------
# Start other daemons
# ---------------------------------------------
echo -n " Starting syslogd : "
/sbin/syslogd
status $? 0
echo -n " Starting telnetd : "
/usr/sbin/telnetd
status $? 0
# ---------------------------------------------
# Done!
# ---------------------------------------------
echo ""
echo "System initialization complete."
```
### Build directory for the kernel
After creating the above files and directories, install the kernel modules into the `Root File System`.
```bash
cd ~/beaglebone_workspace/linux-5.10.168-ti-r76
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- CONFIG_PREFIX=/media/<username>/rootfs/ modules_install
```
> Refer [admin-guide: build-directory-for-the-kernel](https://github.com/beagleboard/linux/tree/v5.19/Documentation/admin-guide#build-directory-for-the-kernel) for more information.
# Boot Partition
Create a boot folder in your workspace directory and copy `MLO`, `u-boot.img`, `uImage`, and `am335x-boneblack.dbt`.
```bash
cd ~/beaglebone_workspace/
mkdir boot
cp u-boot-2023.10/MLO boot/
cp u-boot-2023.10/u-boot.img boot/
cp linux-5.10.168-ti-r76/arch/arm/boot/uImage boot/
cp linux-5.10.168-ti-r76/arch/arm/boot/dts/am335x-boneblack.dtb boot/
```
### uEnv.txt
Go into the `boot` folder and create a file called `uEnv.txt`. This file will tell the `BootLoader` where to load the kernel image and the device binary tree.
```bash
vi boot/nEnv.txt
```
Copy the following into `uEnv.txt`:
```bash
uenv_addr=0x81000000
load_addr=0x82000000
dtb_addr=0x88000000
mmc_args=setenv bootargs console=ttyO0,115200n8 noinitrd root=/dev/mmcblk0p2 rw rootfstype=ext4 rootwait
sdboot=echo Booting from SD Card ...;mmc rescan;fatload mmc 0:1 ${uenv_addr} uEnv.txt;env import -t ${uenv_addr} $filesize;fatload mmc 0:1 ${load_addr} uImage;fatload mmc 0:1 ${dtb_addr} am335x-boneblack.dtb;run mmc_args;bootm ${load_addr} - ${dtb_addr}
uenvcmd=run sdboot
```
**Important:** Leave a newline at the end of the `uEnv.txt` file.
Finally, copy everything from the `~/beaglebone_workspace/boot` directory to the `BOOT` partition of your SD card.
```bash
cd ~/beaglebone_workspace/boot/
sudo cp * /media/<username>/BOOT/
sync
```
# Connect FTDI cable with the board
Connect FTDI cable with J1 serial header on the board.
![J1](https://hackmd.io/_uploads/B1zStzkia.png)
> For more information, refer [BBB_SRM: 7.5 Serial Header](https://github.com/beagleboard/beaglebone-black/blob/master/BBB_SRM.pdf).
# Boot result
After you boot up the board, the system should mount the root file system successfully and you should automatically be logged in as root `#`.
![boot_result](https://hackmd.io/_uploads/B1UOuz1jT.png)
# Reference
* [How to Build a Linux Distribution for the BeagleBone Black](https://buildelinux.readthedocs.io/en/latest/embedded_systems/linux_distribution/linux_distro/)