Skip to content

FreeBSD and Freescale IMX6

Russell Haley edited this page Aug 5, 2016 · 20 revisions

So you said you have been over the crossbuild and sd card image pages already and things are still fuzzy? Crochet is a great tool that produces standardized images for many supported platforms, but the scripts add a layer of complexity that is a setback when you are first learning to build FreeBSD for arm.

Fine then, here are my build steps. I feel this is original content as I built up this information over years of tears and more tears (ask the guys on the arm email list how many tears they shed trying to help me through this). However, this is largely the same information found on the FreeBSD Wiki.

Crossbuilding for IMX6 Freescale

1. Build everything.

Set up a Projects directory under our home folder.

mkdir -p ~/Projects/hummingboard/src

I have a core i7 and an SSD so I load up the number of concurrent jobs with -j10 or -j20

svn checkout https://svn0.us-west.FreeBSD.org/base/head .../src

OR

svn up .../src

THEN

cd .../src

The buildworld target creates all the compilers and the userland utilities

make TARGET=arm TARGET_ARCH=armv6 -j10 buildworld 

buildkernel creates the kernel and all the loadable modules. The specific kernel for the platform can be customized through the files under src/sys/arm/conf

make -DNO_CLEAN TARGET=arm TARGET_ARCH=armv6 KERNCONF=IMX6 -j10 buildkernel 

2. Format the sd card:

  • 1 - 10 mb at the front of the sd card unpartitioned
  • MBR partition Scheme
  • 10 - 100 mb fat32 slice for ubldr and uEnv.txt u-boot configuration file
  • The rest of the space for a FreeBSD slice

Note: first use gpart to destroy everything that may already exist

sudo mkdir /mnt/fatpart
sudo mkdir /mnt/bsdpart

gpart create -s mbr da4
gpart add -t fat32 -b 1M -s 50M da4
sudo newfs_msdos -F32 /dev/da4s1

gpart add -t freebsd da4
sudo newfs /dev/da4s2

sudo mount /dev/da4s1 /mnt/fatpart
sudo mount /dev/da4s2 /mnt/bsdpart

3. build u-boot from ports:

For the hummingboard, we can use the sysutil/u-boot-cubox-hummingboard port:

cd /usr/ports/sysutils/u-boot-cubox-hummingboard/
sudo make

the output can be found in a folder such as: /usr/ports/sysutils/u-boot-cubox-hummingboard/work/stage/usr/local/share/u-boot/u-boot-cubox-hummingboard

NOTE: After an update to my PC-BSD the version of the arm cross compiler was bumped to 5.3.0 from 4.9.2 and u-boot failed to build. pkg remove arm-none-eabi-gcc pkg install arm-none-eabi-gcc492 solves the problem

##4. Write u-boot to the disk sudo dd if=u-boot of=md0 seek=2

This didn't seem to work: sudo dd if=u-boot.imx of=md0 seek=2 540+0 records in 540+0 records out 276480 bytes transferred in 0.016680 secs (16575537 bytes/sec)

5. Copy ubldr into the msdos partition

TODO

6. Install the Userland

make -DNO_CLEAN TARGET=arm TARGET_ARCH=armv6 DESTDIR=/mnt/bsdpart installworld distribution 

7. Install the kernel

make TARGET=arm TARGET_ARCH=armv6 KERNCONF=IMX6 installkernel DESTDIR=/mnt/bsdpart

Customizing your kernel and build image

Conf files

The main place to customize the kernel is using the kernel configuration files under .../src/sys/arm/conf as noted above.

Configuring what packages are build for a specific project (i.e. shrink your installation) can be done using the SRCCONF variable. See the rather awkwardly documented src.conf(5) man page here:

https://www.freebsd.org/cgi/man.cgi?query=src.conf&apropos=0&sektion=0&manpath=FreeBSD+11-current&arch=default&format=html

The "main" make.conf(5) configuration file is here:

https://www.freebsd.org/cgi/man.cgi?query=make.conf&apropos=0&sektion=0&manpath=FreeBSD+11-current&arch=default&format=html

and the main build page with more information about the make targets and some of the more common variables available is here (but not SRCCONF!):

https://www.freebsd.org/cgi/man.cgi?query=build&apropos=0&sektion=0&manpath=FreeBSD+11-current&arch=default&format=html

Note: Creating a minimalist installation can also be achieved using NANOBSD, which is currently under construction by Warner Losh, but I don't know too much more than this. But here are some references of unknown freshness.

https://bsdrp.net/documentation/technical_docs/nanobsd

https://www.freebsd.org/doc/en/articles/nanobsd/howto.html

Other build tricks :

Writing to memdisk instead of little files to the sd card

Writing the installworld to sd card takes FOREVER. I've tried to get fancy and speed up the installation by creating a memorydisk image first and then copying everything into that.

truncate -s 1024M imx6.img
sudo mdconfig -f imx6.img -u0
gpart create -s mbr md0
gpart add -t fat32 -b 1M -s 50M md0
newfs_msdos -F32 /dev/md0s1
gpart add -t freebsd md0
sudo newfs /dev/md0s2
sudo dd if=u-boot of=md0 seek=2 --> This didn't seem to work
make -DNO_CLEAN TARGET=arm TARGET_ARCH=armv6 DESTDIR=/mnt/memdisk installworld distribution 
make -DNO_CLEAN TARGET=arm TARGET_ARCH=armv6 DESTDIR=/mnt/memdisk installkernel
umount /mnt
mdconfig -d -u0
sysctl kern.geom.debugflags=16
dd if=imx6.img of=/dev/da0 bs=4096k

I have not verified this is correct code.

Booting from the network

The main build reference for all of this is on the FreeBSD wiki. The crossbuild page provides an excellent build tutorial and explains how to boot the kernel from tftp and mount the rootfs using an nfs mount point.

https://wiki.freebsd.org/FreeBSD/arm/crossbuild

Build locations

I typically use a PC-BSD desktop computer as it's easy and I really like using ZFS. Up until recently I would do all my crossbuilding in a FreeBSD jail. The provided good isolation from my main system but had the drawback that copying files in and out of the jail was difficult due to security restrictions, albeit because I didn't have it set up very well.

Since I have started building in my home directory without a jail, I can copy items much faster and generally have the freedom required to mount and unmount things from a single console, but I have now run into a case where an update to my host computer broke my u-boot build. While not an insurmountable problem, it does create a case for using a jail to isolate your build tools from your host system (which you may need updates for!).

Booting From NAND

On the older Digi Imx53 platform a jumper could be set to toggle the boot location from the sd card(s) to an internal nand flash. I had experimented with running u-boot from nand which can in turn could be used to load the kernel file from SD using u-boot variables and commands. Once the kernel was running I could then mount a USB rootfs. I only had this working for a week or so before I broke it again and could never get it running a second time.

However, my projected next attempt was to copy the kernel onto the nand flash using u-boot commands through the command line terminal and then updating u-boot to load the kernel directly from nand. This could technically also be done using ubldr as well. Here are some notes that outlined a script to do this:

echo ====Set Variables====
setenv kernel_file /CCWMX53/kernel
setenv u-boot_file /CCWMX53/u-boot.bin
setenv ramdisk_file /CCWMX53/uRamdisk

setenv u-boot_size 0x800
setenv kernel_size 0x1800
setenv ramdisk_size 0x1800


setenv u-boot_nand_offset 0x400  //original was 40000000 Should this be 0x400?
setenv u-boot_size 0x800


setenv kernel_addr 0x70800000
setenv ramdisk_addr 0x40100000

echo ===== U-Boot settings =====
setenv load_u-boot 'tftp ${loadaddr} ${u-boot_file}'
setenv install_u-boot 'protect off ${u-boot_nand_offset}
+${u-boot_size};era ${u-boot_nand_offset} +${u-boot_size};cp.b
${loadaddr} ${u-boot_nand_offset} ${u-boot_size};saveenv'
setenv update_u-boot run load_u-boot install_u-boot

echo ===== FreeBSD Kernel settings =====
setenv load_kernel 'tftp ${loadaddr} ${kernel_file};'
setenv install_kernel 'era ${kernel_addr} + ${kernel_size};cp.b
${loadaddr} ${kernel_addr} ${kernel_size}'
setenv update_kernel run load_kernel install_kernel

echo ===== Ramdisk settings =====
setenv load_ramdisk 'tftp ${loadaddr} ${ramdisk_file};'
setenv install_ramdisk 'era ${ramdisk_addr} + ${ramdisk_size};cp.b
${loadaddr} ${ramdisk_addr} ${ramdisk_size}'
setenv update_ramdisk run load_ramdisk install_ramdisk

echo ===== Save new definitions =====
saveenv

The important part would be this:

setenv load_kernel 'tftp ${loadaddr} ${kernel_file};' setenv install_kernel 'era ${kernel_addr} + ${kernel_size};cp.b ${loadaddr} ${kernel_addr} ${kernel_size}'

which would load the kernel into memory using tftp, erasing whatever is on the nand blocks we needed using era and then using cp.d to write the kernel to the nand.

None of this was ever attempted and this should be considered pseudo-code not a working prototype. Moreover, I am SURE there is an easier way to do this. In the end, if you could achieve something like this using ubldr instead of loading the kernel directly, you could then still have a standard image on some other medium (including an updatable kernel) and also utilize what would otherwise be an unused nand chip.

Update: From a gentleman named Ron on the mailing list: My Sheevaplug loads the kernel from NAND which mounts the rootfs from USB-stick. And does this for a couple of years already. I used to have a rootfs on nandfs(5) also, but nandfs is not stable enough.

nandtool erase dev=/dev/gnand0s.fbsd-boot
dd if=/tmp/kernel.bin of=/dev/gnand0s.fbsd-boot bs=2k conv=sync