EDK2 iSCSI support


Synopsis

This wiki page describes how to boot from an iSCSI target using the Aarch64 QEMU system model and EDK2 firmware.

Host Configuration

The host needs to be configured to support QEMU networking. This page will describe setting up the iSCSI target and (optional) DHCP server on the host as well, although these functions could also be provided by machines on the network.

TAP network interface configuration

To set up a tap interface for QEMU, use the following commands:

ip tuntap add dev tap0 mode tap user <user name>
ip link set dev tap0 up
ifconfig tap0 192.168.3.1

Change "<user name>" in the above to match the username that will be running QEMU.


For a more detailed explanation, please see Host Setup for Networking. This covers a variety of setups, including those that add bridging with host physical networks if you want QEMU to have full network connectivity beyond the host. For the setup described here for iSCSI, Case 3 is sufficient, with just a tap interface configured. The tap interface needs to be up and configured for the DHCP server or iSCSI target to be brought up.

DHCP server setup (Optional)

EDK2 can optionally get the iSCSI parameters from the DHCP server instead of being statically configured. This can be convenient as it minimizes the manual configuration that needs to be through the EDK2 menus. Using the isc-dhcp-server package, the following configuration fragment will provide both an IP address and ISCSI target configuration to UEFI. These can both also be statically configured in EDK2

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

subnet 192.168.3.0 netmask 255.255.255.0 {
  range 192.168.3.3 192.168.3.253;
  interface tap0;
  option root-path "iscsi:192.168.3.1::::iqn.2015-01.com.example:edk2";
}

Explanation of fields:

option root-path

iSCSI target information returned in DHCP response

interface

limits responses to this interface

For this example, the iSCSI target name "iqn.2015-01.com.example:edk2""is in IQN format. This is one of the standard ways of identifying iSCSI targets and initiators, and is used by EDK2. The IP address of the iSCSI target is 192.168.3.1. Note that the DHCP server needs to be (re)started after the tap0 interface is brought up.

iSCSI target configuration

The EDK2 iSCSI support was tested with the Linux-IO iSCSI target, using the 'targetcli' configuration utility. Instructions for setting up an iSCSI target can be found at the iSCSI and targetcli pages on the linux-iscsi.org wiki. The following targetcli commands should create a working setup, using the filesystem image file described below. You will need to update the file path to one suitable for your system.

> set global auto_cd_after_create=false
> cd /backstores/fileio
> create name=file_be file_or_dev=/path/to/iscsi-disk-image.bin size=100M
> cd file_be
> /iscsi create wwn=iqn.2015-01.com.example:edk2
> cd /iscsi/iqn.2015-01.com.example:edk2/tpg1/
> luns/ create /backstores/fileio/file_be
> portals/ create 192.168.3.1
> set attribute authentication=0 demo_mode_write_protect=0 generate_node_acls=1 cache_dynamic_acls=1
> / saveconfig

Note that the tap0 interface needs to be configured with the IP address 192.168.3.1 before the portal create command will succeed.

Preparing disk image

The disk image used as a backstore is the same as would be used if accessing it using virtio: a GPT partitioned image, with an EFI System Partition (ESP). A basic image with a kernel and initrd is provided here: iscsi-disk-image.bin.gz Simply uncompress this and use it as the iSCSI backing store, or as a virtio connected disk image. The provided disk image provides two files: Image.efi, and initrd, which are the EFI stub enabled Linux kernel, and the initrd respectively. Note that if you build your own kernel, the filename should end in ".efi" in order for EDK2 to recognize it as something that can be added as a boot menu entry.

Booting a full Linux installation with the root filesystem on iSCSI is more involved and requires mounting the root filesystem in the initrd, and is not described here.

Building UEFI

Currently you will need to build your own EDK2 image to enable iSCSI. A small patch is required on top of the 2015.01 Linaro EDK2 release.

The following steps should build a working EDK2 image, and domplete instructions to build EDK2 are also available. The resulting QEMU_EFI.fd file will be used to boot EDK2 under QEMU. You will need an Aarch64 compiler in your path, which can be downloaded from [www.linaro.org:/downloads | Linaro].

$ git clone https://git.linaro.org/uefi/linaro-edk2.git
$ git clone https://git.linaro.org/uefi/uefi-tools.git
$ cd linaro-edk2
$ git checkout origin/linaro-edk2-2015.01
$ wget 'https://wiki.linaro.org/LEG/Engineering/Kernel/UEFI/UEFI_ISCSI?action=AttachFile&do=get&target=0001-Don-t-require-optional-ISCSI-negotiation-responses.patch' -O edk2.patch
$ patch -p1 < edk2.patch
$ ../uefi-tools/uefi-build qemu64-intelbds
$ ls -al ./Build/ArmVirtualizationQemu-IntelBds-AARCH64/RELEASE_GCC48/FV/QEMU_EFI.fd

The QEMU_EFI.fd file is now ready for use. (Aside: the FVP platforms require an additional step - packaging the EDK2 binary in a fip.bin file. This is required when using ATF (Arm Trusted Firmware), and is not required for QEMU since ATF is not used.)

Building QEMU

QEMU 2.2.0 or later is required. If this is not provided by your distribution, you can build it yourself:

$ git glone git://git.qemu-project.org/qemu.git
$ cd qemu
$ git checkout -b 2.2.0-stable v2.2.0
$ ./configure --prefix=/usr/local --target-list=aarch64-softmmu
$ make -j`getconf _NPROCESSORS_ONLN`
$ sudo make install

Running QEMU

Preparing flash image files

To run QEMU and emulate flash for persistent storage of the UEFI variables, we need use the "-plfash" option instead of the "-bios" option. This also means that the files we provide must be the full 64 MBytes of the flash they are backing up. We need to pad the QEMU_EFI.fd file that we built to 64 MBytes, and create an empty 64 MByte file for the second flash which contains the UEFI variables. A prebuilt flash0.ing can be used if you don't want to build your own image.

$ dd if=/dev/zero of=flash0.img bs=1M count=64
$ dd if=/dev/zero of=flash1.img bs=1M count=64
$ dd if=QEMU_EFI.fd of=flash0.img conv=notrunc

To update the flash0 image with a rebuilt QEMU_EFI.fd, simple rerun the line:

$ dd if=QEMU_EFI.fd of=flash0.img conv=notrunc

Invoking QEMU

qemu-system-aarch64 -m 1024 -cpu cortex-a57 -M virt \
-pflash QEMU_EFI.fd -pflash pflash1.bin -nographic \
-device virtio-net-device,netdev=v0 -netdev tap,id=v0,ifname=tap0

The 'v0' id is only used to connect the "-device" with the "-netdev" arguments - it is an arbitrary name.
Once started, EDK2 should boot to the shell. It will try to do a network boot first (and fail), and then fall through to the EFI shell boot option, so the first boot will be somewhat slow.

Configure EDK2 iSCSI

Now that EDK2 is booted, we can configure it to connect to an iSCSI target:

  1. Type "exit" to exit the EFI shell.
  2. Select "Device Manager"
  3. Select "iSCSI Configuration"
  4. Enter the iSCSI Initiator IQN. This is the name of the initiator that will be provided to the target. For our simple setup any valid IQN name will do, as the target does not validate this or use it to control what devices are presented. Enter "iqn.2015-01.com.example:edk2init", or some other IQN formatted name.
  5. Select "Port XX:XX:XX:XX:XX:XX" You should see a screen like this:

edk2-iscsi.png

  1. Select "Enable iSCSI
  2. Configure IP address for Initiator (EDK2)
    • If using DHCP, select the DHCP check box
    • If using static configuration, configure the IP parameters. This needs to be on the same subnet as your host tap0 interface
  3. Configure the iSCSI target information.
    • If using the DHCP configuration listed above with "root-path", select the "Get target info via DHCP" option that becomes available when DHCP is enabled.
    • If using a static configuration, then you will need to specify all the fields here:
      • Target name: This is the IQN formatted name for the target, iqn.2015-01.com.example:edk2 for the examples on this page
      • Target IP address: 192.168.3.1 for the examples on this page.
      • Target Port: 3260
      • Target LUN: 0
  4. ISID: this can be left as is
  5. Chap configuration: None is used in this example. (The 'demo' mode of the target configuration does not use any authentication.)
  6. Save the configuration. NOTE: At this time, the "F10" key doesn't seem to properly save the information. Use the "Save Changes" item near the bottom of the iSCSI port configuration page.

The EDK2 firmware has now been configured to connect to an iSCSI target, and will do so the next time it is booted.

Change boot order for quicker boot

The default boot options include booting via the network (PXE-like), and this will slow down the boot process. To allow for quicker boot, you can remove the unused boot options. To do so:

  1. Select the "Boot Maintenance Manager" from the top level EDK2 configuration menu
  2. Select "Boot Options"
  3. Select "Change Boot Option"
  4. Move "EFI Internal Shell" to the top of the list, and commit the changes.

Note: The "F10=Save" option does not seem to work properly, so you will need to exit out to the top boot maintenance manager menu, and answer "Y" when prompted about saving changes.

The EFI shell is now the first boot option, so network boot will not be tried first.

Boot Linux from EFI shell

After the above steps have been completed, we can now boot QEMU and verify that the iSCSI drive is being found. If you did not disable the network boot, EDK2 will be slow to boot as it is waiting for network boot timeouts. Once booted, you should boot to the shell and see something like this:

UEFI Interactive Shell v2.0
EDK II
UEFI v2.40 (EDK II, 0x00010000)
Mapping table
      FS0: Alias(s):HD36affk1:;BLK2:
          VenHw(837DCA9E-E874-4D82-B29A-23FE0E23D1E2,003E000A00000000)/MAC(525400123456,0x1)/IPv4(192.168.3.1)/iSCSI(iqn.1111-11.1.1:ovmf,0x1,0x0,None,None,None,TCP)/HD(1,GPT,B3BF1578-2E32-403E-AC41-0B10238FDBD1,0x800,0x317DF)
     BLK3: Alias(s):
          VenHw(F9B94AE2-8BA6-409B-9D56-B9B417F53CB3)
     BLK0: Alias(s):
          VenHw(8047DB4B-7E9C-4C0C-8EBC-DFBBAACACE8F)
     BLK1: Alias(s):
          VenHw(837DCA9E-E874-4D82-B29A-23FE0E23D1E2,003E000A00000000)/MAC(525400123456,0x1)/IPv4(192.168.3.1)/iSCSI(iqn.1111-11.1.1:ovmf,0x1,0x0,None,None,None,TCP)
Press ESC in 1 seconds to skip startup.nsh or any other key to continue.
Shell> 

FS0: should be your iSCSI filesystem, and you will see the IQN iSCSI target name in the path.

Now you can simply make FS0 the active filesystem, and boot Linux:

Shell> fs0: 
FS0:\> dir
Directory of: FS0:\
01/27/2015  16:16           6,387,232  Image.efi
01/27/2015  16:16           1,942,093  initrd
          2 File(s)   8,329,325 bytes
          0 Dir(s)
FS0:\> Image.efi initrd=initrd
EFI stub: Booting Linux Kernel...
...

This should boot to a Buildroot login where you can login as root, no password required.

Configure boot menu option for iSCSI

Note: It should be possible to save this new boot option persistently, but this does not currently work.
Now that we have configured iSCSI, and verified that Linux boots, we can add a boot menu entry that will boot the Linux image on the iSCSI filesystem.

To configure this, restart QEMU and go to the main EDK configuration menu, then:

  • 1.Select "Boot Maintenance Manager"
  • Select "Boot Options"
  • Select "Add Boot Option"
  • Select the path that corresponds to the iSCSI filesystem. you should see the IP address and the IQN name of the target in the path.
  • Select "Image.efi"
  • Input your desired description, and "initrd=initrd" in the "Input Optional Data" field
  • commit the changes and exit.
  • Go to the "Boot Manager" menu, and select your newly created boot option.

The new boot menu option you created will be booted immediately. It should be possible to save this new boot option persistently, however this does not currently work (as of 2015.01 release.)

Useful links

Leif Lindholm describes how to install Debian Jessie on QEMU Aarch64.
Alex Bennee has a nice writeup on QEMU Aarch64 system emulation. This is where I learned about buildroot.

LEG/ServerArchitecture/UEFI/UEFI_ISCSI (last modified 2017-08-17 12:12:58)