I was working on a project that required writing a Linux device driver. I chose to do this on a Beaglebone Black, an inexpensive single board Linux computer. The first step was to set up an environment to build a custom kernel and device tree. This write-up describes that process.

The board I am using can be found here.

Initial Setup

I am developing on a windows machine using a Linux virtual machine in Oracle VirtualBox. If you are developing directly on a Linux machine or some other platform not all of these instructions will be applicable. The first step is to follow the beaglbone quick start guide to boot the board. To summarize:

Download the official beaglebone image from the beagleboard website.

Use BalenaEtcher to flash an SD card with the image.

Connect to the Beaglebone using a breadboard and USB serial adapter like this one, connected to the serial header on the Beaglebone black. The connector is next to the 48 pin connector on the power supply jack side of the board:

Pin 1 (closest to power supply side): Ground
Pin 4: RX
Pin 5: TX

I connected to the Beaglebone through a router, so I configured my VM with a bridged network adapter and created a DHCP reservation so it's IP address does not change. I did the same for the beaglebone.

Attach the USB serial adapter to the VM.

On the VM, install the packages needed for the kernel build process:

sudo apt-get install  gcc-arm-Linux-gnueabi qt5-default g++ pkg-config libssl-dev flex bison picocom git

In a terminal window, connect to the Beaglebone. /dev/ttyUSB0 here is the USB serial adapter. Connect to the board with Picocom:

sudo picocom -b 115200 /dev/ttyUSB0
(ctrl a ctrl x to exit)

Log in with the default credentials printed in the terminal window and create a new user account:

sudo adduser alex (use the default credentials for sudo)

Add the new user to the sudo group:

sudo usermod -aG sudo alex

An optional step for convenience is to modify the sudoers file so the new user account doesn't require a password to use sudo. Obviously this is insecure.

sudo visudo

added line:

alex ALL=(ALL) NOPASSWD: ALL

Ctlr x + y + enter to save.

Back on the Linux VM, create an SSH key pair (or use an existing one):

ssh-kegen -t rsa

Use SCP to copy the public key to the beaglebone (replacing the IP):

scp ~/.ssh/id_rsa.pub alex@192.168.0.101:~

SSH into the Beaglebone and create an authorized_keys file to set up SSH authentication:

ssh alex@192.168.0.101

mkdir .ssh
cp id_rsa.pub .ssh
cd .ssh
touch authorized_keys
cat id_rsa.pub >> authorized_keys

Back on the Linux VM, set up a host profile for the Beaglebone:

sudo vi ~/.ssh/config

Add the following lines, again replacing the IP address:

Host beagle
    HostName 192.168.0.101
    User alex
    IdentityFile ~/.ssh/id_rsa

Now it is possible to log in to the Beaglebone with:

ssh beagle

Building the Kernel

On the Linux VM, clone the Beaglebone Linux kernel:

git clone git://github.com/beagleboard/Linux.git

On the Beaglebone, obtain the version of the existing kernel:

uname -r

The output of this command is the tag name to check out in the Beaglebone repository. Back on the VM:

git checkout <version>

Create a new branch for your kernel development:

git checkout -b custom-kernel

The ARCH and CROSS_COMPILE environment variables need to be set. They can be passed on the command line but, for convenience, add them to your bash profile: vi ~/.profile

export ARCH=arm
export CROSS_COMPILE=arm-Linux-gnueabi-

Change into the Linux directory and build with the default configuration:

make bb.org_defconfig

If desired, this configuration can be modified with xconfig/menuconfig etc. eg:

make xconfig

Modify the kernel version string to indicate the custom kernel, in the top-level Makefile:

EXTRAVERSION = <some version string>

Build the Linux image and device tree binaries, passing the LOADADDR parameter:

make LOADADDR=0x81000000 uImage dtbs

Deploy the Kernel

Using TFTP provides a quick way to load the kernel at boot time. On the VM, install a tftp server:

sudo apt-get install tftpd-hpa

Copy the vImage and device tree binary from the Linux directory to the tftp server directory (this can be scripted so it happens when you build a new kernel):

sudo cp arch/arm/boot/zImage /var/lib/tftpboot
sudo cp arch/arm/boot/dts/am335x-boneblack.dtb /var/lib/tftpboot

Reset the Beaglebone with the reset button. Then, in the Picocom window connected to the board via serial, interrupt the boot process with the space bar. Set the following U-boot environment variables and arguments (192.168.0.101 is the IP of the Beaglebone, 192.168.0.102 is the VM):

setenv ipaddr 192.168.0.101
setenv serverip 192.168.0.102
setenv bootcmd 'tftp 0x81000000 zImage; tftp 0x82000000 am335x-boneblack.dtb; bootz 0x81000000 - 0x82000000'
setenv bootargs ip=dhcp console=ttyS0,115200n8 root=/dev/mmcblk1p1 rw
saveenv

Reset the Beaglebone again. You should be able to log in via SSH or the serial terminal. Verify the kernel version shows the custom kernel version string from above:

uname -a

This setup provides a complete environment for modifying, building, deploying and testing a custom Linux kernel. In a future post, I am going to add a UART device and write a basic serial driver module to my kernel.

Tips

If you end up re-imaging your Beaglebone, you will get a host key error when attempting to SSH to it. You can fix it with the following:

ssh-keygen -R <hostname>

where <hostname> is the Beaglebone's IP address

References

Bootlin (a great resource for tons of Linux related development.)

Kernel Build (good tips on cross-compiling for the Beaglebone)

Get honeypotted? I like spam. Contact Us Contact Us Email Email ar.hp@outlook.com email: ar.hp@outlook.com