FreeBSD, Electronics and more
There is a lot of ARM boards, RaspberryPi, BeagleBone, CubieBoard, BananaPi etc ...
Most of them support Linux officially and the vendors often provides images of Linux tailored for their boards.
FreeBSD support the more popular ones, there is official images of the 10.2 release for :
BeagleBone (And BeagleBone Black)
HummingBoard
GUMSTIX
PandaBoard
RaspberryPi Model B
WandBoard
And the 11.0 current adds the following boards :
BananaPi
CubieBoard
CubieBoard 2
RaspberryPi 2
This series of articles will document my steps of bringing FreeBSD on the Olimex A20-SOM-EVB. I hope that I will not make a lot of mistakes and that it will help people to add FreeBSD support on other boards.
The first step to add support for a new board is to run a custom Uboot on it.
Das U-Boot is an universal boot loaded use of many platform and many architecture.
Most of the boards uses U-Boot as their bootloader but generaly you can't boot FreeBSD the "official" way.
The "official" way to boot FreeBSD on an ARM platform is to use ubldr.
On i386 and amd64 the final boot stage is handled by loader(8), it will setup some variables (currdev and loaddev for example), process /boot/loader.rc etc ... and finally it will load and start the kernel.
ubldr is simply a version of loader(8) that uses the U-Boot API.
This is where the problems begin, most (if not all) U-Boot provided by the boards vendors aren't configured to include the API, that's why have to compile U-Boot ourselves.
Fortunatly there is a easy way to create a U-Boot for a boards, it is to use the existing ports. The FreeBSD developpers have chosen to create a u-boot port for each supported platform. And because ports are packaged, it means that if you want the FreeBSD tailored u-boot for the BeagleBone you just have to pkg install u-boot-beaglebone
and it will install the program into /usr/local/share/u-boot/u-boot-beaglebone/.
The A20-SOM use an Allwinner processor and there is already some boards in -CURRENT with this processor, the CubieBoard (A10) and the CubieBoard2 (A20). The sysutils/u-boot-cubieboard
port is a modular one. Some variables (PKGNAMESUFFIX, COMMENT, MODEL and CONF_TARGET) can be overwritten and this is what the sysutils/u-boot-cubieboard2
port does. So to create a port for the Olimex A20-SOM all I need is a Makefile that uses the cubieboard one and overide some variables :
PKGNAMESUFFIX= -olinuxino-lime2 COMMENT= Cross-build U-Boot loader for Olimex A20 Olinuxino Lime 2 LICENSE= GPLv2 # Local overrides MASTERDIR= ${.CURDIR}/../u-boot-cubieboard DESCR= ${.CURDIR}/pkg-descr MODEL= sun7i-a20-olinuxino-lime2 CONF_TARGET= A20-OLinuXino-Lime2_defconfig .include "${MASTERDIR}/Makefile"
The MODEL variable contain the file of the dtb that will be used (We will talk about DTS/DTB in part 2)
The CONF_TARGET is the U-Boot config file for the platform.
If you're wondering why I use the olinuxino-lime2 config and dtb this is because the official linux images from Olimex for the A20-SOM uses them. The two boards are almost the same so Olimex only made one dts for them.
After make install clean
you will have those files in /usr/local/share/u-boot/u-boot-olinuxino-lime2
:
README sunxi-spl.bin u-boot-sunxi-with-spl.bin u-boot.img
README is a copy of pkg-descr. This leave us the SPL file, the U-Boot one and both of them combined in one file.
So what's SPL ?
SPL is the first file loaded and executed by the processor. All the different SoC uses different file name or location. For example the SoC in the BeagleBone (TI AM335x) load the file MLO from the first MSDOS partition of the SD card. But it can also load it from a SPI Flash or via the uart using the xmodem protocol. Every SoC implement a different boot procedure.
The A20 SoC will try to load the SPL file from the SD Card first and then from other media (See the A20 User Manual page 96). It doesn't need a FAT partition, it will simply loads the data from the 16th sector. The SPL file will then load the u-boot program from the 64th sector and execute it.
The u-boot-sunxi-with-spl.bin
file contain both SPL and UBOOT data with the necessary padding between them. This means that we can simple dd this file on the sdcard:
# Assuming that your SD card is da0 sudo dd if=/usr/local/share/u-boot/u-boot-olinuxino-lime2/u-boot-sunxi-with-spl.bin of=/dev/da0 bs=1k seek=8
Now connect to your board using the uart to verify that it can boot of the SD card with tip ucom1 -115200
. To use the tip
program without using the root account, you must be the the dialer group. ucom1 is defined in /etc/remote
and resolv to /dev/cuaU0
which is the first usb<->serial adapter on the system. -115200
tells tip to use the 115200 baudrate (the default is 9600).
If you did everything right you will have something like this :
U-Boot SPL 2015.04 (Nov 27 2015 - 15:26:05) DRAM: 1024 MiB CPU: 912000000Hz, AXI/AHB/APB: 3/2/2 U-Boot 2015.04 (Nov 27 2015 - 15:26:05) Allwinner Technology CPU: Allwinner A20 (SUN7I) I2C: ready DRAM: 1 GiB WARNING: Caches not enabled MMC: SUNXI SD/MMC: 0 ** No partition table - mmc 0 ** Using default environment In: serial Out: serial Err: serial SCSI: SUNXI SCSI INIT SATA link 0 timeout. AHCI 0001.0100 32 slots 1 ports 3 Gbps 0x1 impl SATA mode flags: ncq stag pm led clo only pmp pio slum part ccc apst Net: dwmac.1c50000 Hit any key to stop autoboot: 0 Booting from: mmc 0 ubldr ** Unrecognized filesystem type **
Because we used the patched U-Boot from ports, it is already configured to load the file ubldr from the first FAT partition of the SD card. Let examine the uboot environment variables :
sunxi# env print Fatboot=env exists loaderdev || env set loaderdev ${fatdev}; env exists UserFatboot && run UserFatboot; echo Booting from: ${fatdev} ${bootfile}; fatload ${fatdev} ${kernel_addr_r} ${bootfile} && bootelf; Netboot=env exists loaderdev || env set loaderdev net; env exists UserNetboot && run UserNetboot; dhcp ${kernel_addr_r} ${bootfile} && bootelf; SetupFatdev=env exists fatdev || env set fatdev 'mmc 0'; baudrate=115200 bootcmd=run Fatboot bootdelay=2 bootfile=ubldr bootm_size=0xf000000 console=ttyS0,115200 ethact=dwmac.1c50000 ethaddr=02:17:08:40:c1:8c fatdev=mmc 0 fdt_addr_r=0x43000000 fdtfile=olinuxino-lime2.dtb kernel_addr_r=0x42000000 loaderdev=mmc 0 preboot=usb start; env exists bootfile || env set bootfile ubldr; env exists SetupFatdev && run SetupFatdev; env exists UserPreboot && run UserPreboot; pxefile_addr_r=0x43200000 ramdisk_addr_r=0x43300000 scriptaddr=0x43100000 stderr=serial,vga stdin=serial,usbkbd stdout=serial,vga Environment size: 995/131068 bytes
bootcmd is set to run the commands in the Fatboot variable. Those commands will load bootfile (ubldr) from fatdev (mmc 0) to address kernel_addr_r (0x42000000) and run the bootelf command.
Let's compile ubldr.
We have to run a buildworld before, I'm sure that it is somewhat possible without it but we will need it anyway after so let's do that now.
# Setup the environ for building freebsd export TARGET=arm export TARGET_ARCH=armv6 export SRCROOT=/path/to/freebsd/source/tree export MAKEOBJDIRPREFIX=/path/to/obj/dir export MAKESYSPATH=$SRCROOT/share/mk buildenv=`make -C $SRCROOT buildenvvars` # Build World make -j `sysctl -n hw.ncpu` -C $SRCROOT buildworld # Build ubldr eval $buildenv make -C $SRCROOT/sys/boot -m $MAKESYSPATH obj eval $buildenv make -C $SRCROOT/sys/boot -m $MAKESYSPATH clean eval $buildenv make -C $SRCROOT/sys/boot -m $MAKESYSPATH depend eval $buildenv make -C $SRCROOT/sys/boot -m $MAKESYSPATH UBLDR_LOADADDR=0x42000000 all
Now let's create the fat partition on the SD card:
# Create a MBR scheme sudo gpart create -s mbr da0 # Create a FAT12 partition, start the partition at 1M so it doesn't overide the SPL+UBOOT sudo gpart add -t \!12 -b 1M -s 1m da0 sudo newfs_msdos -F12 /dev/da0s1 sudo mount_msdosfs /dev/da0s1 /mnt sudo cp ${MAKEOBJDIRPREFIX}/${TARGET}.${TARGET_ARCH}/${SRCROOT}/sys/boot/arm/uboot/ubldr /mnt sudo umount /mnt
And test the SD card on the board :
U-Boot SPL 2015.04 (Nov 27 2015 - 15:26:05) DRAM: 1024 MiB CPU: 912000000Hz, AXI/AHB/APB: 3/2/2 U-Boot 2015.04 (Nov 27 2015 - 15:26:05) Allwinner Technology CPU: Allwinner A20 (SUN7I) I2C: ready DRAM: 1 GiB WARNING: Caches not enabled MMC: SUNXI SD/MMC: 0 reading u-boot.env ** Unable to read "u-boot.env" from mmc0:1 ** Using default environment In: serial Out: serial Err: serial SCSI: SUNXI SCSI INIT SATA link 0 timeout. AHCI 0001.0100 32 slots 1 ports 3 Gbps 0x1 impl SATA mode flags: ncq stag pm led clo only pmp pio slum part ccc apst Net: dwmac.1c50000 Hit any key to stop autoboot: 0 Booting from: mmc 0 ubldr reading ubldr 263152 bytes read in 66 ms (3.8 MiB/s) ## Starting application at 0x42000094 ... Consoles: U-Boot console Compatible U-Boot API signature found @7f235408 FreeBSD/armv6 U-Boot loader, Revision 1.2 (elbarto@harlock.staff.bocal.org, Fri Nov 27 15:52:44 CET 2015) DRAM: 1024MB MMC Device 1 not found MMC Device 2 not found MMC Device 3 not found MMC Device 1 not found Number of U-Boot devices: 3 U-Boot env: loaderdev='mmc 0' Found U-Boot device: disk Checking unit=1 slice=<auto> partition=<auto>... good. Booting from disk1s1: % - can't load 'kernel' Type '?' for a list of commands, 'help' for more detailed help. loader>
ubldr loads fine and now we're ready to load the DTB and the Kernel.
See you soon in Part 2.