30 Jun 2013

Running UEFI virtualised

UEFI is a portable platform firmware standard, although in practice it has up until recently been used only on IA64 and amd64/x64 platforms. The opensource implementation (tianocore edk2) includes support also for ia32 and ARM (aarch32) platforms.

I develop for the ARM platform, but I sometimes need to verify my work on other platforms. Since I cannot really keep reflashing my Linux desktop machine every time, I need to use an emulator such as QEMU for testing. This is possible thanks to the awesome feature called OVMF which is included within the Tianocore EDK2 source tree.

Inside the OvmfPkg directory inside edk2, there is a build.sh script which umm ... either builds a UEFI image or boots said UEFI image in QEMU, depending on how it is called.

It still needs a minor bit of fiddling to make it work, but this takes care of all the actually hard bits. So I'll focus on documenting the "easy" bits (which are only easy if you know them).

On my Debian Wheezy installation, which uses gcc-4.7 by default, an edit is required to the toolchain configuration template file:

    diff --git a/BaseTools/Conf/tools_def.template b/BaseTools/Conf/tools_def.template
    index a82404a..5f59a5d 100644
    --- a/BaseTools/Conf/tools_def.template
    +++ b/BaseTools/Conf/tools_def.template
    @@ -2859,7 +2859,7 @@ DEFINE GCC46_ASM_FLAGS               = DEF(GCC45_ASM_FLAGS)
     *_GCC46_X64_ASLCC_FLAGS          = DEF(GCC_ASLCC_FLAGS) -m64
     *_GCC46_X64_ASLDLINK_FLAGS       = DEF(GCC46_IA32_X64_ASLDLINK_FLAGS) -m elf_x86_64
    -*_GCC46_X64_ASM_FLAGS            = DEF(GCC46_ASM_FLAGS) -m64 -melf_x86_64
    +*_GCC46_X64_ASM_FLAGS            = DEF(GCC46_ASM_FLAGS) -m64
     *_GCC46_X64_CC_FLAGS             = DEF(GCC46_X64_CC_FLAGS)
     *_GCC46_X64_DLINK_FLAGS          = DEF(GCC46_X64_DLINK_FLAGS)
     *_GCC46_X64_RC_FLAGS             = DEF(GCC_X64_RC_FLAGS)

Then, to build UEFI with gcc 4.6 or later:

    ./OvmfPkg/build.sh -a X64 -t GCC46

The script tries to auto-extract toolchain config from the current environment, and ends up most upset since there is no GCC47 toolchain in the build config.

And to launch the generated inage in QEMU:

    ./OvmfPkg/build.sh -a X64 -t GCC46 qemu

We must specify the toolchain here even though we are not building anything at this point, because the script deduces the path under `./Build` where the generated firmware image can be found, using the toolchain name.

QEMU might complain about some missing ROM files at this point. If you wish, symlink them in from your system's QEMU ROM directory (in my case `/usr/share/qemu`) to the directory where the script places your UEFI ROM (in my case `./Build/OvmfX64/DEBUG_GCC46/X64`). My image ran successfully without any such modifications though.

If you do nothing else, your image should launch, displaying a Tianocore logo, some boot diagnostics, some attempts to boot using various facilities and then falling back to launching an EFI shell since no such facilities were provided by the above configuration.

I will follow up shortly with a post about modifying disk image files and playing around with testing kernels under the resulting system (my original reason for looking into this).

posted at: 13:37 | path: /uefi | permanent link to this entry