Author: Sam Protsenko <semen.protsenko at linaro dot org>

UEFI Network Booting


Synopsis

This wiki page describes how to accomplish next boot sequence:

1. UEFI is being run under RTSM

2. UEFI obtains IP-address from DHCP-server

3. UEFI obtains GRUB via TFTP from TFTP-server

4. UEFI runs obtained GRUB (GRUB must be EFI image)

5. GRUB obtains config file and shows menu

6. GRUB downloads next files via TFTP (using network services of UEFI):

  • - DTB

    - initrd

    - kernel

7. GRUB starts the kernel


PXE Server Setup

PXE server is your host (PC or laptop etc).

It should provide all services needed for network booting (see http://en.wikipedia.org/wiki/Preboot_Execution_Environment).

TFTP Server

TFTP server provides files transfer over network.

Install TFTP server:

$ sudo aptitude install tftpd-hpa tftp

Create directory where all the files will be located and sub-directories:

$ sudo mkdir -p /srv/tftp/efi/for-grub

Edit "/etc/default/tftpd-hpa" file as follows:

TFTP_USERNAME="tftp"
TFTP_DIRECTORY="/srv/tftp"
TFTP_ADDRESS="0.0.0.0:69"
TFTP_OPTIONS="--secure"

xinetd

There are 2 approaches how to run tftpd daemon:

  1. Let tftpd to be always running (via specifying RUN_DAEMON="yes" in tftpd-hpa config file)
  2. Let super-server handle tftpd starting

"xinetd" is super-server daemon. It listens for incoming requests over a network and launches the appropriate service for that request. In our case it will start tftpd service when it catches TFTP request over the network.

Install it:

$ sudo aptitude install xinetd

Create “/etc/xinetd.d/tftp” file with next content:

service tftp
{
    protocol        = udp
    port            = 69
    socket_type     = dgram
    wait            = yes
    user            = root
    server          = /usr/sbin/in.tftpd
    server_args     = --secure /srv/tftp
    disable         = no
}

Explanation:

disable = no

Enable spawning TFTPD process

server_args = /srv/tftp

Path to TFTP files

server_args = --secure

Use relative (rather than absolute) pathes; see "man tftpd" for details

Once config is modified, restart xinetd:

$ sudo service xinetd restart

DHCP Server

DHCP server offers IP addresses to clients.

Install server:

$ sudo aptitude install isc-dhcp-server

NOTE: if installation wasn't completed due to error -- don't worry, we will fix it later (after bringing network bridge up we will be able to start DHCP server, so we can finish "isc-dhcp-server" package installation using "sudo dpkg --configure" command).

Edit "/etc/default/isc-dhcp-server" file, so it contains line:

INTERFACES="br0"

(because our DHCP server will be offering addresses to network bridge, i.e. to RTSM model).

This action also can be done next way:

$ sudo dpkg-reconfigure isc-dhcp-server

and then specify "br0" interface.

Add these lines to /etc/dhcp/dhcpd.conf:

allow booting;
allow bootp;

subnet 192.168.0.0 netmask 255.255.255.0 {
  range 192.168.0.3 192.168.0.253;
}

host rtsm {
  hardware ethernet 00:02:f7:ef:5c:f5;
  fixed-address 192.168.0.20;
  option host-name "rtsm";
  next-server 192.168.0.1;
  filename "efi/grub.efi";
}

Explanation of fields:

hardware ethernet

MAC address of client (UEFI on RTSM)

fixed address

IP address of client

option host-name

Host name of client (see "man dhcp-options" for details)

next-server

IP address of PXE server (this PC)

filename

bootloader file to be offer via TFTP

Building projects

Obtaining ARM Toolchain

ARMv7 (32-bit)

Linaro toolchain binaries can be obtained from here: https://launchpad.net/linaro-toolchain-binaries/+download

I'm using 2013.08 release. Here is instructions how to setup this version of toolchain.

Obtain binaries:

$ wget https://launchpadlibrarian.net/147740857/gcc-linaro-arm-linux-gnueabihf-4.8-2013.08_linux.tar.xz

Unpack it to /opt:

$ sudo tar xJvf gcc-linaro-arm-linux-gnueabihf-4.8-2013.08_linux.tar.xz -C /opt

Add to your ~/.bashrc:

export PATH=/opt/gcc-linaro-arm-linux-gnueabihf-4.8-2013.08_linux/bin:$PATH
export CROSS_COMPILE=arm-linux-gnueabihf-

Restart your shell.

ARMv8 (64-bit)

Obtain pre-built toolchain:

$ wget http://releases.linaro.org/13.09/components/toolchain/binaries/gcc-linaro-aarch64-linux-gnu-4.8-2013.09-01_linux.tar.bz2

Unpack it to /opt:

$ tar xjvf gcc-linaro-aarch64-linux-gnu-4.8-2013.09-01_linux.tar.bz2 -C /opt

Add to your ~/.bashrc:

export PATH=/opt/gcc-linaro-aarch64-linux-gnu-4.8-2013.09-01_linux/bin:$PATH
export CROSS_COMPILE=aarch64-linux-gnu-

Restart your shell.


For details see:

[1] HowTo/BuildArm64Kernel

[2] http://www.linaro.org/engineering/engineering-projects/armv8

UEFI

Obtaining sources

Install dependencies:

sudo aptitude install uuid-dev build-essential acpica-tools

Obtain UEFI tools:

$ git clone git://git.linaro.org/arm/uefi/uefi-tools.git uefi-tools
$ cd uefi-tools
$ export PATH=$PATH:$(pwd)

Obtain UEFI sources with network support:

$ git clone git://git.linaro.org/arm/uefi/uefi-next.git
$ cd uefi-next
$ git checkout linaro-tracking

For details see:

[1] LEG/ServerArchitecture/UEFI/build#Using_uefi-tools_-_aka_the_normal_way

Building on ARMv7 (32-bit)

NOTE: Make sure that your CROSS_COMPILE env. var. doesn't contain "ccache" or stuff like that. Because UEFI building fails when it's not plain. You can just do next command to be sure it's ok:

$ export CROSS_COMPILE=arm-linux-gnueabihf-

Build UEFI:

$ uefi-build.sh rtsm_a15x1

The result binary will be at this location:

Build/ArmVExpress-RTSM-A15/RELEASE_ARMLINUXGCC/FV/RTSM_VE_CORTEX-A15_EFI.fd

For details see:

[1] LEG/ServerArchitecture/UEFI/build


Building on ARMv8 (64-bit)

NOTE: Make sure that your CROSS_COMPILE env. var. doesn't contain "ccache" or stuff like that. Because UEFI building fails when it's not plain. You can just do next command to be sure it's ok:

$ export CROSS_COMPILE=aarch64-linux-gnu-

Obtain UEFI sources with network support:

$ git clone git://git.linaro.org/arm/uefi/uefi-next.git
$ cd uefi-next
$ git checkout linaro-tracking

Build UEFI:

$ uefi-build.sh fvp

The result binary will be at this location:

Build/ArmVExpress-FVP-AArch64/RELEASE_ARMLINUXGCC/FV/FVP_AARCH64_EFI.fd

GRUB

Install dependencies:

$ sudo aptitude install git-bzr-ng kpartx bison flex autogen autoconf automake libdevmapper-dev libfreetype6-dev libfreetype6

Building on ARMv7 (32-bit)

Clone repo:

$ git bzr clone http://bazaar.launchpad.net/~leif-lindholm/linaro-grub/arm-uefi/ grub-uefi
$ cd grub-uefi

Fix build issue:

$ sed -i 's/ docs//' Makefile.am
$ git add Makefile.am
$ git commit -m "Fix build under Debian"

Build GRUB:

$ ./autogen.sh
$ ./configure STRIP=arm-linux-gnueabihf-strip --host=x86 --target=arm-linux-gnueabihf --with-platform=efi --prefix=/tmp/grub-efi_installed --disable-werror
$ make
$ make install

Create EFI image (pay attention to "-p" option and to "tftp" and "efinet" modules):

$ cd /tmp/grub-efi_installed
$ modules="boot chain configfile configfile efinet ext2 fat gettext help hfsplus linux loadenv lsefi normal normal ntfs ntfscomp part_gpt part_msdos part_msdos read search search_fs_file search_fs_uuid search_label terminal terminfo tftp"
$ bin/arm-linux-gnueabihf-grub-mkimage -v -o grub.efi -O arm-efi -p "efi" $modules

Copy GRUB EFI image and GRUB modules to TFTP files:

$ cp grub.efi /srv/tftp/efi/
$ cp -r lib/grub/arm-efi/ /srv/tftp/efi/

Create GRUB config file /srv/tftp/efi/grub.cfg with next content:

menuentry 'RTSM A15x1' {
   devicetree (tftp)efi/for-grub/rtsm_ve-ca15x1.dtb
   initrd (tftp)efi/for-grub/initrd
   linux (tftp)efi/for-grub/zImage console=ttyAMA0,115200n8 root=/dev/mmcblk0p2 rootwait ro mem=1024M ip=dhcp
}

More informution about GRUB for UEFI can be found here:

[1] http://lists.gnu.org/archive/html/grub-devel/2013-11/msg00299.html


Building on ARMv8 (64-bit)

Clone repo and switch to ARMv8 branch:

$ git clone http://git.savannah.gnu.org/cgit/grub.git
$ cd grub
$ git checkout master

Build GRUB:

$ ./autogen.sh
$ ./configure --host=x86_64-linux-gnu --target=aarch64-linux-gnu --build=x86_64-linux-gnu --with-platform=efi --prefix=/tmp/grub64-efi_installed
$ make
$ make install

Create EFI image:

$ cd /tmp/grub64-efi_installed/
$ modules="boot chain configfile configfile efinet ext2 fat gettext help hfsplus loadenv lsefi normal normal ntfs ntfscomp part_gpt part_msdos part_msdos read search search_fs_file search_fs_uuid search_label terminal terminfo tftp linux"
$ bin/grub-mkimage -v -o grub.efi -O arm64-efi -p "efi" $modules


Copy GRUB EFI image and GRUB modules to TFTP files:

$ cp grub.efi /srv/tftp/efi/
$ cp -r lib/grub/arm64-efi/ /srv/tftp/efi

Create GRUB config file /srv/tftp/efi/grub.cfg with next content:

menuentry 'ARM64 FVP' {
   set root=(pxe)
   linux /efi/for-grub/Image console=ttyAMA0,38400n8 earlyprintk=pl011,0x1c090000 debug user_debug=31 uefi_debug ignore_loglevel root=/dev/vda2 rootfstype=ext4 rootwait rw ip=dhcp
   devicetree /efi/for-grub/fvp-base-gicv2-psci.dtb
}

For details see:

[1] LEG/ServerArchitecture/GRUBonAArch64

Obtaining MMC image

NOTE: since we are going to do network boot, it can be done without MMC image. But in such a case we couldn't have rootfs and therefore Linux shell (we will have only initrd shell). If you want to do so -- you can skip this section entirely. See "Running RTSM Model with UEFI" for details.

We need MMC image that contains /boot and rootfs. It's like regular eMMC image for embedded devices. This image will be loaded by RTSM model.

ARMv7 (32-bit)

Method 1: Use pre-built image

We will use pre-built MMC image. It can be obtained this way:

$ wget https://snapshots.linaro.org/ubuntu/pre-built/vexpress/486/vexpress-raring_nano_20131007-486.img.gz
$ gunzip vexpress-raring_nano_20131007-486.img.gz

For details see:

[1] ARM/FastModels#Create_a_Linaro_image_for_the_ARM_Landing_Team.27s_release

[2] Platform/DevPlatform/Ubuntu/ImageInstallation

Method 2: Build custom MMC image

Of course you can build your own MMC image in a way described below.

First you need to obtain latest linaro-image-tools for that purpose. See Platform/DevPlatform/Ubuntu/ImageInstallation for details. I would recommend to use development tree from VCS repo:

$ sudo aptitude install bzr
$ bzr branch lp:linaro-image-tools
$ export PATH=$(pwd)/linaro-image-tools:$PATH

Dependencies for linaro-media-create:

$ sudo aptitude install parted dosfstools u-boot-tools python-argparse python-dbus python-debian python-parted qemu-user-static btrfs-tools command-not-found python-yaml
$ sudo update-command-not-found

Obtain hwpack (tarball with /boot) and rootfs tarball:

$ wget https://snapshots.linaro.org/ubuntu/images/nano/516/linaro-raring-nano-20131007-516.tar.gz
$ wget https://snapshots.linaro.org/ubuntu/hwpacks/vexpress/486/hwpack_linaro-vexpress_20131007-486_armhf_supported.tar.gz

Create MMC image:

$ image=linaro-raring-nano-20131007-516.tar.gz
$ hwpack=hwpack_linaro-vexpress_20131007-486_armhf_supported.tar.gz
$ board=vexpress
$ linaro-media-create             \
        --binary $image           \
        --hwpack $hwpack          \
        --dev $board              \
        --rootfs ext4             \
        --image-file linaro.img   \
        --image_size 2000M

ARMv8 (64-bit)

Building the kernel for ARMv8

Obtain kernel:

$ git clone git://git.linaro.org/arm/acpi/leg-kernel.git
$ cd leg-kernel
$ git checkout leg-20131119.0

Configure the kernel:

$ make ARCH=arm64 defconfig
$ make ARCH=arm64 menuconfig

In menuconfig enable next options:

- CONFIG_EFI

- CONFIG_EFI_STUB

Build the kernel and device tree blob:

$ make ARCH=arm64 -j4 Image
$ make ARCH=arm64 foundation-v8.dtb

Result files are:

- arch/arm64/boot/Image

- arch/arm64/boot/dts/foundation-v8.dtb


[1] HowTo/BuildArm64Kernel


Creating MMC image

Create a blank image:

$ dd if=/dev/zero of=uefi-root.img bs=1M count=1k

$ /sbin/sgdisk -n 1:-:200m -t 1:EF00 uefi-root.img
$ /sbin/sgdisk -n 2:-:- -t 2:8300 uefi-root.img

$ sudo kpartx -a uefi-root.img
$ sudo mkfs.vfat -F32 -s 2 /dev/mapper/loop0p1
$ sudo mkfs.ext4 /dev/mapper/loop0p2
$ sudo /sbin/blkid /dev/mapper/loop0p1
$ sudo kpartx -d uefi-root.img

Copy kernel and DTB into MMC image:

$ sudo kpartx -a uefi-root.img
$ sudo mkdir /media/mount
$ sudo mount /dev/mapper/loop0p1 /media/mount/
$ sudo cp arch/arm64/boot/Image /media/mount/
$ sudo cp arch/arm64/boot/dts/foundation-v8.dtb /media/mount/
$ sudo umount /media/mount
$ sudo kpartx -d uefi-root.img

Preparing files for GRUB

GRUB dowloads kernel image, device tree blob and initial RAM-disk files. So we need to obtain them and put them in TFTP directory so that GRUB is able to download them via TFTP.

Here is a sequence how to obtain those files from pre-built MMC image. We will use the same MMC image that was obtained in "Obtaining MMC image" chapter. You can of course build your own kernel and get these files from there (for details see ARM/FastModels#Get_a_kernel_a_device_tree_blob).

NOTE: kernel can't use uInitrd and uImage (that intended for u-boot), so they must be converted to regular "initrd" and "zImage" files.

Here is a working sequence:

$ wget https://snapshots.linaro.org/ubuntu/pre-built/vexpress/486/vexpress-raring_nano_20131007-486.img.gz
$ gunzip vexpress-raring_nano_20131007-486.img.gz
$ sudo -s

# kpartx -a vexpress-raring_nano_20131007-486.img
# mkdir /mnt/loop0p1
# mount /dev/mapper/loop0p1 /mnt/loop0p1
# cd /mnt/loop0p1

# cp uInitrd rtsm/rtsm_ve-ca15x1.dtb /srv/tftp/efi/for-grub

# cd -
# umount /mnt/loop0p1
# kpartx -d vexpress-raring_nano_20131007-486.img

# cd /srv/tftp/efi/for-grub
# dd if=uInitrd of=initrd bs=1 skip=64
# dd if=uImage of=zImage bs=1 skip=64
# rm uInitrd uImage

# exit
$

For more details see:

[1] ARM/FastModels#Get_a_kernel_a_device_tree_blob

[2] ARM/FastModels#Get_the_initrd

[3] Platform/Android/AndroidOnFastModels#How_to_rebuild_the_kernel_image

Running UEFI Network Booting

Creating Bridge and TAP

See LEG/ServerArchitecture/UEFI/Host_Setup_for_Networking

NOTE: Use procedure described in "Case 1".


NetworkManager notice

If you are using NetworkManager and have some setup in /etc/network/interfaces critical for RTSM, you may want to disable it while working with RTSM/virtual networking.

It can be done this way:

$ sudo service network-manager stop

Or maybe you may want to configure it to managed mode so that it respect networking setup in /etc/network/interfaces. It can be accomplished like this:

$ sudo vim /etc/NetworkManager/NetworkManager.conf

then change the line managed=false to managed=true and save file.

Restart network manager:

sudo service network-manager restart

For details see:

[1] https://wiki.debian.org/NetworkManager#Wired_Networks_are_Unmanaged

Installing RTSM Model

ARMv7 (32-bit)

Obtain RTSM model (be sure to substitute your linaro account name instead of “your.name”)

$ sftp your.name@fastmodels.linaro.org:/home/resources/
sftp> get RTSM_A15x124_VE_7.1_6.tgz
sftp> bye

Obtained model is Cortex-A15 (ARMv7) 1/2/4 cores, VersatileExpress board.

Install RTSM model:

$ tar xzvf RTSM_A15x124_VE_7.1_6.tgz
$ ./RTSM_A15x124_VE.sh

For details see:

[1] https://collaborate.linaro.org/display/IKB/FlexLM+and+Fast+Models

[2] ARM/FastModels

ARMv8 (64-bit)

Obtain RTSM model (be sure to substitute your linaro account name instead of “your.name”):

$ sftp your.name@fastmodels.linaro.org:/home/resources/
sftp> get FVP_Base_AEMv8A-AEMv8A_0.8_5108.tgz
sftp> bye

Extract and install it:

$ tar xzvf FVP_Base_AEMv8A-AEMv8A_0.8_5108.tgz
$  ./FVP_Base_AEMv8A-AEMv8A.sh

For details see:

[1] https://collaborate.linaro.org/display/IKB/FlexLM+and+Fast+Models

[2] http://releases.linaro.org/13.09/openembedded/aarch64/

Choosing terminal for RTSM

RTSM uses xterm by default. If you want to use xterm, it must be installed:

$ sudo aptitude install xterm

Otherwise (if you prefer another terminal), a little hack should be done.

First, make sure that "xterm" package is not installed:

$ sudo aptitude purge xterm

Then create "/usr/bin/xterm" file:

$ sudo touch /usr/bin/xterm
$ sudo chmod +x /usr/bin/xterm
$ sudo vim /usr/bin/xterm

And save it with next content:

   1 #!/bin/bash
   2 
   3 my_terminal=urxvtc
   4 
   5 # Getting rid of "urxvt: "terminal_0": malformed option."
   6 params=$(echo $@ | sed 's/ terminal_0//')
   7 
   8 $my_terminal $params

I'm using URxvt terminal. If you prefer another one (like "gnome-terminal" or "konsole" etc), please be sure to change "my_terminal" variable properly.

For details see:

[1] ARM/FastModels#Hacking_RTSM_to_use_gnome-terminal_instead_of_xterm

Running RTSM License

In order to use RTSM models you need to run appropriate license. The only way to do that at the moment is to use Linaro licensing server. So SSH-tunnel must be created for this purpose.

1. Create SSH-key:

$ ssh-keygen -t rsa -C "your_email@example.com"
$ ssh-add id_rsa

2. Add generated public key to login.linaro.org:

$ cat ~/.ssh/id_rsa.pub | xclip

...and paste it here: https://login.linaro.org

3. Send mail to it-support@linaro.org with request to be added to FlexLM group

4. Add to your ~/.bashrc:

export ARMLMD_LICENSE_FILE=8224@127.0.0.1

5. Starting port forwarding to Linaro FastModel licensing server

It can be done using next script (be sure to replace “name” with your linaro account name).

   1 #!/bin/sh
   2 
   3 name=your.name
   4 server=flexlm.linaro.org
   5 port1=8224
   6 port2=18224
   7 bind1=$port1:localhost:$port1
   8 bind2=$port2:localhost:$port2
   9 
  10 export ARMLMD_LICENSE_FILE=$port1@127.0.0.1
  11 
  12 ssh                  \
  13    -L $bind1         \
  14    -L $bind2         \
  15    -N $name@$server

Run this script and enter you SSH password.

6. It’s convenient to run this SSH process in background. So do next:

  • - press Ctrl+Z - switch it to background:

$ bg
  • - detach from current terminal:

$ disown

That’s it! Now you are able to use RTSM models.

For details see:

[1] https://collaborate.linaro.org/display/IKB/FlexLM+and+Fast+Models

[2] ARM/FastModels

Running RTSM Model with UEFI

NOTE: since we are going to do network boot, one can get rid of MMC image file at all, removing this line:

   -C motherboard.mmc.p_mmc_file="$rtsm_mmc"            \

In such a case we will only trap to the initrd busybox shell, not having full working Linux environment. That's because rootfs can be taken only from MMC image (our PXE server doesn't send rootfs over network). Nevertheless, it can be a good start point since it doesn't require messing up with MMC image and boot will be much faster. And it also can be good test scenario.

ARMv7 (32-bit)

Next script allows you to run RTSM model with UEFI and networking support. Be sure to replace "rtsm_*" variables with your pathes.

   1 #!/bin/sh
   2 
   3 rtsm_model=path/to/your/model/RTSM_VE_Cortex-A15x1
   4 rtsm_mmc=path/to/your/mmc/image/vexpress-raring_nano_20131007-486.img
   5 rtsm_uefi=path/to/your/uefi/bin/RTSM_VE_CORTEX-A15_EFI.fd
   6 
   7 nic="tap0"
   8 mac="00:02:f7:ef:5c:f5"
   9 
  10 $rtsm_model                                             \
  11    -C motherboard.smsc_91c111.enabled=1                 \
  12    -C motherboard.smsc_91c111.mac_address=$mac          \
  13    -C motherboard.hostbridge.interfaceName="$nic"       \
  14    -C motherboard.mmc.p_mmc_file="$rtsm_mmc"            \
  15    -C motherboard.flashloader0.fname=$rtsm_uefi

ARMv8 (64-bit)

Next script allows you to run FVP model with UEFI and networking support. Be sure to replace "rtsm_*" variables with your pathes.

   1 #!/bin/sh
   2 
   3 rtsm_model=path/to/your/model/FVP_Base_AEMv8A-AEMv8A
   4 rtsm_mmc=path/to/your/mmc/image/vexpress-raring_nano_20131007-486.img
   5 rtsm_uefi=path/to/your/uefi/bin/FVP_AARCH64_EFI.fd
   6 rtsm_uefi_sec=bl1.bin
   7 
   8 nic="tap0"
   9 mac="00:02:f7:ef:5c:f5"
  10 
  11 $rtsm_model                                                             \
  12         -C bp.flashloader0.fname=$rtsm_uefi                             \
  13         -C pctl.startup=0.0.0.0                                         \
  14         -C bp.secure_memory=0                                           \
  15         -C cluster0.NUM_CORES=4                                         \
  16         -C cluster1.NUM_CORES=4                                         \
  17         -C cache_state_modelled=0                                       \
  18         -C bp.pl011_uart0.untimed_fifos=1                               \
  19         -C bp.virtioblockdevice.image_path=$rtsm_mmc                    \
  20         -C bp.secureflashloader.fname=$rtsm_uefi_sec                    \
  21         -C bp.hostbridge.interfaceName=$nic                             \
  22         -C bp.smsc_91c111.enabled=true                                  \
  23         -C bp.smsc_91c111.mac_address=$mac

NOTE: "cache_state_modelled" param must be set to 0. Otherwise, GRUB couldn't be started, showing "Synchoronous exception" error at terminal.

NOTE: do NOT use "bp.hostbridge.userNetworking" option, it switches off networking even when specified as "true".

In order to use UEFI we need to obtain secure bootloader. There are 3 files need to be in place:

- bl1.bin

- BL2_AP_Trusted_RAM.bin

- BL31_AP_Trusted_RAM.bin


Run next commands in directory with your FVP model running script:

$ wget http://releases.linaro.org/13.09/openembedded/aarch64/bl1.bin
$ wget http://releases.linaro.org/13.09/openembedded/aarch64/BL2_AP_Trusted_RAM.bin
$ wget http://releases.linaro.org/13.09/openembedded/aarch64/BL31_AP_Trusted_RAM.bin

NOTE: those files may be outdated. If you can't get to UEFI due to secure bootloader doesn't boot -- please use next approach to build secure bootloader manually:

Building ARM trusted firmware manually

$ git clone https://github.com/ARM-software/arm-trusted-firmware.git
$ cd arm-trusted-firmware
$ sudo aptitude install colormake ccache

Then run next script:

   1 #!/bin/sh
   2 make=colormake
   3 uefi_path=<put the path to your UEFI sources directory here>
   4 uefi_file=Build/ArmVExpress-FVP-AArch64/RELEASE_ARMLINUXGCC/FV/FVP_AARCH64_EFI.fd
   5 uefi=$uefi_path/$uefi_file
   6 dest=<put the path to destination for result binaries here>
   7 
   8 set -e
   9 
  10 echo
  11 echo "---> Cleaning..."
  12 CROSS_COMPILE="ccache aarch64-linux-gnu-" $make PLAT=fvp clean
  13 
  14 echo
  15 echo "---> Building..."
  16 CROSS_COMPILE="ccache aarch64-linux-gnu-" $make PLAT=fvp all
  17 
  18 echo
  19 echo "---> Building FIP..."
  20 CROSS_COMPILE="ccache aarch64-linux-gnu-" $make PLAT=fvp BL33=$uefi fip
  21 
  22 echo
  23 echo "---> Copying..."
  24 cp -f build/fvp/release/*.bin $dest

[1] http://releases.linaro.org/13.09/openembedded/aarch64/ (see "Binary Image Installation" inlay)

[2] http://snapshots.linaro.org/components/kernel/uefi-next/158

[3] http://irclogs.linaro.org/2012/12/19/%23linaro-enterprise.txt

Choosing PXE boot in UEFI menu

When you see such a line:

The default boot selection will start in  10 seconds

Press some key and you will see bootloader menu. Then do next:

[a] Boot Manager
[1] Add Boot Device Entry
[8] PXE on MAC Address: 00:02:F7:EF:5C:F5
Description for this new Entry: pxe
[5] Return to main menu
[2] pxe

Now you must see GRUB menu with single entry: "RTSM A15x1". Press "Enter" and it will boot kernel.


Boot Process Automation

One can wish to make network booting completely automatic (e.g. for testing purpose). Here is some insights on how to do so.

Make UEFI store it's configuration

First we need to start RTSM model in a way it can store UEFI configuration (e.g. boot menu entries) in separate file and then use it at next run. It can be done by adding next lines to RTSM model run line:

   -C motherboard.flashloader1.fname=uefi-vars.fd       \
   -C motherboard.flashloader1.fnameWrite=uefi-vars.fd

So now your script for running RTSM model with UEFI must looks like:

   1 #!/bin/sh
   2 
   3 rtsm_model=path/to/your/model/RTSM_VE_Cortex-A15x1
   4 rtsm_mmc=path/to/your/mmc/image/vexpress-raring_nano_20131007-486.img
   5 rtsm_uefi=path/to/your/uefi/bin/RTSM_VE_CORTEX-A15_EFI.fd
   6 
   7 nic="tap0"
   8 mac="00:02:f7:ef:5c:f5"
   9 
  10 $rtsm_model                                             \
  11    -C motherboard.smsc_91c111.enabled=1                 \
  12    -C motherboard.smsc_91c111.mac_address=$mac          \
  13    -C motherboard.hostbridge.interfaceName="$nic"       \
  14    -C motherboard.mmc.p_mmc_file="$rtsm_mmc"            \
  15    -C motherboard.flashloader0.fname=$rtsm_uefi         \
  16    -C motherboard.flashloader1.fname=uefi-vars.fd       \
  17    -C motherboard.flashloader1.fnameWrite=uefi-vars.fd

Running RTSM+UEFI using this script you will have boot menu configuration stored in "uefi-vars.fd" file. Change boot menu configuration manually one single time and next time when you run RTSM+UEFI -- it going to load your configuration from "uefi-vars.fd" automatically.

Adjust UEFI boot menu

Now we need to change boot menu in a way it has "PXE boot" by default. Start RTSM model, press any key to get to the boot menu, and then do next:

[a] Boot Manager
[1] Add Boot Device Entry
[7] PXE on MAC Address: 00:02:F7:EF:5C:F5
Description for this new Entry: pxe
[3] Remove Boot Device Entry
[1] Linaro image on SD card
[5] Return to main menu
[1] pxe

Now bootloader has the only one option where to boot from (PXE) and will boot it automatically once countdown is finished ("The default boot selection will start in ... seconds"). Also this configuration is being stored in "uefi-vars.fd" and will load automatically on next RTSM run.

Make GRUB boot automatically

Now we have GRUB that waits in GRUB menu for user to make choice. We can ask GRUB to boot first entry automatically next way. Add next lines in "/srv/tftp/efi/grub.cfg" file:

set default="0"
set timeout=1

The whole "grub.cfg" file now must looks like (for ARMv7 (32-bit) case):

set default="0"
set timeout=1
menuentry 'RTSM A15x1' {
    devicetree (tftp)efi/for-grub/rtsm_ve-ca15x1.dtb
    initrd (tftp)efi/for-grub/initrd
    linux (tftp)efi/for-grub/zImage console=ttyAMA0,115200n8 root=/dev/mmcblk0p2 rootwait ro mem=1024M ip=dhcp
}

Once all described steps are done, the whole chain is done automatically: 1. you start RTSM model 2. then UEFI accomplish PXE boot automatically, downloading GRUB EFI image and running it 3. GRUB automatically performs first menu entry (which is PXE boot also) 4. so GRUB downloads kernel, DTB and initrd and then starts them 5. kernel started


Other resources

LEG/ServerArchitecture/UEFI/UEFI_Network_Booting (last modified 2018-02-22 14:56:48)