UEFI App Bare Bones: Difference between revisions

[unchecked revision][unchecked revision]
Content deleted Content added
Changed FAT32 instructions to use mtools
m Bot: Replace deprecated source tag with syntaxhighlight
 
(45 intermediate revisions by 18 users not shown)
Line 1:
{{BeginnersWarning}}
{{Rating|2}}
 
In this tutorial, wedevelopers will create a hard drive or ISO image containing a bare bones UEFI application for the x86_64x86-64 platform.
 
YouIt areis recommended to have read and fully understood the [[Bare Bones]] tutorial first. The [[UEFI]] page provides some background to the UEFI boot process and should also be consulted first.
 
This tutorial uses the header files and GUID definitions from the [https://sourceforge.net/projects/gnu[GNU-efi/ gnu-efiEFI]] project, but does '''not''' use the gnu-efi build system, but rather the MingwMinGW-w64 or LLVM/Clang toolchain.
 
== Prerequisites ==
 
YouDevelopers will need a [[GCC Cross-Compiler]] or Clang targeting the '''x86_64-w64-mingw32''' target (for [[PE]] output), and the [https://sourceforge.net/projects/gnu-efi/ '''gnu-efi'''] package to(for compileUEFI the actual kernelheaders). Most ToLinux builddistros theprovide EFIcross-compilers filesystemfor imagethis wetarget, use [[MTools]] and optionally [http://www.tysos.org/redmine/projects/tysos/wiki/EFIso it'''mkgpt''']s ifusually younot also wantnecessary to createbuild a hard diskit imageyourself. This Toexample rundoes undernot anlink emulator,against we use '''qemu[[GNU-system-x86_64''' and the [http://tianocore.sourceforge.net/wiki/OVMF '''x64 OVMF firmware'''EFI]]. or Iffollow you wish toits build aprocess; CDonly image,the youheaders willare also need '''xorriso'''used.
 
To build the EFI filesystem image, developers can use [[MTools]] or [https://github.com/jncronin/mkgpt '''mkgpt'''] to create a hard disk image. To build a CD image, '''xorriso''' (in [[mkisofs]] emulation mode) will be needed. To run under an emulator, it is best to use '''qemu-system-x86_64''' coupled with the [http://tianocore.sourceforge.net/wiki/OVMF '''x64 OVMF firmware'''].
Under an apt-based system (e.g. Debian/Ubuntu) you can run <source lang="bash">sudo apt-get install qemu binutils-mingw-w64 gcc-mingw-w64 xorriso mtools
 
wget http://www.tysos.org/files/efi/mkgpt-latest.tar.bz2
Under an apt-based system (e.g. Debian/Ubuntu), youdevelopers can run: <sourcesyntaxhighlight lang="bash">sudo apt-get install qemu ovmf gnu-efi binutils-mingw-w64 gcc-mingw-w64 xorriso mtools</syntaxhighlight>
tar jxf mkgpt-latest.tar.bz2
 
cd mkgpt && ./configure && make && sudo make install && cd ..</source> and then separately download OVMF and extract the OVMF.fd file somewhere, and also gnu-efi.
To install mkgpt you can run these commands:<syntaxhighlight lang="bash">git clone https://github.com/jncronin/mkgpt.git
cd mkgpt
automake --add-missing
autoreconf
./configure
make
sudo make install</syntaxhighlight>
 
== Testing the emulator ==
Line 20 ⟶ 28:
Now is a good time to check the emulator is working successfully with the OVMF firmware.
 
<sourcesyntaxhighlight lang="bash">qemu-system-x86_64 -L OVMF_dir/ -biospflash OVMF.fd</sourcesyntaxhighlight>should launch qemu and dump you atlaunch a UEFI shell prompt.
 
== Preparing the files ==
 
=== hello.c ===
 
CreateNext, create a file with the following:
<sourcesyntaxhighlight lang="c">#include <efi.h>
#include <efilib.h>
 
Line 37 ⟶ 47:
 
/* Say hi */
Status = ST->ConOut->OutputString(ST->ConOut, L"Hello World\n\r\n"); // EFI Applications use Unicode and CRLF, a la Windows
if (EFI_ERROR(Status))
return Status;
Line 56 ⟶ 66:
 
return Status;
}</sourcesyntaxhighlight>
 
=== gnu-efi/lib/data.c ===
 
WeDevelopers will also need bring in the data.c file from the gnu-efi distribution, as this contains many predefined GUIDs for the various UEFI services. To avoid bloat and unnecessary dependencies on the rest of gnu-efi, youit will need to editbe itedited to remove the references to 'LibStubStriCmp', 'LibStubMetaiMatch', and 'LibStubStrLwrUpr' (simply makeset all the members of the LibStubUnicodeInterface structure be NULL).
 
=== gnu-efi/lib/lib.h ===
 
data.c includes this file. It Wemust copybe itcopied as-is to ourthe source directory.
 
== Building ==
 
To build, we use ourthe cross-compiler:
<syntaxhighlight lang="bash">
<source lang="bash">x86_64-w64-mingw32-gcc -ffreestanding -Ipath/to/gnu-efi/inc -Ipath/to/gnu-efi/inc/x86_64 -Ipath/to/gnu-efi/protocol -c -o hello.o hello.c
# compile: (flags before -o become CFLAGS in the Makefile)
x86_64-w64-mingw32-gcc -ffreestanding -Ipath/to/gnu-efi/inc -Ipath/to/gnu-efi/inc/x86_64 -Ipath/to/gnu-efi/protocol -c -o data.o path/to/gnu-efi/lib/data.c
<source lang="bash">x86_64-w64-mingw32-gcc -ffreestanding -Ipath/to/gnu-efi/inc -Ipath/to/gnu-efi/inc/x86_64 -Ipath/to/gnu-efi/inc/protocol -c -o hello.o hello.c
x86_64-w64-mingw32-gcc -nostdlib -Wl,-dll -shared -Wl,--subsystem,10 -e efi_main -o BOOTX64.EFI hello.o data.o -lgcc</source>Note here that '--subsystem 10' specifies an EFI application.
x86_64-w64-mingw32-gcc -ffreestanding -Ipath/to/gnu-efi/inc -Ipath/to/gnu-efi/inc/x86_64 -Ipath/to/gnu-efi/inc/protocol -c -o data.o path/to/gnu-efi/lib/data.c
# link: (flags before -o become LDFLAGS in the Makefile)
x86_64-w64-mingw32-gcc -nostdlib -Wl,-dll -shared -Wl,--subsystem,10 -e efi_main -o BOOTX64.EFI hello.o data.o -lgcc</source>Note here that '--subsystem 10' specifies an EFI application.
</syntaxhighlight>
Note here that '--subsystem 10' specifies an EFI application for ld.
 
=== Under LLVM/clang ===
The build sequence under LLVM/clang is essentially the same, although there is the advantage of having ''all'' targets installed by default:
 
<syntaxhighlight lang="bash">
CFLAGS='-target x86_64-unknown-windows
-ffreestanding
-fshort-wchar
-mno-red-zone
-Ipath/to/gnu-efi/inc -Ipath/to/gnu-efi/inc/x86_64 -Ipath/to/gnu-efi/inc/protocol'
LDFLAGS='-target x86_64-unknown-windows
-nostdlib
-Wl,-entry:efi_main
-Wl,-subsystem:efi_application
-fuse-ld=lld-link'
clang $CFLAGS -c -o hello.o hello.c
clang $CFLAGS -c -o data.o path/to/gnu-efi/lib/data.c
clang $LDFLAGS -o BOOTX64.EFI hello.o data.o
</syntaxhighlight>
 
Passing '--target x86_64-unknown-windows' to clang tells it to compile for x86_64 "Windows". This is quite not the same as 64-bit UEFI PE yet, but as before the "freestanding" part makes it a good kernel image. An example of this toolchain is found in the [https://github.com/c-util/c-efi c-efi] project.
 
Note the '-mno-red-zone' part used here as well -- it is a [https://stackoverflow.com/questions/25787408/why-cant-kernel-code-use-a-red-zone bad idea] to use a red zone for kernel code if interrupts are to be implemented. It should be done with GCC as well, but read [[Libgcc without red zone]] for the extra work needed to be done.
 
== Creating the FAT image ==
{{Main|Bootable Disk}}
 
Next, you will need to create a FAT filesystem image.
<syntaxhighlight lang="bash">
<source lang="bash">dd if=/dev/zero of=fat.img bs=1k count=1440
mformat -i fat.img -f 1440 ::
mmd -i fat.img ::/EFI
mmd -i fat.img ::/EFI/BOOT
mcopy -i fat.img BOOTX64.EFI ::/EFI/BOOT</source>
</syntaxhighlight>
 
Now, we can either use this as a USB stick image directly or embed it in HD image or CD image.
 
=== Running as a USB stick image ===
 
YouThe FAT image can either writebe itwritten directly to a USB stick and useused in in a UEFI machine, or it can be run itdirectly in qemuQEMU:
 
<sourcesyntaxhighlight lang="bash">qemu-system-x86_64 -L OVMF_dir/ -biospflash OVMF.fd -usb -usbdevice disk::fat.img</sourcesyntaxhighlight>
 
=== Creating and running the HD image ===
Line 94 ⟶ 133:
The HD image is a disk image in the [[GPT]] format, with the FAT image specially identified as a 'EFI System Partition'.
 
<sourcesyntaxhighlight lang="bash">mkgpt -o hdimage.bin --image-size 4096 --part fat.img --type system
qemu-system-x86_64 -L OVMF_dir/ -biospflash OVMF.fd -hda hdimage.bin</sourcesyntaxhighlight>
 
=== Creating and running the CD image ===
The isoISO image is a standard ISO9660 image which contains ourthe FAT image as a file. A special El Torito option (-e) then points EFI aware systems to this image to be loaded. The YouCD image can either burnbe the CD imageburned to a CD and run itran in a UEFI machine, or run itdirectly in qemuQEMU:
<sourcesyntaxhighlight lang="bash">mkdir iso
cp fat.img iso
xorriso -as mkisofs -R -f -e fat.img -no-emul-boot -o cdimage.iso iso
qemu-system-x86_64 -L OVMF_dir/ -biospflash OVMF.fd -cdrom cdimage.iso</sourcesyntaxhighlight>
 
== What to do next? ==
 
YouDevelopers may want to try using some more of the EFI boot services, e.g., to [[Loading files under UEFI|read more files]] from yourthe FAT image, manage memory, set up [[GOP|graphical frame buffer]] etc. (see the [http://www.uefi.org/specifications UEFI Specifications] page for further documentation of this).
 
There is also a finished app bare bone which supports both Linux and Windows (Visual Studio), see [https://github.com/pbatard/uefi-simple uefi-simple].
 
== Common problems ==
 
Some UEFI hardware implementations require that the FAT image is in the FAT32 format (rather than FAT12 or FAT16). OVMF does not have this limitation, so youdevelopers will not see such a problem in qemuQEMU. However, Thethe minimum size of a FAT32 filesystem is, however, around 32 MiB, so youdevelopers will need to generate a much biggerlarger image and pass the '-F' option to mformat.
 
== See also ==
 
* [[UEFI]]
* [[UEFI ISO Bare Bones]]
* [[GNU-EFI]]
* [[POSIX-UEFI]]
 
[[Category:Bare bones tutorials]]
[[Category:Firmware]]
[[Category:UEFI]]