Installing Debian 10 on the i.MX53 devboard
Last week, one of my friends told me that we have a ton of i.MX53 Quick Start boards collecting dust in a storage room at our uni.
I was thinking of maybe doing an Embedded Linux workshop of some kind with the board, and also use it as an opportunity to learn about the Linux boot process on embedded devices and the process of generating a Debian installation from scratch.
This guide walks through the process of installing Debian 10 on the board, and is a modified version of the InstallingDebianOn guide from the Debian wiki. I tried to add in-depth explanations (which I hope are helpful to someone out there).
Partitioning the SD card
First we’ll set up an MBR partition table (didn’t test this on GPT yet, but it should be possible) on a 4GiB SD card.
Also, we’ll make sure to leave 2 MiB of free space before the first partition; fdisk
does this by default.
We need two partitions: one for the boot files, and another one for the root filesystem (rootfs).
I like using an interactive fdisk
session to partition the disk (you can find a detailed tutorial here):
Note: you’ll have to change /dev/sdd
to the appropriate device on your machine
TODO: maybe rewrite this with parted
as a one-liner
$ sudo fdisk /dev/sdd
Welcome to fdisk (util-linux 2.40).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.
Command (m for help): o
Created a new DOS (MBR) disklabel with disk identifier 0x8d7f6430.
Command (m for help): n
Partition type
  p   primary (0 primary, 0 extended, 4 free)
  e   extended (container for logical partitions)
Select (default p): p
Partition number (1-4, default 1): 1
First sector (2048-7716863, default 2048): 2048
Last sector, +/-sectors or +/-size{K,M,G,T,P} (2048-7716863, default 7716863): +512M
Created a new partition 1 of type 'Linux' and of size 512 MiB.
Command (m for help): n
Partition type
  p   primary (1 primary, 0 extended, 3 free)
  e   extended (container for logical partitions)
Select (default p): p
Partition number (2-4, default 2): 2
First sector (1050624-7716863, default 1050624): Â
Last sector, +/-sectors or +/-size{K,M,G,T,P} (1050624-7716863, default 7716863): Â
Created a new partition 2 of type 'Linux' and of size 3.2 GiB.
Command (m for help): w
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.
This gives us the following:
$ sudo fdisk -l /dev/sdd
Disk /dev/sdd: 3.68 GiB, 3951034368 bytes, 7716864 sectors
Disk model: STORAGE DEVICE Â Â
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: 0x8d7f6430
Device     Boot   Start     End Sectors  Size Id Type
/dev/sdd1 Â Â Â Â Â Â Â Â Â 2048 1050623 1048576 Â 512M 83 Linux
/dev/sdd2 Â Â Â Â Â Â 1050624 7716863 6666240 Â 3.2G 83 Linux
Notice that the units are given in terms of 512-byte sectors; our first partition, dev/sdd1
, starts at an offset of 2048 * 512 = 1048576 (1 MiB).
We’ll format the boot partition as ext2
and the other one as ext4
:
$ sudo mkfs.ext2 -L "MX53_BOOT" /dev/sdd1
$ sudo mkfs.ext4 -T small -L "MX53_ROOT" /dev/sdd2
(-T small
is optional here).
Installing u-boot
Now here comes something really cool: u-boot, aka the Universal Boot Loader. Almost every embedded platform out there uses this as a bootloader. The i.MX53 is no exception.
Every platform has a different process of installation for u-boot (I don’t understand it very well myself), but for the i.MX53 apparently you just need to place it somewhere between the beginning of the disk and the first partition (which is honestly pretty cool). We just have to make sure not to overwrite the MBR table in the process (which for our use case won’t exceed 1 KiB).
In order to achieve this, we will fetch the u-boot image for the iMX53 board from the Debian repos, and write it to an offset of 2 * 512 bytes = 1 KiB into the SD card, before the first partition starts:
$ wget "http://ftp.us.debian.org/debian/dists/buster/main/installer-armhf/current/images/u-boot/MX53LOCO/u-boot.imx.gz"
$ zcat u-boot.imx.gz > u-boot.imx
$ sudo dd if=u-boot.imx of=/dev/sdd seek=2 bs=512
Let’s quickly confirm we didn’t mess up the MBR table by doing this:
$ sudo sfdisk --verify /dev/sdd
/dev/sdd:
No errors detected.
The bootloader uses the serial (RS-232) port on the board, so in order to view the output and use the console you’ll probably need an RS-232 to USB adapter. You can use minicom
in order to view the serial output:
$ sudo minicom -D /dev/ttyUSB0
To save you from future headaches, you can press Ctrl+A -> O
to open the configuration menu, then go into the Serial port setup
window and press F
in order to disable Hardware Flow Control and allow you to type characters into the console
(you need to disable it because your RS-232 adapter most likely doesn’t support it, which makes you unable to
type into the console).
If all goes well, when you insert the SD card into the i.MX53 and reset the board, you should see something like the following on the serial port:
U-Boot 2019.01+dfsg-7 (May 14 2019 - 02:07:44 +0000)
CPU: Â Â Freescale i.MX53 rev2.1 at 800 MHz
Reset cause: POR
Board: MX53 LOCO
I2C: Â Â ready
DRAM: Â 1 GiB
MMC: Â Â FSL_SDHC: 0, FSL_SDHC: 1
Loading Environment from MMC... *** Warning - bad CRC, using default environment
In: Â Â Â serial
Out: Â Â serial
Err:   serial                                                                Â
Net: Â Â FEC Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â
Hit any key to stop autoboot: Â 0 Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â
switch to partitions #0, OK Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â
mmc0 is current device                                                       Â
** File not found boot.scr ** Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â
** File not found zImage **
Generating the rootfs
Important: this section assumes you’re using a Debian-based system. This should probably work on other distros, but it is untested. Experiment at your own risk. :-)
We will need debootstrap
– one of the coolest tools ever in the embedded Linux world – which will generate a Debian rootfs that we can use on the board. We will also need to use QEMU in order to emulate an arm
host when building the rootfs:
$ sudo apt update
$ sudo apt install debootstrap qemu-user-static
Now let’s mount the partitions we created earlier:
$ sudo mkdir -pv /mnt/debinst
$ sudo mount LABEL="MX53_ROOT" /mnt/debinst
$ sudo mkdir -pv /mnt/debinst/boot
$ sudo mount LABEL="MX53_BOOT" /mnt/debinst/boot
Then we can finally run the first stage of debootstrap
:
$ sudo debootstrap --arch armhf --foreign buster /mnt/debinst http://ftp.us.debian.org/debian
After this is finished, we will chroot
into the recently created rootfs to continue with the installation:
$ sudo cp -pv /usr/bin/qemu-arm-static /mnt/debinst/usr/bin/
$ sudo chroot /mnt/debinst qemu-arm-static /bin/bash
Notice how we copy the qemu-arm-static
binary into the rootfs, and then immediately start bash inside a virtualized arm
environment as we chroot (i.e., from now on we’re running everything in a QEMU arm
platform).
You should now be in a chroot shell withing the debootstrap
-generated rootfs. We will then clean up our environment variables (which were inherited from the host – we don’t want them):
$ env -i bash # Clear all env vars except for the indispensable ones
$ export TERM=xterm-color
$ export HOME=/root
$ export LANG=C.UTF-8
Next, we can run the second (and final) stage of debootstrap
. This is only necessary when creating a Debian rootfs for a foreign architecture (hence the --foreign
flag earlier) – the first stage will download and unpack all the .deb
files, while the second one runs all the package configuration scripts (which can only be done on the target architecture). When targeting the same arch as the host the two stages are merged.
Run the following and go grab some coffee, because this might take a seriously long time depending on how beefy your CPU is. :-) Also make sure to use an SD card with decent read/write speeds!
$ /debootstrap/debootstrap --second-stage
If you got this far, congratulations! 🎉 Hopefully the wait wasn’t too long. Now it’s time to do some basic housekeeping and configuration of the rootfs.
Installing a terminal editor
$ apt install ncurses-term
$ apt install vim nano # choose your favorite editor
Setting up /etc/fstab
Here we will configure the automounting of partitions. The SD card for the i.MX53 should be in /dev/mmcblk0
:
/dev/mmcblk0p2 / auto errors=remount-ro 0 1
/dev/mmcblk0p1 /boot auto ro,nosuid,nodev 0 1
Adjusting the timezone
$ dpkg-reconfigure tzdata
Network configuration
If we want ethernet to work “out of the box”, we need to configure the eth0
interface to use DHCP:
$ nano /etc/network/interfaces
# interfaces(5) file used by ifup(8) and ifdown(8)
# Include files from /etc/network/interfaces.d:
source-directory /etc/network/interfaces.d
allow-hotplug eth0
iface eth0 inet dhcp
And don’t forget to set the hostname (you can set this to anything you’d like):
$ echo imx53 > /etc/hostname
Also install ssh
for later:
$ apt install ssh
Console configuration
This will avoid headaches later on:
$ apt install console-setup
Setting up accounts
Let’s set up the password for the root account, and create a privileged user called lkcamp
:
$ passwd
$ useradd -m -G users,audio,adm,sudo lkcamp
$ passwd lkcamp
Installing the kernel and configuring u-boot
Important: make sure to follow these steps carefully or the board won’t boot into Linux. :-)
Install the following packages:
$ apt install linux-image-armmp u-boot-imx init
The linux-image-armmp
is of particular importance to us and will, among other things, place the kernel images in /boot
and run a script to generate an initramfs
, which will leave you with something like this:
$ ls -lah /boot
total 26M
drwxr-xr-x. 3 root root 4.0K May 15 23:55 .
drwxr-xr-x. 18 root root 1.0K May 15 23:52 ..
-rw-r--r--. 1 root root 3.0M Jun 30 2022 System.map-4.19.0-21-armmp
-rw-r--r--. 1 root root 205K Jun 30 2022 config-4.19.0-21-armmp
-rw-r--r--. 1 root root 19M May 15 23:55 initrd.img-4.19.0-21-armmp
drwx------. 2 root root 16K May 15 23:31 lost+found
-rw-r--r--. 1 root root 4.0M Jun 30 2022 vmlinuz-4.19.0-21-armmp
Now we have to configure flash-kernel
, which is responsible for setting up u-boot to load the kernel we just generated. Start by installing it:
$ apt install flash-kernel
We have to specify the string that defines our machine:
$ echo "Freescale i.MX53 Quick Start Board" > /etc/flash-kernel/machine
Now, all the supported flash-kernel
targets are defined in /usr/share/flash-kernel/db/all.db
. You might notice that there is already an entry for the Freescale i.MX53 Quick Start Board
, but it is incomplete (for some reason) and we need to manually patch some things. First of all, find the entry for the board and change it to this:
Machine: Freescale i.MX53 Quick Start Board
Machine: Freescale MX53 LOCO Board
Kernel-Flavors: armmp mx5
DTB-Id: imx53-qsb.dtb
Boot-DTB-Path: /boot/board.dtb
U-Boot-Kernel-Address: 0x70008000
U-Boot-Initrd-Address: 0x72000000
Boot-Kernel-Path: /boot/uImage
Boot-Initrd-Path: /boot/uInitrd
Required-Packages: u-boot-tools
Bootloader-Sets-Incorrect-Root: no
U-Boot-Script-Name: bootscr.mx5-custom
Boot-Script-Path: /boot/boot.scr
We will need to write the custom script specified in U-Boot-Script-Name
. In order to do that, we will start from a copy of the provided generic u-boot script:
$ cp -pv /etc/flash-kernel/bootscript/bootscr.uboot-generic /etc/flash-kernel/bootscript/bootscr.mx5-custom
Then we will edit /etc/flash-kernel/bootscript/bootscr.mx5-custom
and add the following environment variables to the beginning of the script:
setenv distro_bootpart ${mmcpart}
setenv boot_targets mmc
setenv fdtfile ${fdt_file}
setenv bootpart ${mmcpart}
setenv devnum ${mmcdev}
setenv console ttymxc0
setenv devtype mmc
setenv fdt_addr_r ${fdt_addr}
setenv ramdisk_addr_r ${loadaddr}
setenv kernel_addr_r 0x70008000
setenv prefix /
Finally, we need to set a kernel command so that Linux can mount our rootfs during boot. Add the following to /etc/default/flash-kernel
:
LINUX_KERNEL_CMDLINE="root=/dev/mmcblk0p2 ro rootfstype=ext4 rootwait fixrtc"
Notice how we told it that our root partition is on /dev/mmcblk0p2
and that it is an ext4
filesystem. :-)
That’s it! Now we only need to run flash-kernel
:
$ flash-kernel
After it does its thing, you should have something like the following in your /boot
folder:
$ ls -lah /boot
total 72M
drwxr-xr-x. 4 root root 4.0K May 16 00:29 .
drwxr-xr-x. 18 root root 1.0K May 16 00:09 ..
-rw-r--r--. 1 root root 3.0M Jun 30 2022 System.map-4.19.0-21-armmp
-rw-r--r--. 1 root root 21K May 16 00:29 board.dtb
-rw-r--r--. 1 root root 3.2K May 16 00:29 boot.scr
-rw-r--r--. 1 root root 205K Jun 30 2022 config-4.19.0-21-armmp
lrwxrwxrwx. 1 root root 36 May 16 00:29 dtb -> dtbs/4.19.0-21-armmp/./imx53-qsb.dtb
lrwxrwxrwx. 1 root root 36 May 16 00:29 dtb-4.19.0-21-armmp -> dtbs/4.19.0-21-armmp/./imx53-qsb.dtb
lrwxrwxrwx. 1 root root 36 May 16 00:08 dtb.bak -> dtbs/4.19.0-21-armmp/./imx53-qsb.dtb
drwxr-xr-x. 3 root root 4.0K May 16 00:08 dtbs
-rw-r--r--. 1 root root 19M May 15 23:55 initrd.img-4.19.0-21-armmp
drwx------. 2 root root 16K May 15 23:31 lost+found
-rw-r--r--. 1 root root 4.0M May 16 00:29 uImage
-rw-r--r--. 1 root root 4.1M May 16 00:08 uImage.bak
-rw-r--r--. 1 root root 19M May 16 00:29 uInitrd
-rw-r--r--. 1 root root 19M May 16 00:09 uInitrd.bak
-rw-r--r--. 1 root root 4.0M Jun 30 2022 vmlinuz-4.19.0-21-armmp
Now cross your fingers, insert the SD card on the board and press that reset button. If everything goes well, you should see Linux booting. Congrats! 🎉
Next steps
- Figure out how to boot Debian 12 on this thing with the 6.1 kernel
- Investigate U-Boot in more depth; maybe generate a rootfs with Buildroot, compile a custom kernel + initramfs and try to boot it by hand from the U-Boot console?