Preparations
Terminology: uploading in this article goes from your development host (PC, laptop whatever) to the target system/board. Some people talk about "downloading to the target" and such silly stuff, I find that totally confusing especially since the terminal (minicom) will have all its terminology reversed, as it is equipped for downloading and uploading to other servers. The target system can be imagined as some server if it helps you. We will upload to it. Enough said, live with it.
Create a directory for your aarch64 work if you wanna clone my setup:
mkdir aarch64
Getting a Cross Compiler for AArch64
For compiling the U-Boot, kernel and root filesystem you can just use the latest Linaro AArch64 GCC toolchain I'm using linaro-toolchain-binaries 4.9 2014.11 (Aarch64 little-endian) for Linux as of writing.Serial Terminal
Install minicom. In Fedora it's simply dnf -y install minicom and you're done with it.
Setup minicom, I just use this terminal program out of habit:
- As root: minicom -s
- In the Serial port setup, select port (/dev/ttyS0 for your first built-in port, /dev/ttyUSB0 for a USB-to-serial dongle) menu set up 115200 baud, 8 data bits, NO parity, 1 stop bit, NONE control flow, then select hardware flow control
- The Juno has two serial ports, I noticed the device sometimes delivers with a USB-to-serial dongle with two ports and then the primary can be ttyUSB1 or whatever, try around.
- In the Modem and dialing menu delete "init string", "reset string" and "hang up string", this is no modem so why would we care, it only disturbs our use of the serial port
- Save as dfl to save this as default
U-boot
Compiling U-Boot
- Clone a u-boot from the upstream U-Boot git
(all changes needed to make U-Boot work on the Juno are now upstream on the master branch):
cd /home/user/aarch64 git clone git://git.denx.de/u-boot.git cd u-boot
- Configure and build the shebang for Juno, use my juno-uboot.mak makefile (download and save it in the u-boot dir) to build it like this: make -f juno-uboot.mak build if you're not doing this then you can just see what my makefile does and replicate the setup with a script or manually or whatever suit you, this is just what I prefer to do. Makefiles are nice. Bonus: if you like to use the FVP fastmodel, there is also a fvp-uboot.mak
- Make sure that u-boot-juno.bin appears in your output directory (in my makefile that is /home/user/aarch64)
Bonus: my patch to get low-level debug prints akin to Linux' earlyprints helped me debug and get Juno U-Boot in shape.
Precompiled U-Boot
To skip all U-boot business just download my pre-compiled U-Boot: and use it. It's usually pretty up-to-date, else push me about it. These are compiled to be started from SDRAM memory at 0xe0000000
- u-boot-juno.bin (2015-04-14)
Building an fip.bin with U-Boot in it
First: make sure you can rebuild ARM Trusted Firmware as described in the ARM Trusted Firmware user guide. This is not optional if you want to do U-Boot development, you have to have this setup to create flash images that boot on the Juno. I usually just clone the ARM open firmware git into my /home/user/aarch64 working directory and work from there.
What you want to do is to create bl1.bin and fip.bin files where the latter contains a U-Boot image rather than (U)EFI as is common. Do this by specifying the u-boot-juno.bin file as BL33 (boot level 3, step 3) executable.
My build-tf.mak makefile usually does this when used inside the arm trusted firmware tree. If it doesn't work for you, hack the build until it works.
As a bonus, the Juno contains a power management firmware, SCP. This needs to be kept in sync with the ARM Trusted Firmware, or they will refuse to boot. Thes SCP firmwares are found in Ryan Harkins GIT repository.
Precompiled BL1 and FIP
These are sporadically updated bl1 and fip images that can be used as reference, or if you "just wanna run U-boot". If flashed onto the Juno as described below they should work.
- bl1-juno.bin (2015-09-04)
- fip-juno.bin (2015-09-04)
Flashing U-Boot to the Juno board
- Connect a USB slave cable to the USB 1.1 slave socket on the back side of the Juno system, attach it to your development host.
- Start minicom and boot target into boot monitor, usually by pressing the little white reset button on the back of the Juno board
- A command prompt to the boot CPU thing should come up like this:
Cmd> - At the prompt, type usb_on and hit enter.
- This should make USB mass storage device named JUNO come up, and that is how we're gonna flash our images.
- On a modern system you can just copy over all the
necessary files to the target system with a script like this
(I have this script in my /home/user/aarch64 directory):
#!/bin/bash JUNODIR=/run/media/${USER}/JUNO if [ -d ${JUNODIR}/SOFTWARE ] ; then cp bl1-juno.bin ${JUNODIR}/SOFTWARE/bl1.bin cp fip-juno.bin ${JUNODIR}/SOFTWARE/fip.bin cp Image ${JUNODIR}/SOFTWARE/Image cp juno.dtb ${JUNODIR}/SOFTWARE/juno.dtb umount ${JUNODIR} else echo "No JUNO USB mass storage drive mounted" fi
As you can see bl1.bin and fip.bin are necessary to copy over. As described earlier, U-Boot is embedded into fip.bin
As Image is pretty big, this can of course be omitted if you're not rebuilding your kernel. It will take some time to flash also.
- When the files are copied over to the Juno, type:
cmd> reboot
now the different binaries will be flashed from the interrim USB mass storage store and into the NOR flash where the ROM will load them and boot them.
Kernel
A stock Linux kernel v3.19-rc6 or later should boot just fine on the Juno board.
When I build kernels I use this aarch64.mak makefile, like this: make -f aarch64.mak config && make -f aarch64.mak build - it is mainly a way to automate things. It may try (and may fail) to build an experimental U-Boot type uImage as well but disregard that if it doesn't work.
You need an external root filesystem or my homebrew initramfs root filesystem to attach to the kernel when building it if you wanna get to prompt. See below.
Root Filesystem
By default, the kernel is built without a root file system. It is assumed on boot that the USB stick on the flip side of the Juno board will contain a root filesystem. U-Boot will instruct the kernel to mount and boot using this root filesystem by passing the command line switch root=/dev/sda1 rw rootwait. In later U-Boots this may be set to /dev/sda2 as that is custom with many distributions that assume the machine has no flash, so they put the kernel and device tree (or similar) on the first partition.
If you rather prefer to bake the root filesystem into the kernel using the initramfs mechanism (which means the root filesystem is attached at the end of the kernel) my Aarch64 initramfs rootfs image is downloadable from the link. This should be put in the apropriate place to be attached to the kernel image, I just put it in my /home/user/aarch64 directory.
Notice that when you use an initramfs, the kernel will become quite big, around 14MiB, which means the the resulting raw Image will not fit in the internal flash of the Juno, so you probably only want to use this method if you're booting over TFTP.
If you're interested, here is the script I actually use to generate that root filesystem. It's a bit tricky to use and require some extra files.
It is possible to put the Busybox-based initramfs on a USB stick if you prefer, boot the kernel and mount root from it. Then do like this:
- Prepare a USB stick on your computer (assuming it
appears as /dev/sdc):
umount /run/media/[username]/[path to USB stick mount] dd if=/dev/zero of=/dev/sdc bs=1M count=8 fdisk /dev/sdc [n p 1 ENTER ENTER w] mkfs.ext4 /dev/sdc1 mkdir /mnt/rootfs mount /dev/sdc1 /mnt/rootfs cd /tmp wget http://dflund.se/~triad/krad/junoboard/rootfs-aarch64.cpio cd /mnt/rootfs cpio -d -i -F /tmp/rootfs-aarch64.cpio cd umount /mnt/rootfs
- Boot the kernel with a suitable command line, so something like this:
setenv bootargs console=ttyAMA0,115200n8 root=/dev/sda1 rw rootwait rootfstype=ext4 ; set serverip 192.168.1.1 ; set ipaddr 192.168.1.2 ; tftpboot 0x80000000 Image ; tftpboot 0x83000000 juno.dtb ; booti 0x80000000 - 0x83000000
Creating an ArchLinux root filesystem
I use this simple distribution to quickly get some prebuilt software to test. There is a sparse support page over at ARM ArchLinux. I prepare it on a USB stick like this:
- Prepare a USB stick on your computer (assuming it
appears as /dev/sdc):
umount /run/media/[username]/[path to USB stick mount] dd if=/dev/zero of=/dev/sdc bs=1M count=8 fdisk /dev/sdc [n p 1 ENTER ENTER w] mkfs.ext4 /dev/sdc1 mkdir /mnt/rootfs mount /dev/sdc1 /mnt/rootfs cd /tmp wget http://archlinuxarm.org/os/ArchLinuxARM-aarch64-generic-latest.tar.gz cd /mnt/rootfs tar xvfz /tmp/ArchLinuxARM-aarch64-generic-latest.tar.gz cd umount /mnt/rootfs
- Boot the kernel with a suitable command line, usually it is necessary
to tag on init=/sbin/init so something like this:
setenv bootargs console=ttyAMA0,115200n8 root=/dev/sda1 rw rootwait rootfstype=ext4 init=/sbin/init ; set serverip 192.168.1.1 ; set ipaddr 192.168.1.2 ; tftpboot 0x80000000 Image ; tftpboot 0x83000000 juno.dtb ; booti 0x80000000 - 0x83000000
- Log in with root/root, update the system with pacman -Syu
Prebuilt kernel Image
The version number indicates the version of the Linux kernel used on each build.
- Image-v4.4 - distro kernel, lots of stuff enabled so that it can be used with ArchLinux or similar, it does NOT fit in the NOR flash partition, ~10MB
- Image-v4.2 - just a kernel, small enough to fit in the NOR flash partition
- Image-v4.1-rc3 - just a kernel, small enough to fit in the NOR flash partition
- Image-v4.0 - just a kernel, small enough to fit in the NOR flash partition
- Image-v4.0-initramfs - complete with an initramfs that boots to prompt, this is ~15MiB so can not boot from flash, only from TFTP
- Image-3.20-HEAD (historical artifact)
Prebuilt device tree
This is basically just the latest device tree compiled from the upstream Linux kernel arch/arm64/boot/dts/arm/juno.dts.
Uploading and booting a Linux kernel
Default boot from NOR Flash
This is the default boot procedure and what will happen if you do nothing when U-Boot comes up. Juno U-Boot is pre-configured to load the kernel and DTB files from NOR flash on the Juno board and put them into DRAM memory.
The layout of the NOR flash is determined from the AFS image format, and images are loaded by name. The uncompressed kernel image named Image will be loaded to address 0x80000000 in DRAM, and the device tree image named juno will be loaded to address 0x83000000 in DRAM and it will then be booted using the command booti 0x80000000 - 0x83000000.
Using serial port
To upload a kernel using the now running U-boot using ymodem on the serial port only:
- Interrupt the default boot process by hitting ENTER when the U-Boot boot delay is seen
- Type loady 0x80000000 at the U-Boot prompt to start the ymodem protocol parser in U-Boot and upload a file to 0x80000000
- In minicom type Control-AS to access the upload feature
- Select ymodem
- Select your compiled Image file with arrow keys and hit space
- Hit Enter on Okay
- Wait for a long time while the kernel uploads to target...
- Hit Enter to return to the U-Boot prompt
- Type loady 0x83000000 at the U-Boot prompt to start the ymodem protocol parser and upload a second file to 0x83000000
- In minicom type Control-AS to access the upload feature
- Select your compiled juno.dtb file with arrow keys and hit space
- Hit Enter on Okay
- Wait for a short time while the kernel uploads the little device tree blob to target...
- Hit Enter to return to the U-Boot prompt
- Type booti 0x80000000 - 0x83000000 (boot from memory) as you can see giving the Image and device tree blob as arguments and hope for the best...
Using TFTP over Ethernet
- Set up a TFTP server
- Put the Image and juno.dtb file in the TFTP server base directory
- Get an IP number on you local network for the system
- Interrupt the default boot process by hitting ENTER when the U-Boot boot delay is seen
- Issue the following command line, substituting the right IP numbers for your local network server and system IP:
set serverip 192.168.1.32 ; set ipaddr 192.168.1.35 ; tftpboot 0x80000000 Image ; tftpboot 0x83000000 juno.dtb ; booti 0x80000000 - 0x83000000