How to get out of u-boot shell and boot the aarch64 kernel on Raspberry 3 / 4

Kim Il
5 min readApr 6, 2021

I somehow got into the u-boot shell, but the kernel is not booting and stuck in a PXE loop. To get into the u-boot shell do a hard reset (the old out/in game) and press the anykey like a maniac.

I did follow this guide https://archlinuxarm.org/platforms/armv8/broadcom/raspberry-pi-3 , but not to the last comma, because i’m smart and know what i’m doing. Or so …

But instead of figuring out what i did wrong, i will figure out how to get Captain AArch64 out of his U-Boat.

First wth can i do in the u-boot shell:

Usefull commands:
help - scrolls super fast, can only read half the stuff
bdinfo - Board info such as memory addresses and sizes, clock frequencies, MAC address, etc
mtdparts - list partition table
coninfo - print console devices and information
printenv - the most important & useful of them all
setenv - needed to set variables
version - U-Boot 2021.1
What i did in the first iterationmmc dev 0 - set the mmc interface to sdcard
ls mmc 0:1 / - show contents of boot partition
ls mmc 0:1 /dtbs - device tree files
Check for correct device tree file:printenv fdtfile - is it correct for your model? if not
setenv fdtfile broadwell/bcm2837-rpi-3-b.dtb
printenv fdt_addr_r - is it set? if not
setenv fdt_addr_r 0x02E00000
Load the flat device tree file:
load mmc 0:1 ${fdt_addr_r} /dtbs/${fdtfile}

The kernel is compressed in /Image.gz for me:
(check 'help booti' for how to boot compressed kernels)setenv kernel_comp_addr_r 0x0a000000load mmc 0:1 ${kernel_addr_r} /Image.gz
12011759 bytes read in 514 ms (22.3 MiB/s)
setenv kernel_comp_size 12011759saveenv(Back to writing this)

Please note: If you disconnect your usb keyboard while in the u-boot shell, you have to reboot. It will NOT pickup your USB keyboard again. I have a RPi 3b 1.2, so this could be different on a RPi 4.

I have a kvm setup with only one USB keyboard/mouse for several machines. So to write this medium story i have to switch the keyboard from the raspberry to my main box and therefor loose control of the RPi 3b 1.2 i try to boot.

Ok, now you know why, here is my second try:

Do everything from the first iteration again, then:ramdisk_addr_r should be 0x02f00000load mmc 0:1 ${ramdisk_addr_r} /initramfs-linux.img
> 7046078 bytes read
setenv ramdisk_size 7046078
load mmc 0:1 ${fdt_addr_r} /dtbs/${fdtfile}load mmc 0:1 ${kernel_addr_r} /Image.gz
> 12011759 bytes read in 514 ms (22.3 MiB/s)
setenv kernel_comp_size 12011759
setenv kernel_comp_addr_r 0x0a000000
setenv bootargs earlyprintk console=ttyAMA0 console=tty0 root=/dev/mmcblk0p2 rootwaitbooti ${kernel_addr_r} ${ramdisk_addr_r}:${ramdisk_size} ${fdt_addr_r}
Heureka! Boot running into login tty
Login root/root and do the arch things

Maybe you are now thinking: nice for you but i WANT to know how to FIX it, i am not doing all this on every boot!

OK, here you go: Dead ends and enlightenments

printenv boot_a_script
> boot_a_script= loading /boot.scr and executing it
load mmc 0:1 ${scriptaddr} /boot.scr
source ${scriptaddr}
> ** Bad device...
setenv devtype mmc
setenv devnum 0
source ${scriptaddr}
> Failed to load /Image

The u-boot script (boot.scr) tries to load an uncompressed kernel, but on the card there is only Image.gz! Fine, swap out the card, uncompress Image.gz to Image and retry, because i’m brave and don’t care about the Image being 33MB vs 12MB for the .gz

load mmc 0:1 ${kernel_addr_r} /Image
Ooops - guru meditation, it seems i did overwrite something in memory, the shell is dead

Now knowing that loading an uncompressed kernel will not work without doing memory offset calculations and stuff, i opt for the compressed kernel.

Links to u-boot user manual & memory allocation:
https://www.denx.de/wiki/DULG/Manual
https://stackoverflow.com/tags/u-boot/hot?filter=year
https://www.raspberrypi.org/forums/viewtopic.php?t=244785

For booti to uncompress an gz kernel only two vars are needed:

setenv kernel_comp_addr_r 0x0a000000 // space for decompress far out
load mmc 0:1 ${kernel_addr_r} /Image.gz
setenv kernel_comp_size ${filesize} // size of the last load

This two comp vars have to be added to boot.txt, and then the boot.scr must be regenerated with mkscr, which is on the card.

Note: The bootargs use root=PARTUUID=${uuid} so your root partition MUST have a PARTUUID (not to confuse with UUID!), or you can also use root=/dev/mmcblk0p2, but this will cause problem on RPi 4. So — if we do it, we do it correct!

Check if there are PARTUUIDs:
lsblk -o NAME,SIZE,MOUNTPOINT,UUID,PARTUUID

How to set PARTUUID
https://www.raspberrypi.org/forums/viewtopic.php?t=191775

On your linux dev box mount the cards first partition into ./boot & cd boot. The boot.txt should look like this:

# After modifying, run ./mkscr
# 2021.04.06 fixed kernel loading
# Set root partition to the second partition of boot device
part uuid ${devtype} ${devnum}:2 uuid
# Tell Linux that it is booting on a Raspberry Pi2/3
setenv machid 0x00000c42

setenv bootargs console=ttyS1,115200 console=tty1 root=PARTUUID=${uuid} rw rootwait smsc95xx.macaddr="${usbethaddr}"

# Load Image.gz
if load ${devtype} ${devnum}:${bootpart} ${kernel_addr_r} /Image.gz; then
# added 2021.04.06 by Kim
# set decompression stage
setenv kernel_comp_size ${filesize}
setenv kernel_comp_addr_r 0x0a000000

# load the flat device tree file
if load ${devtype} ${devnum}:${bootpart} ${fdt_addr_r} /dtbs/${fdtfile}; then
# Load the ramdisk
if load ${devtype} ${devnum}:${bootpart} ${ramdisk_addr_r} /initramfs-linux.img; then
# Do your prayers
booti ${kernel_addr_r} ${ramdisk_addr_r}:${filesize} ${fdt_addr_r};
else
booti ${kernel_addr_r} - ${fdt_addr_r};
fi;
fi;
fi

Then regenerate it by running sudo ./mkscr in the boot folder

❯ sudo ./mkscr 
Image Name: U-Boot boot script
Created: Tue Apr 6 09:55:54 2021
Image Type: ARM Linux Script (uncompressed)
Data Size: 852 Bytes = 0.83 KiB = 0.00 MiB
Load Address: 00000000
Entry Point: 00000000
Contents:
Image 0: 844 Bytes = 0.82 KiB = 0.00 MiB
❯ cat boot.scr
'Vs�j�`lj�@t�(U-Boot boot script�# After modifying, run ./mkscr
# 2021.04.06 fixed kernel loading

# Set root partition to the second partition of boot device
part uuid ${devtype} ${devnum}:2 uuid
.....

Looks good, see the binary in front?

This should do it, now your RPi 3 boots aarch64

For completeness this is my config.txt:

# Enabled by default Arch ARM64 
enable_uart=1

#CEA
hdmi_group=1
#1080p 60 Hz
hdmi_mode=16

# run in 64bit mode
arm_control=0x200

dtparam=audio=on
gpu_mem=128


# CONFIG_DRM_VC4: This driver requires that "avoid_warnings=2" be present in
# the config.txt for the firmware, to keep it from smashing our display setup.
avoid_warnings=2

# Uncomment if you get no picture on HDMI for a default "safe" mode
#hdmi_safe=1

# Uncomment this if your display has a black border of unused pixels visible
# and your display can output without overscan.
#disable_overscan=1

# Uncomment the following to adjust overscan. Use positive numbers if console
# goes off screen, and negative if there is too much border.
#overscan_left=20
#overscan_right=20
#overscan_top=20
#overscan_bottom=20

# Uncomment to force a console size. By default it will be display's size minus
# overscan.
#framebuffer_width=1280
#framebuffer_height=720

# Uncomment if an HDMI display is not detected and composite is being output.
hdmi_force_hotplug=1

# Uncomment to force a specific HDMI mode (this will force VGA).
#hdmi_group=1
#hdmi_mode=1

# Uncomment to force an HDMI mode rather than DVI. This can make audio work in
# DMT (computer monitor) modes.
#hdmi_drive=2

# Uncomment to increase signal to HDMI, if you have interference, blanking, or
# no display.
#config_hdmi_boost=4

# Uncomment for composite PAL
#sdtv_mode=2

# Uncomment to overclock the ARM. 700 MHz is the default.
#arm_freq=800

# For more options, see http://elinux.org/RPi_config.txt

--

--