Buildroot is simply my favorite step forward from the dark days of cross-compiling and bootstrapping in the blind. There are plenty of great resources out there that cover buildroot and initial configuration. Personally I’ve enjoyed George Hillard’s four-part series: Mastering Embedded Linux.
I’m working on some lowcost image cameras for my own MR/XR/CV purposes, so I was delighted in beginning my work on this project to find buildroot and Mr. Hillard’s good walkthrough.
Buildroot will get a large number of COTS boards booting to a minimum level. Once you’ve reached that point you have to decide on a large array of build and package options and then finally configuration of any daemons or services you’ve chosen. Personally, I prefer an initial boot and smoke test of an image. Once that’s proven working I prefer configuration via loopback mounts on my Linux dev box (Linux or MAC will do just fine).
BURN YOUR FIRST IMAGE TO SD CARD
So you’ve patiently waited for buildroot to generate an image! Congrats! Let’s spin that new image up! Insert your SD card into your USB drive or SD card slot
FIND YOUR SD CARD
sudo fdisk -l
The above will barf a fair bit of information related to all of your drives. Be mindful, your SD card is probably not going to be named “sda” pay attention to your drive size, if your SD card is not initialized it may simply be displayed with the drive information and no partitions. So, for instance, my SD card is shown below.
Disk /dev/sdf: 1.9 GiB, 2002780160 bytes, 3911680 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x00000000
Device Boot Start End Sectors Size Id Type
/dev/sdf1 * 2048 22527 20480 10M c W95 FAT32 (LBA)
/dev/sdf2 22528 145407 122880 60M 83 Linux
This particular SD card is actually a 32GB card, but the image that is currently written to it is only 2GB in size.
WRITE YOUR IMAGE
The below line should be modified to reflect your input file’s location (if=) and the output file (of=), in this case, it’s the proper device path for your drive (/dev/sdf). Be certain of your drive destination here (There be dragons, which will happily burn the start of a partition!)
sudo dd if=output/images/sdcard.img of=/dev/sdf bs=1M status=progress
BOOT YOUR IMAGE
Hey! We’ve come all this way it’s time for the “smoke test”, don’t worry, I’m unaware of a single instance where the initial image ever let the magic smoke out of boards. The worst you’ll get is a failure to boot, perhaps if you’ve misconfigured or misidentified your board version (Raspberry Pi which version?) you may get a kernel panic. No worries. Slap it in and let’s see! I leave it to you for output be it a serial TTY or full video to watch the boot! If it didn’t or doesn’t (boot), don’t worry you’re not the first or the last. Check the board, version, and check your buildroot board config and version information. You’ll get it.
NEXT STEPS
Finally, I leave you with your first “tool” for your new buildroot dev board. Mounting your buildroot image locally. This is a good first step and fallback to a fully realized dev environment for the board your bootstrapping. I use this to get my ssh keys in place, setup development network options, and many quick dirty trials where it’s faster than sitting at the CLI to configure and setup.
MAKE YOUR SD MOUNT POINT
First, we’ll create a mount folder for our use. I drop mine into the ‘/mnt’ folder on Linux or for Macs. You could use ‘/media’ and if you’re extra special you can pick your very own location.
sudo mkdir /mnt/sdimg
FIND YOUR IMAGE OFFSET
You’ll need to compute your image offset. The buildroot image file has two partitions and the first is usually a boot loader marked as a FAT/W95 partition (We don’t want to mount that!). You’ll use the good ol’ ‘fdisk -l‘ just like we did from the Find Your SD Card section. This can be done on the sd card device if you have it inserted on your computer (For me this was device drive /dev/sdf) or you can pull this information directly from the built image (sdcard.img).
fdisk -l output/images/sdcard.img
Disk output/images/sdcard.img: 523 MiB, 548405248 bytes, 1071104 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x00000000
Device Boot Start End Sectors Size Id Type
output/images/sdcard.img1 * 2048 22527 20480 10M c W95 FAT32 (LBA)
output/images/sdcard.img2 22528 1071103 1048576 512M 83 Linux
You will only need two bits of information from the second partition, which is the start sector. Above this is 22528 this offset will stay consistent for a given target build and buildroot version. It may change given board/processor options or an updated buildroot revision. We take that information and multiply it by the Units at the top of the fdisk output: 512. So…
Offset = 22528 x 512 = 11534336
Now let’s mount this…
MOUNT LOOPBACK
Next, you’ll need to mount your image to the folder using a loopback. This is not a network loopback, but a block device loopback and implementation will vary for distros and versions. Most modern distros support loopbacks out of the box using ‘mount -o‘, older distros may require the use of losetup or even more esoteric steps, don’t google it unless you need it I say. Using Ubuntu 18.04 it’s easy.
sudo mount -o loop,offset=11534336 output/images/sdcard.img /mnt/sdimg
So you should now be able to access and modify your buildroot file system from your mount point! (For me this is /mnt/sdimg). This is your first tool in your new target environment. I often set up ssh keys and set up various network interfaces before doing more direct work on the target system. Occasionally it’s faster to prototype some directory trees, scripts, and system structures from a full box than CLI on the target system and this is one way to get that work done.
ls -la /mnt/sdimg/
total 92
drwxr-xr-x 18 root root 4096 May 25 03:51 .
drwxr-xr-x 3 root root 4096 Jul 25 17:49 ..
drwxr-xr-x 2 root root 4096 May 25 03:51 bin
drwxr-xr-x 4 root root 4096 May 21 21:23 dev
drwxr-xr-x 15 root root 4096 May 25 03:51 etc
drwxr-xr-x 7 root root 4096 May 25 03:51 lib
lrwxrwxrwx 1 root root 3 May 24 17:38 lib32 -> lib
-rwxr-xr-x 1 root root 5136 May 25 03:51 linuxrc
drwx------ 2 root root 16384 May 25 03:51 lost+found
drwxr-xr-x 10 root root 4096 May 25 02:18 media
drwxr-xr-x 2 root root 4096 May 21 21:23 mnt
drwxr-xr-x 2 root root 4096 May 21 21:23 opt
drwxr-xr-x 2 root root 4096 May 21 21:23 proc
drwx------ 3 root root 4096 May 22 20:44 root
drwxr-xr-x 3 root root 4096 May 25 02:17 run
drwxr-xr-x 2 root root 4096 May 25 03:51 sbin
drwxr-xr-x 2 root root 4096 May 21 21:23 sys
drwxrwxrwt 3 root root 4096 May 24 21:04 tmp
drwxr-xr-x 8 root root 4096 May 25 03:51 usr
drwxr-xr-x 5 root root 4096 May 23 01:04 var
NEXT STEPS
In a future post I’ll walk through my buildroot setup choices and dive into the DTB (Device Tree Blob) where the arm soc peripherals live their separate meta compiled lives…