UEFI: Difference between revisions

From OSDev Wiki
Jump to navigation Jump to search
(179 intermediate revisions by 45 users not shown)
Line 1: Line 1:
(削除) {{Stub}} (削除ここまで)
(追記) (U)EFI or (Unified) Extensible Firmware Interface is a specification for x86, x86-64, ARM, and Itanium platforms that defines a software interface between the operating system and the platform firmware/BIOS. The original EFI was developed in the mid-1990s by Intel for use developing firmware/BIOS for Itanium platforms. In 2005 Intel transitioned the specification to a new working group called the Unified EFI Forum, consisting of companies such as AMD, Microsoft, Apple, and Intel itself. All modern PCs ship with UEFI firmware and UEFI is widely supported by both commercial and open source operating systems. Backwards compatibility is provided for legacy operating systems. (追記ここまで)


== (削除) Introduction (削除ここまで)==
== (追記) UEFI basics (追記ここまで)==


(削除) (U)EFI or (Unified) Extensible Firmware Interface (削除ここまで)is (削除) a specification that defines a software interface between the operating system(s) and the platform's firmware. In the mid 90s Intel was creating a new processor architecture that was 64-bit (削除ここまで), (削除) but wasn't backwards-compatible with (削除ここまで)the (削除) old x86 (削除ここまで). (削除) This architecture was (削除ここまで)the (削除) Itanium 64. Because the IA-64 only supports 64-bit instructions, the PC BIOS couldn (削除ここまで)'(削除) t be used, therefore Intel developed the (削除ここまで)EFI (削除) specification. Later on this specification was managed (削除ここまで)((削除) and still is (削除ここまで)) (削除) by the UEFI board, an association of several companies such as AMD, Microsoft, Intel, Apple and so on (削除ここまで).
(追記) ===Downloading UEFI images=== (追記ここまで)
(追記) If you choose [[VirtualBox]] for virtualization, then UEFI (追記ここまで)is (追記) already included (追記ここまで), (追記) no need to download (追記ここまで)the (追記) image manually (追記ここまで). (追記) You just have to enable it in (追記ここまで)the (追記) VM (追記ここまで)'(追記) s preferences by clicking "Settings" / "Systems" / "Enable (追記ここまで)EFI ((追記) special OSes only (追記ここまで))(追記) " checkbox (追記ここまで).


== (削除) Support == (削除ここまで)
(追記) Otherwise for emulation and virtual machines, you'll need an OVMF.fd firmware image. It might be tricky to find, so here are some alternative download links too: (追記ここまで)
(追記) * [https://github.com/tianocore/tianocore.github.io/wiki/OVMF TianoCore Download] (official link) (追記ここまで)
(追記) * [https://github.com/BlankOn/ovmf-blobs OVMF-blobs] (unofficial precompiled 32 bit and 64 bit versions, easy to use) (追記ここまで)
(追記) * [https://www.kraxel.org/repos/ RPM packages] (official TianoCore packages) (追記ここまで)
(追記) * [https://packages.debian.org/sid/ovmf Debian packages] (追記ここまで)
(追記) * [https://packages.gentoo.org/useflags/ovmf Gentoo packages] (追記ここまで)
(追記) * [https://aur.archlinux.org/packages?O (追記ここまで)=(追記) 0&K (追記ここまで)=(追記) ovmf Arch packages] (追記ここまで)


(削除) The (U)EFI specification is currently defined for the Itanium platform (削除ここまで), (削除) the x86-platform (64-bit included) and the ARM platform. Since Apple (削除ここまで)'s (削除) movement with Mac OS X from the PowerPC architecture to the x86-architecture, they have been using EFI, although with minor differences here and there. Most modern operating systems, boot loaders and boot managers support (U)EFI as well nowadays. Most 64-bit versions of Microsoft Windows (削除ここまで), (削除) FreeBSD, Apple Mac OS X and Linux all have support (削除ここまで)for (削除) UEFI to some extent. As for boot loaders and managers you generally have (E)GRUB and ELILO. As for emulators and virtual machines, you can generally use VirtualBox and Qemu. (削除ここまで)
(追記) Under Linux (追記ここまで), (追記) you can also install these with your distro (追記ここまで)'s (追記) package manager (追記ここまで), for (追記) example: (追記ここまで)


== (削除) Developing (削除ここまで)for ((削除) U (削除ここまで))EFI ==
(追記) '''Debian / Ubuntu''' (追記ここまで)
(追記) <source lang (追記ここまで)=(追記) "bash"> (追記ここまで)
(追記) # apt-get install ovmf (追記ここまで)
(追記) </source> (追記ここまで)
(追記) '''RedHat / CentOS''' (追記ここまで)
(追記) <source lang (追記ここまで)=(追記) "bash"> (追記ここまで)
(追記) # yum install ovmf (追記ここまで)
(追記) </source> (追記ここまで)
(追記) '''MacOS''' (追記ここまで)
(追記) Use the OVMF-blobs repo. (追記ここまで)
(追記) '''Windows''' (追記ここまで)
(追記) Use the OVMF-blobs repo or download the RPM version, then use ''7-Zip File Manager'' to extract the OVMF.fd file from the downloaded archive. (追記ここまで)
(追記) ===UEFI vs. legacy BIOS=== (追記ここまで)
(追記) A common misconception is that UEFI and BIOS are mutually exclusive. In reality, both legacy motherboards and UEFI-based motherboards both include BIOS ROMs. The differences are in where they find the bootloader/OS, how they prepare the system before executing it, and what convenience functions they provide. (追記ここまで)
(追記) ====Platform initialization==== (追記ここまで)
(追記) On a legacy system, the [[BIOS]] performs all the usual platform initialization (memory controller configuration, [[PCI]] bus configuration and BAR mapping, graphics card initialization, etc.), but then drops into a backwards-compatible [[Real Mode|real mode]] environment. The bootloader must enable the [[A20 Line|A20 gate]], configure a [[GDT]] and an [[IDT]], switch to [[protected mode]], and for x86-64 CPUs, configure paging and switch to [[x86-64|long mode]]. (追記ここまで)
(追記) UEFI firmware performs those same steps, but it also enables the A20 gate and prepares either protected mode environment with flat [[segmentation]] ( (追記ここまで)for (追記) 32-bit x86 processors) or a long mode environment with identity-mapped paging (追記ここまで)((追記) for x86-64 processors (追記ここまで))(追記) . (追記ここまで)
(追記) Additionally, the platform initialization procedure of UEFI firmware is standardized. This allows UEFI firmware to be extended in a vendor-neutral way. (追記ここまで)
(追記) ====Boot mechanism==== (追記ここまで)
(追記) A legacy BIOS loads a 512 byte flat binary blob from the [[MBR]] of the boot device into memory at physical address 0x7C00 and jumps to it. The bootloader can return back to the BIOS through INT 0x18. On the other hand, UEFI firmware loads an arbitrary sized UEFI application (a relocatable [[PE]] executable file) from a [[FAT]] partition on a [[GPT]] or MBR partitioned boot device to some address selected at run-time. Then it calls that application's main entry point. The application can return control to the firmware, which will continue searching for another boot device or bring up a diagnostic menu. (追記ここまで)
(追記) ====System discovery==== (追記ここまで)
(追記) A legacy bootloader scans memory for structures like the [[EBDA]], [[SMBIOS]], and [[ACPI]] tables. It uses PIO to talk to the root [[PCI]] controller and scan the PCI bus. It is possible that redundant tables may be present in memory (for example, the [[MP_Specification|MP]] table in the SMBIOS contains information that's also present in the ACPI [[DSDT]] and [[MADT]]) and the bootloader can choose which to use. (追記ここまで)
(追記) When UEFI firmware calls a UEFI application's entry point function, it passes a "System Table" structure, which contains pointers to all of the system's ACPI tables, memory map, and other information relevant to an OS. Legacy tables (like MP tables) may not be present in memory. (追記ここまで)
(追記) ====Convenience functions==== (追記ここまで)
(追記) A legacy BIOS hooks a variety of interrupts which a bootloader can trigger to access system resources like disks and the screen. These interrupts are not standardized, except by historical convention. Each interrupt uses a different register passing convention. (追記ここまで)
(追記) UEFI firmware establishes many callable functions in memory, which are grouped into sets called "protocols" and are discoverable through the System Table. The behavior of each function in each protocol is defined by specification. UEFI applications can define their own protocols and persist them in memory for other UEFI applications to use. Functions are called with a standardized, modern calling convention supported by many C compilers. (追記ここまで)
(追記) ====Development environment==== (追記ここまで)
(追記) Legacy bootloaders can be developed in any environment that can generate flat binary images: NASM, GCC, etc. UEFI applications can be developed in any language that can be compiled and linked into a [[PE]] executable file and supports the calling convention used to access functions established in memory by the UEFI firmware. In practice this means one of three development environments: EDK2, GNU-EFI or POSIX-UEFI. (追記ここまで)
(追記) [[EDK2]] is a large and complex, yet feature filled environment with its own build system. It can be configured to use GCC, LLVM, MinGW, Microsoft Visual C++, etc. as a cross-compiler. Not only can it be used to compile UEFI applications, but it can also be used to compile UEFI firmware to be flashed to a BIOS ROM. (追記ここまで)
(追記) [[GNU- (追記ここまで)EFI(追記) ]] is a set of libraries and headers for compiling UEFI applications with a system's native GCC (does not work with LLVM CLang). It can't be used to compile UEFI firmware. Since it's just a couple of libraries against which a UEFI application can be linked, it is much easier to use than TianoCore ( EDK2 ). (追記ここまで)
(追記) [[POSIX-UEFI]] is very similar to GNU-EFI, but it is distributed mainly as a source, not as a binary library, has ANSI C like names and works with GCC as well as LLVM CLang. It's shipped with a Makefile that sets up the compiler flags for you. (追記ここまで)
(追記) ====Emulation==== (追記ここまで)
(追記) [[OVMF]], a popular open source UEFI firmware, has been ported to the QEMU (but not Bochs) emulated machine. Because it implements the UEFI specification, it behaves very similarly to commercial UEFI firmware on real machines. (OVMF itself is built with TianoCore, and its source ship with it as well, but pre-built images are available.) (追記ここまで)
(追記) ===Legacy bootloader or UEFI application?=== (追記ここまで)
(追記) If you are targeting legacy systems for which UEFI is not available or is not reliable, you should develop a legacy bootloader. This requires intimate knowledge of 16-bit addressing and the backwards-compatibility features of an x86 or x86-64 CPU. If you are targeting modern systems you should develop a UEFI application. Many UEFI firmwares can be configured to emulate a legacy BIOS, but there is even more variation among these emulated environments than among real legacy BIOS. (追記ここまで)
(追記) Although there is a slight learning curve to become familiar with the UEFI development environments, using the System Table, and accessing UEFI-provided protocols (functions), there are far fewer "gotchas" than trying to remain compatible with the wide variety of quickly-becoming-obsolete legacy BIOSs on real machines. UEFI is the standard for all modern PCs. (追記ここまで)
(追記) ===UEFI class 0-3 and CSM (追記ここまで)==(追記) = (追記ここまで)
(追記) PCs are categorized as UEFI class 0, 1, 2, or 3. A class 0 machine is a legacy system with a legacy BIOS; i.e. not a UEFI system at all. (追記ここまで)
(追記) A class 1 machine is a UEFI system that runs exclusively in Compatibility Support Module (CSM) mode. CSM is a specification for how UEFI firmware can emulate a legacy BIOS. UEFI firmware in CSM mode loads legacy bootloaders. A class 1 UEFI system may not advertise UEFI support at all, since it isn't exposed to the bootloader. It's only UEFI "within" the BIOS. (追記ここまで)
(追記) A class 2 machine is a UEFI system that can launch UEFI applications but also includes the option to run in CSM mode. The majority of modern PCs are UEFI class 2 machines. Sometimes the choice to run UEFI applications vs. CSM is a one-or-the-other setting in the BIOS configuration, and other times the BIOS will decide which to use after selecting the boot device and checking whether it has a legacy bootloader or a UEFI application. (追記ここまで)
(追記) A class 3 machine is a UEFI system that does not support CSM. UEFI class 3 machines only run UEFI applications and do not implement CSM for backwards compatibility with legacy bootloaders. (追記ここまで)
(追記) ===Secure Boot=== (追記ここまで)
(追記) Secure Boot is a digital signature scheme for UEFI applications that consists of four components: (追記ここまで)
(追記) * '''PK''': Platform Key (追記ここまで)
(追記) * '''KEK''': Key Exchange Keys (追記ここまで)
(追記) * '''db''': Whitelist database (追記ここまで)
(追記) * '''dbx''': Blacklist database (追記ここまで)
(追記) UEFI firmware that supports Secure Boot is always in one of three states: (追記ここまで)
(追記) * Setup mode, Secure Boot ''off'' (追記ここまで)
(追記) * User mode, Secure Boot ''off'' (追記ここまで)
(追記) * User mode, Secure Boot ''on'' (追記ここまで)
(追記) In setup mode, any UEFI application can change or delete the PK, add/remove keys from the KEK, and add/remove whitelist or blacklist entries from the db or dbx. (追記ここまで)
(追記) In user mode, regardless of whether Secure Boot is on or off: (追記ここまで)
(追記) * The PK may only be changed or deleted by a UEFI application that already has the current PK. (追記ここまで)
(追記) * Keys can only be added/removed from the KEK by a UEFI application that has the PK. (追記ここまで)
(追記) * Whitelist and blacklist entries can only be added/removed from the db and dbx by a UEFI application that has any one of the keys in the KEK. (追記ここまで)
(追記) Finally, in user mode with Secure Boot ''on'', UEFI applications must meet one of the following four requirements to be launched: (追記ここまで)
(追記) * Signed, with signature in db and not in dbx (追記ここまで)
(追記) * Signed by a key in db and not in dbx (追記ここまで)
(追記) * Signed by a key in the KEK (追記ここまで)
(追記) * Unsigned, but a hash of the application is in db and not in dbx (追記ここまで)
(追記) Note that UEFI applications are not signed by the PK, unless the PK also happens to be in the KEK. (追記ここまで)
(追記) Not all UEFI firmwares support Secure Boot, although it is a requirement for Windows 8. Some UEFI firmwares support Secure Boot and there's no option to be disabled, which poses a problem for independent developers that do not have access to the PK or any of the keys in the KEK, and therefore can't install their own key or application signature or hash to the whitelist database. Independent developers should develop on systems that either do not support Secure Boot or has an option for Secure Boot to be turned off. (追記ここまで)
(追記) An easy way out to use a loader that is signed by Microsoft, and allows you to load another binary signed by a key and certificate owned by you (called MOK, Machine Owner's Key). Such a loader is [https://github.com/rhboot/shim shim], used by RedHat, Fedora, Suse, Ubuntu, Arch and many other distros to load GRUB. The filename of the EFI executable is hardwired in shim, but if you rename your loader to GRUBX64.EFI (or GRUBIA32.EFI), you sign it with your MOK key and certificate using [https://github.com/imedias/sbsigntool sbsigntool], then you can load any loader in Secure Boot you want. (追記ここまで)


(削除) One can develop applications, boot loaders or drivers for (U)EFI if he/she has the required hardware or software (削除ここまで)to (削除) develop for it. As said before you can (削除ここまで)use (削除) VirtualBox (削除ここまで)and (削除) Qemu as both of them seem to (削除ここまで)have a (削除) (U)EFI implementation (削除ここまで)of (削除) some sort (削除ここまで). (削除) Another option is to use Intel's TianoCore (削除ここまで), (削除) which is supposedly (削除ここまで)their (削除) own (U)EFI firmware interface implementation (削除ここまで)to run (削除) on top of the PC BIOS and/or as a Coreboot payload. The simplest way is by getting the right hardware. Generally there are several motherboards available that have an (U)EFI implementation, sometimes with a PC BIOS implementation next to it (削除ここまで). (削除) Below is a list of noticeable BIOS companies: (削除ここまで)
(追記) ===How (追記ここまで)to use (追記) UEFI=== (追記ここまで)
(追記) Traditional operating systems like Windows (追記ここまで)and (追記) Linux (追記ここまで)have (追記) an existing software architecture and (追記ここまで)a (追記) large code base to perform system configuration and device discovery. With their sophisticated layers (追記ここまで)of (追記) abstraction they don't directly benefit from UEFI (追記ここまで). (追記) As a result (追記ここまで), their (追記) UEFI bootloaders do little but prepare the environment for them (追記ここまで)to run.


(削除) * AMI (Aptio) (削除ここまで).
(追記) An independent developer may find more value in using UEFI to write feature-full UEFI applications, rather than viewing UEFI as a temporary start-up environment to be jettisoned during the boot process (追記ここまで). (追記) Unlike legacy bootloaders (追記ここまで), (追記) which typically interact with BIOS only enough to bring up the OS (追記ここまで), (追記) a UEFI application can implement sophisticated behavior with the help of UEFI (追記ここまで). (追記) In other words, an independent developer shouldn't be in a rush to leave "UEFI-land" (追記ここまで).
(削除) * Phoenix (SecureCore (削除ここまで), (削除) TrustedCore (削除ここまで), (削除) AwardCore) (削除ここまで).
(削除) * Insyde (InsydeH20) (削除ここまで).


(削除) Apple macs are also well known (削除ここまで)to (削除) implement UEFI 1 (削除ここまで).(削除) 0 (not 2 (削除ここまで).(削除) 0) (削除ここまで)
(追記) A good starting point is writing a UEFI application that uses the System Table (追記ここまで)to (追記) fetch a memory map, and uses the "File" protocol to read files from FAT-formatted disks (追記ここまで). (追記) The next step might be to use the System Table to locate ACPI tables (追記ここまで).
(削除) == Tools == (削除ここまで)


(削除) The (U)EFI Development Kit, the (U)EFI Toolkit and the (U)EFI specifications might be interesting to use. As for writing actual (U)EFI software you can use several compilers such as GCC and Microsoft Visual Studio for C and FASM for Assembly. The (U)EFI Toolkit might be interesting when using a C compiler, as it contains several C/C++ headers. (削除ここまで)
(追記) ==Developing with POSIX-UEFI== (追記ここまで)
(追記) :''Main article: [[POSIX-UEFI]] (追記ここまで)


(削除) Note that the C language (削除ここまで)is (削除) incompatible with EBC ( (削除ここまで)EFI (削除) Byte Code) (削除ここまで)and (削除) thus (削除ここまで)a (削除) special compiler supporting (削除ここまで)the (削除) EFI C dialect is required (削除ここまで). GCC is (削除) not one such compiler (削除ここまで).
(追記) One option to compile UEFI applications on POSIX like systems (追記ここまで)is (追記) POSIX-UEFI. It provides a [[libc]]-like API for your (追記ここまで)EFI (追記) application, (追記ここまで)and (追記) ships with (追記ここまで)a (追記) Makefile that can detect and set up (追記ここまで)the (追記) toolchain for you (追記ここまで). (追記) It can use (追記ここまで)GCC (追記) or LLVM, and defaults to using the host compiler, but a cross compiler (追記ここまで)is (追記) still recommended (追記ここまで).


== (削除) Booting = (削除ここまで)=
(追記) It uses POSIX style typedefs (like ''uintn_t'' instead of ''UINTN''), and it does not ship with the standard EFI headers. You can still get interfaces not covered by POSIX-UEFI (such as GOP) by installing the EFI headers from GNU-EFI or EDK2. Also, it compiles with the MS ABI, meaning that UEFI services can be called natively (i.e., without uefi_call_wrapper) so long as your apps are compiled with it as well. (追記ここまで)
(追記) The traditional "Hello, world" UEFI program goes like this. (追記ここまで)
(追記) <source lang (追記ここまで)=(追記) "c"> (追記ここまで)
(追記) #include <uefi.h> (追記ここまで)
(追記) (追記ここまで)
(追記) int main (int argc, char **argv) (追記ここまで)
(追記) { (追記ここまで)
(追記) printf("Hello, world!\n"); (追記ここまで)
(追記) return 0; (追記ここまで)
(追記) } (追記ここまで)
(追記) </source> (追記ここまで)
(追記) Makefile looks like this: (追記ここまで)
(追記) <source lang (追記ここまで)=(追記) "make"> (追記ここまで)
(追記) TARGET (追記ここまで)= (追記) main.efi (追記ここまで)
(追記) include uefi/Makefile (追記ここまで)
(追記) </source> (追記ここまで)
(追記) Run make to build it. The result of this process is a PE executable file ''main.efi''. (追記ここまで)


(削除) The (U) (削除ここまで)EFI (削除) system does not look for a boot sector, instead it looks for a file located on a (削除ここまで)[[(削除) FAT (削除ここまで)]] (削除) formatted disk. The system looks for a file in an approved directory. For the most part all (U)EFI implementations look for the file /EFI/BOOT/BOOTX64.EFI. In the case of Apple, apple has modified the firmware to support HFS+. In apple computers a file is "Blessed" with the ability to boot from a certain file. (削除ここまで)
(追記) ==Developing with GNU- (追記ここまで)EFI(追記) == (追記ここまで)
(追記) :''Main article: (追記ここまで)[[(追記) GNU-EFI (追記ここまで)]]


(削除) == Using (削除ここまで)GNU (削除) toolchain for compiling (削除ここまで)and (削除) debugging (削除ここまで)EFI applications (削除) == (削除ここまで)
GNU(追記) -EFI can be used to develop both 32-bit and 64-bit UEFI applications. This section will address 64-bit UEFI applications only, (追記ここまで)and (追記) assumes that the development environment itself is running on an x86_64 system, so that no cross-compiler is needed. For a more thorough walk-through of a proper (non-gnu-efi) development environment, see [[UEFI App Bare Bones]]. (追記ここまで)
(追記) (追記ここまで)
(追記) GNU- (追記ここまで)EFI (追記) includes four things: (追記ここまで)
(追記) * '''crt0-efi-x86_64.o''': A CRT0 (C runtime initialization code) that provides an entry point that UEFI firmware will call when launching the application, which will in turn call the "efi_main" function that the developer writes. (追記ここまで)
(追記) * '''libgnuefi.a''': A library containing a single function (''_relocate'') that is used by the CRT0. (追記ここまで)
(追記) * '''elf_x86_64_efi.lds''': A linker script used to link ELF binaries into UEFI (追記ここまで)applications(追記) . (追記ここまで)
(追記) * '''efi.h''' and other headers: Convenience headers that provide structures, typedefs, and constants improve readability when accessing the System Table and other UEFI resources. (追記ここまで)
(追記) * '''libefi.a''': A library containing convenience functions like CRC computation, string length calculation, and easy text printing. (追記ここまで)
(追記) * '''efilib.h''': Header for ''libefi.a''. (追記ここまで)


(削除) GNU development toolchain consist of binutils package (assembler (削除ここまで), linker(削除) , various utilities for manipulating executable images), GCC compiler, GNU make (削除ここまで)and (削除) GDB debugger. Advantages are obvious - build system is very flexible, (削除ここまで)the (削除) tools have very rich functionality (削除ここまで), (削除) they are free (削除ここまで)and (削除) open source, your EFI application code can be easily integrated to any project. Most of open source software prefers (削除ここまで)this (削除) way (削除ここまで).
(追記) At a bare minimum (追記ここまで), (追記) a 64-bit UEFI application will need to link against ''crt0-efi-x86_64.o'' and ''libgnuefi.a'' using the ''elf_x86_64_efi.lds'' (追記ここまで)linker (追記) script. Most likely you will want to use the provided headers (追記ここまで)and the (追記) convenience library as well (追記ここまで), and this (追記) section will assume that going forward (追記ここまで).


The (削除) first step (削除ここまで)is (削除) to (削除ここまで)compile (削除) your tools with required options (削除ここまで). (削除) Firstly you need (削除ここまで)to compile (削除) binutils package. Obtain (削除ここまで)the (削除) latest from http://ftp (削除ここまで).(削除) gnu.org/gnu/binutils/. You (削除ここまで)will need to (削除) enable (削除ここまで)"(削除) i386-efi-pe (削除ここまで)" (削除) target to have support for EFI PE+ executable format (削除ここまで). (削除) If you use the same toolchain for compiling something else (削除ここまで)in (削除) your project (e (削除ここまで).(削除) g (削除ここまで). (削除) OS kernel) you can also specify required target (e (削除ここまで).(削除) g (削除ここまで). (削除) x86_64 (削除ここまで)-(削除) myOS (削除ここまで)-(削除) freebsd (削除ここまで)) (削除) Note that it (削除ここまで)is (削除) BFD target, not the target platform. If you want to develop for 64-bits platform add "--enable-64-bit-bfd" options to "configure" script (削除ここまで).
The (追記) traditional "Hello, world" UEFI program (追記ここまで)is (追記) shown below. (追記ここまで)
(追記) <source lang="c"> (追記ここまで)
(追記) #include <efi.h> (追記ここまで)
(追記) #include <efilib.h> (追記ここまで)
(追記) EFI_STATUS (追記ここまで)
(追記) EFIAPI (追記ここまで)
(追記) efi_main (EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) (追記ここまで)
(追記) { (追記ここまで)
(追記) InitializeLib(ImageHandle, SystemTable); (追記ここまで)
(追記) Print(L"Hello, world!\n"); (追記ここまで)
(追記) return EFI_SUCCESS; (追記ここまで)
(追記) } (追記ここまで)
(追記) </source> (追記ここまで)
(追記) A few notes: (追記ここまで)
(追記) * efi.h is included so we can use types like EFI_STATUS, EFI_HANDLE, and EFI_SYSTEM_TABLE. (追記ここまで)
(追記) * When creating a 32-bit UEFI application, EFIAPI is empty; GCC will (追記ここまで)compile (追記) the "efi_main" function using the standard C calling convention (追記ここまで). (追記) When creating a 64-bit UEFI application, EFIAPI expands (追記ここまで)to (追記) "__attribute__((ms_abi))" and GCC will (追記ここまで)compile the (追記) "efi_main" function using Microsoft's x64 calling convention, as specified by UEFI (追記ここまで). (追記) Only functions that (追記ここまで)will (追記) be called directly from UEFI (including main, but also callbacks) (追記ここまで)need to (追記) use the UEFI calling convention. (追記ここまで)
(追記) * "InitializeLib (追記ここまで)" (追記) and "Print (追記ここまで)" (追記) are convenience functions provided by libefi (追記ここまで).(追記) a with prototypes (追記ここまで)in (追記) efilib (追記ここまで).(追記) h (追記ここまで). (追記) "InitializeLib" lets libefi (追記ここまで).(追記) a store a reference to the ImageHandle and SystemTable provided by BIOS (追記ここまで). (追記) "Print" uses those stored references to print a string by reaching out to UEFI (追記ここまで)-(追記) provided functions in memory. (Later on we will see how to find and call UEFI (追記ここまで)-(追記) provided functions manually. (追記ここまで))
(追記) This program (追記ここまで)is (追記) compiled and linked as below (追記ここまで).
<source lang="bash">
<source lang="bash">
../(削除) src (削除ここまで)/(削除) configure (削除ここまで)--(削除) prefix=$PREFIX (削除ここまで)--(削除) target=$TARGET (削除ここまで)--(削除) disable (削除ここまで)-(削除) nls (削除ここまで)--(削除) build= (削除ここまで)$(削除) BUILD (削除ここまで)--(削除) enable (削除ここまで)-(削除) 64 (削除ここまで)-(削除) bit (削除ここまで)-(削除) bfd (削除ここまで)\
(追記) $ gcc main (追記ここまで).(追記) c \ (追記ここまで)
(削除) (削除ここまで)--(削除) enable (削除ここまで)-(削除) targets (削除ここまで)=(削除) i386 (削除ここまで)-(削除) efi (削除ここまで)-(削除) pe, (削除ここまで)x86_64(削除) -phoenix-freebsd (削除ここまで)
(追記) -c \ (追記ここまで)
(追記) -fno-stack-protector \ (追記ここまで)
(追記) -fpic \ (追記ここまで)
(追記) -fshort-wchar \ (追記ここまで)
(追記) -mno-red-zone \ (追記ここまで)
(追記) -I /path/to/gnu-efi/headers \ (追記ここまで)
(追記) -I /path/to/gnu-efi/headers/x86_64 \ (追記ここまで)
(追記) -DEFI_FUNCTION_WRAPPER \ (追記ここまで)
(追記) -o main.o (追記ここまで)
(追記) $ ld main (追記ここまで).(追記) o \ (追記ここまで)
(追記) (追記ここまで)/(追記) path (追記ここまで)/(追記) to/crt0 (追記ここまで)-(追記) efi (追記ここまで)-(追記) x86_64.o \ (追記ここまで)
(追記) -nostdlib \ (追記ここまで)
(追記) (追記ここまで)-(追記) znocombreloc \ (追記ここまで)
(追記) (追記ここまで)-(追記) T /path/to/elf_x86_64_efi.lds \ (追記ここまで)
(追記) -shared \ (追記ここまで)
(追記) (追記ここまで)-(追記) Bsymbolic \ (追記ここまで)
(追記) (追記ここまで)-(追記) L /path/to/libs \ (追記ここまで)
(追記) (追記ここまで)-(追記) l:libgnuefi.a \ (追記ここまで)
(追記) (追記ここまで)-(追記) l:libefi.a \ (追記ここまで)
(追記) (追記ここまで)-(追記) o main.so (追記ここまで)
$ (追記) objcopy -j .text \ (追記ここまで)
(追記) -j .sdata \ (追記ここまで)
(追記) (追記ここまで)-(追記) j .data \ (追記ここまで)
(追記) (追記ここまで)-(追記) j .rodata \ (追記ここまで)
(追記) (追記ここまで)-(追記) j .dynamic \ (追記ここまで)
(追記) -j .dynsym \ (追記ここまで)
(追記) (追記ここまで)-(追記) j .rel \ (追記ここまで)
(追記) (追記ここまで)-(追記) j .rela (追記ここまで)\
(追記) (追記ここまで)-(追記) j .reloc \ (追記ここまで)
(追記) (追記ここまで)--(追記) target (追記ここまで)=(追記) efi (追記ここまで)-(追記) app (追記ここまで)-x86_64 (追記) \ (追記ここまで)
(追記) main.so \ (追記ここまで)
(追記) main.efi (追記ここまで)
</source>
</source>
(削除) Here and below $PREFIX variable points to your prefix where you want to install your build tools (e.g. "export PREFIX=/home/John/projects/myOS/build-tools") and $TARGET is you target platform (e.g. "x86_64-myOS-elf"). After that execute "make" and "make install" commands to build and install the package. (削除ここまで)


(削除) If your (削除ここまで)build (削除) machine has not the same architecture as target platform you will (削除ここまで)need a cross compiler. (削除) There (削除ここまで)are [(削除) [GCC_Cross (削除ここまで)-(削除) Compiler|instructions about compiling GCC]] (削除ここまで)for (削除) cross platform development (削除ここまで). (削除) Just use binutils compiled above (削除ここまで)with (削除) these (削除ここまで)instructions.
(追記) The result of this process is a 44 kB PE executable file ''main.efi''. On a real project you'll probably want to use make or another (追記ここまで)build (追記) tool, and may (追記ここまで)need (追記) to build (追記ここまで)a cross(追記) - (追記ここまで)compiler. (追記) The way GNU-EFI works is a bit contrived: you (追記ここまで)are (追記) wrapping an ELF file built by your normal compiler into PE. (追記ここまで)
(追記) ==Emulation with QEMU and OVMF== (追記ここまで)
(追記) Any recent version of QEMU with a recent version of OVMF will be sufficient to run a UEFI application. QEMU binaries are available for many platforms, and a binary OVMF image (OVMF.fd) can be found on the (追記ここまで)[(追記) http://www.tianocore.org/ovmf/ TianoCore] website. QEMU (without any boot disk) can be invoked as below. (To prevent recent versions of QEMU from attempting a PXE (network) boot when no boot disk is found, use <code> (追記ここまで)-(追記) net none</code>. (追記ここまで)
(追記) The recommended way to use OVMF ( (追記ここまで)for (追記) QEMU 1 (追記ここまで).(追記) 6 or newer) is (追記ここまで)with (追記) a <code>pflash</code> parameter. The (追記ここまで)instructions (追記) below assume you have an OVMF image split into separate CODE and VARS sections (追記ここまで).


(削除) You will need a debugger for debugging your applications. Obtain it from http://ftp.gnu.org/gnu/gdb/ and compile: (削除ここまで)
<source lang="bash">
<source lang="bash">
(削除) ./configure (削除ここまで)--(削除) prefix=$PREFIX (削除ここまで)--(削除) target (削除ここまで)=(削除) $TARGET (削除ここまで)--(削除) enable-64-bit-bfd (削除ここまで)
(追記) $ qemu (追記ここまで)-(追記) system (追記ここまで)-(追記) x86_64 (追記ここまで)-(追記) cpu qemu64 \ (追記ここまで)
(追記) (追記ここまで)-(追記) drive if=pflash,format=raw,unit=0,file=path_to_OVMF_CODE.fd,readonly (追記ここまで)=(追記) on \ (追記ここまで)
(追記) (追記ここまで)-(追記) drive if=pflash,format=raw,unit=1,file=path_to_OVMF_VARS.fd \ (追記ここまで)
(追記) (追記ここまで)-(追記) net none (追記ここまで)
</source>
</source>


(削除) Now (削除ここまで)you (削除) are ready (削除ここまで)to (削除) compile your first EFI application. Download gnu-efi package from https: (削除ここまで)/(削除) /sourceforge.net/projects/gnu-efi/ and read its README files. Follow the instructions there (削除ここまで), (削除) check Makefiles are pointing to your build tools and have correct architecture specified. Run "make" command and (削除ここまで)you will (削除) get several sample applications in "apps" directory. We will describe how (削除ここまで)to run (削除) them a bit later but for now you need to examine (削除ここまで)the (削除) build log and notice all commands which where executed and all required options for them (削除ここまで). (削除) This will be a basis for your Makefile if you will wish to integrate EFI application to your project. Several advices: (削除ここまで)
(追記) If (追記ここまで)you (追記) prefer (追記ここまで)to (追記) work on a terminal without a display, or via SSH (追記ここまで)/(追記) telnet (追記ここまで), you will (追記) want (追記ここまで)to run (追記) QEMU without graphics support, using (追記ここまで)the (追記) <code>-nographic</code> flag (追記ここまで).
(削除) * (削除ここまで)If (削除) you build (削除ここまで)a (削除) single binary in your project (削除ここまで)((削除) e.g. OS loader (削除ここまで)) (削除) you (削除ここまで)will (削除) not need to make static libraries like it is done in the gnu-efi package (削除ここまで). (削除) Just compile all required C and Assembler file and link them together in the final executable (削除ここまで)file.
(削除) * If you project has only one target platform you (削除ここまで)can (削除) throw away unnecessary source files (削除ここまで). (削除) Just select for gnu-efi build log all files which where compiled and throw away all the others (削除ここまで).
If (追記) OVMF does not find a boot disk with (追記ここまで)a (追記) properly named UEFI application (追記ここまで)((追記) more on this later (追記ここまで)) (追記) it (追記ここまで)will (追記) drop into a UEFI shell (追記ここまで).
(削除) [ (削除ここまで)http://(削除) ast-phoenix (削除ここまで).(削除) git (削除ここまで).(削除) sourceforge.net (削除ここまで)/(削除) git (削除ここまで)/(削除) gitweb.cgi?p=ast (削除ここまで)-(削除) phoenix/ast (削除ここまで)-(削除) phoenix;a=tree;f=kernel/boot;h=646835063c1362732f209c1312ce0d2ba7b558a5;hb=HEAD Here (削除ここまで)] (削除) is an example of (削除ここまで)the (削除) package integration. Pay attention to the Makefile. We will touch some its aspects later (削除ここまで).
(追記) [[ (追記ここまで)file(追記) :OVMF_shell (追記ここまで).(追記) png]] (追記ここまで)
(追記) You (追記ここまで)can (追記) find a list of shell commands [https://web (追記ここまで).(追記) archive (追記ここまで).(追記) org/web/20170504062623/ (追記ここまで)http://(追記) www (追記ここまで).(追記) sysadminshare (追記ここまで).(追記) com/2012 (追記ここまで)/(追記) 01 (追記ここまで)/(追記) efi (追記ここまで)-(追記) shell (追記ここまで)-(追記) commands.html here (追記ここまで)] (追記) or you can type ''help'' at (追記ここまで)the (追記) shell (追記ここまで).


(削除) Now we need to run the resulted application(s) and somehow debug it. Qemu virtual machine is a good choice because of its rich built-in debugging functionality. (削除ここまで)
(追記) ===Creating disk images=== (追記ここまで)
(追記) :''Main article: [[Bootable Disk]] (追記ここまで)


(削除) Download (削除ここまで)and (削除) compile (削除ここまで)it. (削除) Specify (削除ここまで)your (削除) target (削除ここまで)platform. (削除) You (削除ここまで)can (削除) use "- (削除ここまで)-(削除) enable-kvm" option to significantly increase emulation speed if you have Linux kernel and kvm package installed (削除ここまで).
(追記) To launch a UEFI application you will need to create a disk image (追記ここまで)and (追記) present (追記ここまで)it (追記) to QEMU (追記ここまで). (追記) UEFI firmware expects UEFI applications to be stored in a FAT12, FAT16, or FAT32 file system on a [[GPT]] or [[MBR]]-partitioned disk. Many firmwares only support FAT32, so that's what you'll want to use. Depending on (追記ここまで)your platform(追記) , there are several different ways to create a disk image containing your UEFI application, but they all start by creating a zeroed disk image file (追記ここまで). (追記) The minimum FAT32 partition size is 33,548,800 bytes, plus you will need space for the primary and secondary GPT tables, plus some slack space so the partition (追記ここまで)can (追記) be aligned correctly. Throughout these examples we will be creating a 48,000,000 byte (93750 512 (追記ここまで)-(追記) byte sectors, or 48 MB) disk image (追記ここまで).
<source lang="bash">
<source lang="bash">
.(削除) /configure --prefix (削除ここまで)=(削除) $PREFIX --target-list (削除ここまで)=(削除) x86_64-softmmu --enable-kvm (削除ここまで)
(追記) $ dd if=/dev/zero of=/path/to/uefi (追記ここまで).(追記) img bs (追記ここまで)=(追記) 512 count (追記ここまで)=(追記) 93750 (追記ここまで)
</source>
</source>
(削除) Qemu does not have EFI firmware so you need to download it separately. You can use OVMF firmware based on TianoCore from http://sourceforge.net/apps/mediawiki/tianocore/index.php?title=OVMF. Download 32 or 64 bits version depending on your target platform. Create some directory $YOUR_PREFIX/share/qemu/myOS and place there "vgabios-cirrus.bin" and "OVMF.fd" binaries from the OVMF package. (削除ここまで)


The (削除) last thing left (削除ここまで)is a (削除) disk (削除ここまで)image (削除) with (削除ここまで)EFI (削除) system partition and our (削除ここまで)application (削除) there. EFI requires GUID partitions table (削除ここまで)and (削除) FAT32 filesystem for EFI system partition. We will need gdisk utility from http://sourceforge.net/projects/gptfdisk/ for GUID partitions table creation (削除ここまで).
(追記) ====uefi-run helper application==== (追記ここまで)
The (追記) uefi-run application (追記ここまで)is (追記) useful for quick testing. It creates (追記ここまで)a (追記) temporary FAT (追記ここまで)image (追記) containing your (追記ここまで)EFI application and (追記) starts qemu (追記ここまで).


(削除) Select some reasonable size of your disk. Below I am assuming that $BYTES_PER_SECTOR is number of bytes per sector on your disk (typically 512) and $NUM_SECTORS is total disk size expressed in sectors. Firstly create disk image initial file filled with zeroes: (削除ここまで)
<source lang="bash">
<source lang="bash">
(削除) export filename= (削除ここまで)$(削除) PREFIX (削除ここまで)/(削除) share (削除ここまで)/(削除) qemu (削除ここまで)/(削除) myOS (削除ここまで)/(削除) myOS.disk (削除ここまで)
$ (追記) uefi-run -b (追記ここまで)/(追記) path (追記ここまで)/(追記) to (追記ここまで)/(追記) OVMF.fd -q (追記ここまで)/(追記) path (追記ここまで)/(追記) to (追記ここまで)/(追記) qemu app.efi -- <extra_qemu_args> (追記ここまで)
(削除) dd if= (削除ここまで)/(削除) dev (削除ここまで)/(削除) zero of=$filename bs=$BYTES_PER_SECTOR count=$NUM_SECTORS (削除ここまで)
</source>
</source>


(削除) After that (削除ここまで)create partition table (削除) by gdisk: (削除ここまで)
(追記) uefi-run is not currently packaged for any distribution. You can install it using cargo (the Rust package manager) though ("cargo install uefi-run"). (追記ここまで)
(追記) ====Linux, root required==== (追記ここまで)
(追記) This approach requires root privileges and uses '''gdisk''', '''losetup''', and '''mkdosfs'''. First, use gdisk to (追記ここまで)create (追記) a GPT (追記ここまで)partition table (追記) with a single [[EFI System Partition]]. (追記ここまで)
<source lang="bash">
<source lang="bash">
gdisk (削除) $filename (削除ここまで)
(追記) $ (追記ここまで)gdisk (追記) /path/to/uefi.img (追記ここまで)
(追記) GPT fdisk (gdisk) version 0.8.10 (追記ここまで)
(追記) Partition table scan: (追記ここまで)
(追記) MBR: not present (追記ここまで)
(追記) BSD: not present (追記ここまで)
(追記) APM: not present (追記ここまで)
(追記) GPT: not present (追記ここまで)
(追記) Creating new GPT entries. (追記ここまで)
(追記) Command (? for help): o (追記ここまで)
(追記) This option deletes all partitions and creates a new protective MBR. (追記ここまで)
(追記) Proceed? (Y/N): y (追記ここまで)
(追記) Command (? for help): n (追記ここまで)
(追記) Partition number (1-128, default 1): 1 (追記ここまで)
(追記) First sector (34-93716, default = 2048) or {+-}size{KMGTP}: 2048 (追記ここまで)
(追記) Last sector (2048-93716, default = 93716) or {+-}size{KMGTP}: 93716 (追記ここまで)
(追記) Current type is 'Linux filesystem' (追記ここまで)
(追記) Hex code or GUID (L to show codes, Enter = 8300): ef00 (追記ここまで)
(追記) Changed type of partition to 'EFI System' (追記ここまで)
(追記) Command (? for help): w (追記ここまで)
(追記) Final checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING (追記ここまで)
(追記) PARTITIONS!! (追記ここまで)
(追記) Do you want to proceed? (Y/N): y (追記ここまで)
(追記) OK; writing new GUID partition table (GPT) to uefi.img. (追記ここまで)
(追記) Warning: The kernel is still using the old partition table. (追記ここまで)
(追記) The new table will be used at the next reboot. (追記ここまで)
(追記) The operation has completed successfully. (追記ここまで)
</source>
</source>
(削除) It has interface similar to fdisk utility. Use "o" command to create new partition table, "n" for new partition with default parameters to use the whole disk (partition type "ef00" for EFI system partition), "w" to write all changes and exit. (削除ここまで)Now you have disk image with GUID partition table on it (削除) but the (削除ここまで)partition (削除) is still unformatted (削除ここまで). (削除) We (削除ここまで)will use (削除) Linux loopback device to access (削除ここまで)the (削除) file as block device (削除ここまで). (削除) We need (削除ここまで)to (削除) know exact position of (削除ここまで)the partition on (削除) the disk: (削除ここまで)
Now you have disk image with (追記) [[GPT| (追記ここまで)GUID partition table(追記) ]] (追記ここまで)on it (追記) and an unformatted EFI (追記ここまで)partition (追記) starting at sector 2048 (追記ここまで). (追記) Unless you deviated from the commands shown above, the disk image (追記ここまで)will use (追記) 512-byte sectors, so (追記ここまで)the (追記) EFI partition starts at byte 1,048,576 and is 46,934,528 bytes in length (追記ここまで). (追記) Use losetup (追記ここまで)to (追記) present (追記ここまで)the partition (追記) to Linux (追記ここまで)on (追記) a loopback device. (追記ここまで)
<source lang="bash">
<source lang="bash">
(削除) gdisk (削除ここまで)-(削除) l $filename (削除ここまで)
(追記) losetup (追記ここまで)-(追記) -offset 1048576 --sizelimit 46934528 /dev/loop0 /path/to/uefi.img (追記ここまで)
</source>
</source>
(削除) This command will output list of partitions and their first and last sectors indexes. (削除ここまで)If you (削除) have several partitions then just use numbers for your one (削除ここまで). (削除) Let's assume $START is the first sector index and $SIZE size is (削除ここまで)the partition (削除) size in sectors (i (削除ここまで).(削除) e. last minus first plus one). Associate your image file with the loopback device: (削除ここまで)
(追記) ( (追記ここまで)If (追記) /dev/loop0 is already in use (追記ここまで)you (追記) will need to select a different loopback device (追記ここまで).(追記) ) (追記ここまで)
(追記) Format (追記ここまで)the partition (追記) for FAT32 with mkdosfs (追記ここまで).
<source lang="bash">
<source lang="bash">
(削除) losetup (削除ここまで)-(削除) -offset $start --sizelimit $size (削除ここまで)/dev/loop0 (削除) $filename (削除ここまで)
(追記) mkdosfs (追記ここまで)-(追記) F 32 (追記ここまで)/dev/loop0
</source>
</source>
(削除) So (削除ここまで)now we can create (削除) filesystem there. We need FAT (削除ここまで)for (削除) EFI system partition (削除ここまで). (削除) You can use FAT12 if your partition size is small to prevent from big space overhead from larger FAT filesystems: (削除ここまで)
(追記) The partition can (追記ここまで)now (追記) be mounted, so that (追記ここまで)we can (追記) copy files to it. In this example we use the "/mnt" directory, but you could also (追記ここまで)create (追記) a local directory (追記ここまで)for (追記) temporary use (追記ここまで).
<source lang="bash">
<source lang="bash">
(削除) mkdosfs -F 12 (削除ここまで)/dev/loop0
(追記) mount (追記ここまで)/dev/loop0 (追記) /mnt (追記ここまで)
</source>
</source>
(削除) Now (削除ここまで)you can (削除) mount your (削除ここまで)partition (削除) to some mount point: (削除ここまで)
(追記) Copy any UEFI applications (追記ここまで)you (追記) want to test to the file system. (追記ここまで)
(追記) <source lang="bash"> (追記ここまで)
(追記) $ cp /path/to/main.efi /mnt/ (追記ここまで)
(追記) $ ... (追記ここまで)
(追記) </source> (追記ここまで)
(追記) Finally, unmount the partition and free the loopback device. (追記ここまで)
(追記) <source lang="bash"> (追記ここまで)
(追記) $ umount /mnt (追記ここまで)
(追記) $ losetup -d /dev/loop0 (追記ここまで)
(追記) </source> (追記ここまで)
(追記) ''uefi.img'' is now a disk image containing primary and secondary GPT tables, containing a single partition of type EFI, containing a FAT32 file system, containing one or more UEFI applications. (追記ここまで)
(追記) ====Linux, root not required==== (追記ここまで)
(追記) This approach uses '''parted''', '''mformat''', and '''mcopy''' and (追記ここまで)can (追記) be performed with user privileges. First, use parted to create primary and secondary GPT headers, and a single EFI (追記ここまで)partition (追記) spanning the same range as the approach above. (追記ここまで)
<source lang="bash">
<source lang="bash">
(削除) mkdir (削除ここまで)/(削除) tmp (削除ここまで)/(削除) myOsDisk (削除ここまで)
(追記) $ parted (追記ここまで)/(追記) path (追記ここまで)/(追記) to/uefi.img -s -a minimal mklabel gpt (追記ここまで)
(削除) mount (削除ここまで)/(削除) dev (削除ここまで)/(削除) loop0 (削除ここまで)/(削除) tmp (削除ここまで)/(削除) myOsDisk (削除ここまで)
(追記) $ parted /path/to (追記ここまで)/(追記) uefi.img -s -a minimal mkpart EFI FAT16 2048s 93716s (追記ここまで)
(追記) $ parted (追記ここまで)/(追記) path (追記ここまで)/(追記) to (追記ここまで)/(追記) uefi.img -s -a minimal toggle 1 boot (追記ここまで)
</source>
</source>
(削除) Just copy all files you need there (e.g. your EFI application executable (削除ここまで)image(削除) ). You can create "stratup.nsh" script which (削除ここまで)will (削除) be executed automatically if no other options are configured in EFI built-in boot-manager. Script could (削除ここまで)contain (削除) just your file launching command with required parameters, e.g. "fs0:\\efi\\boot\\myOsLoader some parameters here". According to specification you can create "/EFI/BOOT/BOOTx64. (削除ここまで)EFI(削除) " file which will be loaded automatically. (削除ここまで)
(削除) Finally unmount the (削除ここまで)partition and (削除) release the loopback device: (削除ここまで)
(追記) Now create a new temporary (追記ここまで)image (追記) file that (追記ここまで)will contain (追記) the (追記ここまで)EFI partition (追記) data (追記ここまで)and (追記) use mformat to format it with FAT16. (追記ここまで)
<source lang="bash">
<source lang="bash">
(削除) umount (削除ここまで)/tmp/(削除) myOsDisk (削除ここまで)
(追記) dd if=/dev/zero of= (追記ここまで)/tmp/(追記) part.img bs=512 count=91669 (追記ここまで)
(削除) losetup (削除ここまで)-(削除) d (削除ここまで)/(削除) dev (削除ここまで)/(削除) loop0 (削除ここまで)
(追記) mformat (追記ここまで)-(追記) i (追記ここまで)/(追記) tmp (追記ここまで)/(追記) part.img -h 32 -t 32 -n 64 -c 1 (追記ここまで)
</source>
</source>
(削除) Your disk image is ready and you can finally launch emulation. Obviously creating disk image could be easily automated in order to not execute these actions manually each time. Automation example can be found [http://ast-phoenix.sourceforge.net/doc/doku.php?id=athena:project:phoenix:dev_env#disk_image there]. (削除ここまで)


(削除) There are some advices for emulation running: (削除ここまで)
Use (追記) mcopy (追記ここまで)to (追記) copy any UEFI applications you want (追記ここまで)to (追記) test (追記ここまで)to (追記) the file system (追記ここまで).
(削除) * (削除ここまで)Use (削除) "-serial" option (削除ここまで)to (削除) have serial console available for the virtual machine. You will have console logs in your terminal and a possibility (削除ここまで)to (削除) use simple ports writing (削除ここまで)to (削除) output debug tracing to serial console (削除ここまで).
(削除) * Use "-s" option to enable built-in GDB stab which will wait for connection on TCP port 1234. (削除ここまで)
(削除) Launch Qemu providing path to the directory where your firmware binaries are located: (削除ここまで)
<source lang="bash">
<source lang="bash">
$(削除) PREFIX (削除ここまで)/(削除) bin (削除ここまで)/(削除) qemu-system-x86_64 -L $PREFIX (削除ここまで)/(削除) share (削除ここまで)/(削除) qemu (削除ここまで)/(削除) myOS -bios OVMF (削除ここまで).(削除) fd -m 768 -cpu kvm64 \ (削除ここまで)
$ (追記) mcopy -i (追記ここまで)/(追記) tmp (追記ここまで)/(追記) part.img (追記ここまで)/(追記) path (追記ここまで)/(追記) to (追記ここまで)/(追記) main (追記ここまで).(追記) efi (追記ここまで)::
(削除) -vga cirrus -monitor stdio -serial tcp (削除ここまで)::(削除) 666,server -s -hdb (削除ここまで)$(削除) PREFIX/share/qemu/myOS/myOS (削除ここまで).(削除) disk -enable-kvm (削除ここまで)
$ .(追記) .. (追記ここまで)
</source>
</source>


(削除) Qemu will start and wait for incoming connection to serial console. In (削除ここまで)the (削除) example above it waits on TCP port 666 (削除ここまで). (削除) You can use, for example, socat utility to connect: (削除ここまで)
(追記) Finally, write the partition image into (追記ここまで)the (追記) main disk image (追記ここまで).
<source lang="bash">
<source lang="bash">
(削除) socat -,raw,echo (削除ここまで)=(削除) 0 tcp4:localhost:666 (削除ここまで)
(追記) $ dd if (追記ここまで)=(追記) /tmp/part.img of=/path/to/uefi.img bs=512 count=91669 seek=2048 conv=notrunc (追記ここまで)
</source>
</source>
(削除) Once connected the emulation will start. You can use EFI shell command to navigate through filesystems, output system information or launch your application. It has help for all commands so refer to it for details. (削除ここまで)


(削除) The next important question is the application debugging (削除ここまで). (削除) The first moment (削除ここまで)is (削除) that the (削除ここまで)EFI (削除) application should be stopped at some point (削除ここまで)and (削除) wait for debugger (削除ここまで). (削除) The simplest way to do this is to insert some endless loop in your application. The loop can be enclosed in (削除ここまで)the block (削除) which is executed, for example, when your application receives "--debug" option in its arguments (削除ここまで). (削除) Let's assume you have inserted such code: (削除ここまで)
(追記) ''uefi (追記ここまで).(追記) img'' (追記ここまで)is (追記) now a disk image containing primary and secondary GPT tables, containing a single partition of type (追記ここまで)EFI(追記) , containing a FAT16 file system, containing one or more UEFI applications. (追記ここまで)
<source lang="(削除) c (削除ここまで)">
(削除) EFI_STATUS (削除ここまで)
(追記) ====FreeBSD, root required==== (追記ここまで)
(削除) efi_main (EFI_HANDLE image, EFI_SYSTEM_TABLE *systab) (削除ここまで)
(追記) This approach requires root privileges and uses '''mdconfig''', '''gpart''', '''newfs_msdos''', (追記ここまで)and (追記) '''mount_msdosfs''' (追記ここまで). (追記) First, create a device node that presents (追記ここまで)the (追記) zeroed disk image as a (追記ここまで)block (追記) device. This will let us work on it using standard partitioning and formatting tools (追記ここまで).
(削除) { (削除ここまで)
<source lang="(追記) bash (追記ここまで)">
(削除) EFI_LOADED_IMAGE *loaded_image = NULL; (削除ここまで)
(追記) $ mdconfig -f /path/to/uefi.img (追記ここまで)
(削除) EFI_STATUS status; (削除ここまで)
(追記) md0 (追記ここまで)
(追記) </source> (追記ここまで)


(削除) InitializeLib(image, systab); (削除ここまで)
(追記) In this example the new block device is ''md0''. Now create the empty primary and secondary GPT tables on the device. (追記ここまで)
(削除) status (削除ここまで)= (削除) uefi_call_wrapper(systab- (削除ここまで)>(削除) BootServices (削除ここまで)-(削除) >HandleProtocol, (削除ここまで)
(追記) <source lang (追記ここまで)=(追記) "bash" (追記ここまで)>
(削除) 3, (削除ここまで)
(追記) $ gpart create (追記ここまで)-(追記) s GPT md0 (追記ここまで)
(削除) image, (削除ここまで)
(追記) md0 created (追記ここまで)
(削除) &LoadedImageProtocol, (削除ここまで)
(追記) </source> (追記ここまで)
(削除) (void **)&loaded_image); (削除ここまで)
(削除) if (EFI_ERROR(status)) { (削除ここまで)
(削除) Print(L"handleprotocol: %r\n", status); (削除ここまで)
(削除) } (削除ここまで)


(削除) Print(L (削除ここまで)"(削除) Image base: 0x%lx\n (削除ここまで)", (削除) loaded_image (削除ここまで)->(削除) ImageBase); (削除ここまで)
(追記) Now we can add a partition to the disk. We'll specify an (追記ここまで)"(追記) EFI (追記ここまで)" (追記) partition (追記ここまで), (追記) which just means that GPT will set that partition's GUID to the special "EFI" type. Not all BIOSs require this, and the partition will still be able to be mounted and browsed normally on Linux, FreeBSD, and Windows. (追記ここまで)
(追記) <source lang="bash"> (追記ここまで)
(追記) $ gpart add (追記ここまで)-(追記) t efi md0 (追記ここまで)
(追記) md0p1 added (追記ここまで)
(追記) </source (追記ここまで)>


(削除) int wait (削除ここまで)= (削除) 1; (削除ここまで)
(追記) Next, create a FAT16 file system on the new partition. You can specify various parameters for the file system if you'd like, but it isn't necessary. Ideally you would create a FAT32 partition for best firmware compatibility but FreeBSD seems to create FAT32 partitions that OVMF can't read. (追記ここまで)
(削除) while (削除ここまで)((削除) wait (削除ここまで)) (削除) { (削除ここまで)
(追記) <source lang (追記ここまで)=(追記) "bash"> (追記ここまで)
(削除) __asm__ __volatile__("pause"); (削除ここまで)
(追記) $ newfs_msdos -F 16 md0p1 (追記ここまで)
(削除) } (削除ここまで)
(追記) newfs_msdos: trim 2 sectors to adjust to a multiple of 9 (追記ここまで)
(追記) /dev/md2p1: 93552 sectors in 11694 FAT16 clusters (追記ここまで)((追記) 4096 bytes/cluster (追記ここまで))
(追記) BytesPerSec=512 SecPerClust=8 ResSectors=1 FATs=2 RootDirEnts=512 Media=0xf0 FATsecs=46 SecPerTrack=9 Heads=16 HiddenSecs=0 HugeSectors=93681 (追記ここまで)
(追記) </source> (追記ここまで)


(削除) return EFI_SUCCESS; (削除ここまで)
(追記) The partition can now be mounted, so that we can copy files to it. In this example we use the ''/mnt'' directory, but you could also create a local directory for temporary use. (追記ここまで)
(削除) } (削除ここまで)
(追記) <source lang="bash"> (追記ここまで)
(追記) $ mount_msdosfs /dev/md0p1 /mnt (追記ここまで)
</source>
</source>
(削除) When this code will be executed "pause" instruction will be executed in the loop. (削除ここまで)


(削除) The next thing required for GDB is executable image with symbols. If (削除ここまで)you (削除) carefully examined build log and Makefiles you should note that when EFI executable is created from ELF shared object file only limited set of sections are copied (削除ここまで)to the (削除) resulted image: (削除ここまで)
(追記) Copy any UEFI applications (追記ここまで)you (追記) want to test (追記ここまで)to the (追記) file system. (追記ここまで)
<source lang="(削除) text (削除ここまで)">
<source lang="(追記) bash (追記ここまで)">
.(削除) text .sdata .data .dynamic .dynsym (削除ここまで).(削除) rel (削除ここまで).(削除) rela (削除ここまで).(削除) reloc (削除ここまで)
(追記) $ cp /path/to/main (追記ここまで).(追記) efi /mnt/ (追記ここまで)
(追記) $ (追記ここまで)...
</source>
</source>
(削除) For having debug symbols we need additionally these sections (in case you have compiled files with "-ggdb" option): (削除ここまで)
<source lang="(削除) text (削除ここまで)">
(追記) Finally, unmount the partition and free the block device. (追記ここまで)
(削除) .debug_info .debug_abbrev .debug_loc .debug_aranges .debug_line .debug_macinfo .debug_str (削除ここまで)
<source lang="(追記) bash (追記ここまで)">
(追記) $ umount /mnt (追記ここまで)
(追記) $ mdconfig -d -u md0 (追記ここまで)
</source>
</source>
(削除) But if you create EFI binary which additionally contains these sections the EFI firmware will be unable to launch it. Fortunately, we do not need the file with debug symbols on the target machine since we will use remote debugging anyway. So what you need is to create two EFI binaries - one with only required sections to upload it to target system and another one with debug symbols to use it with GDB. Actually you just need to run objcopy utility twice with different set of sections to copy and different output files. See Makefile example [http://ast-phoenix.git.sourceforge.net/git/gitweb.cgi?p=ast-phoenix/ast-phoenix;a=tree;f=kernel/boot;h=646835063c1362732f209c1312ce0d2ba7b558a5;hb=HEAD there]. (削除ここまで)


(削除) Now you can launch GDB (削除ここまで). (削除) You need to specify some (削除ここまで)file (削除) to use as (削除ここまで)the (削除) target binary - (削除ここまで)you (削除) can specify EFI binary with debug symbols but it will have no sense (削除ここまで)for (削除) debugging because (削除ここまで)the (削除) image will (削除ここまで)be (削除) relocated to different address (削除ここまで). (削除) Note that (削除ここまで)in the (削除) example code above the actual image base address is output (削除ここまで). (削除) It is (削除ここまで)required (削除) to properly load file with symbols (削除ここまで). (削除) Let's say after you have launched your application it provided this output: (削除ここまで)
(追記) ''uefi (追記ここまで).(追記) img'' is now a disk image containing primary and secondary GPT tables, containing a single partition of type EFI, containing a FAT16 (追記ここまで)file (追記) system, containing one or more UEFI applications. (追記ここまで)
<source lang="(削除) text (削除ここまで)">
(削除) Image base: 0x2EE30000 (削除ここまで)
(追記) ====Mac OS (root not required)==== (追記ここまで)
(追記) Mac OS has a single tool (hdiutil) that creates (追記ここまで)the (追記) disk image and copy files at same time. (追記ここまで)
(追記) Let's say that (追記ここまで)you(追記) 're creating a UEFI boot (追記ここまで)for (追記) x86_64. By definition (追記ここまで)the (追記) file name should (追記ここまで)be (追記) BOOTX64 (追記ここまで).(追記) EFI and this file should be located (追記ここまで)in the (追記) /EFI/BOOT folder (追記ここまで).
(追記) First, let's create a temporary folder that will contains all files and folders (追記ここまで)required (追記) for booting UEFI (追記ここまで).
(追記) (追記ここまで)
<source lang="(追記) bash (追記ここまで)">
(追記) $ mkdir -p diskImage/EFI/BOOT (追記ここまで)
</source>
</source>
(削除) So now you need to start GDB (削除ここまで), (削除) connect (削除ここまで)to (削除) local TCP port 1234 where Qemu is waiting for GDB connection and load image with symbols to relocated address. We need to specify relocated addresses for .text and .data sections. Their addresses in non-relocated binary should be added to image base which is provided in (削除ここまで)the (削除) output above (削除ここまで):
<source lang="(削除) text"> (削除ここまで)
(追記) Secondly (追記ここまで), (追記) let's copy the boot application (追記ここまで)to the (追記) required location (追記ここまで):
(削除) # gdb myOS.efi (削除ここまで)
(削除) GNU gdb (GDB) 7.3 (削除ここまで)
<source lang="(追記) bash (追記ここまで)">
(削除) Copyright (C) 2011 Free Software Foundation, Inc. (削除ここまで)
(追記) $ cp bootx64 (追記ここまで).efi (追記) diskImage (追記ここまで)/(追記) EFI (追記ここまで)/(追記) BOOT (追記ここまで)/(追記) BOOTX64 (追記ここまで).(追記) EFI (追記ここまで)
(削除) License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> (削除ここまで)
(削除) This is free software: you are free to change and redistribute it. (削除ここまで)
(削除) There is NO WARRANTY, to the extent permitted by law. Type "show copying" (削除ここまで)
(削除) and "show warranty" for details. (削除ここまで)
(削除) This GDB was configured as "x86_64-unknown-linux-gnu (削除ここまで)"(削除) . (削除ここまで)
(削除) For bug reporting instructions, please see: (削除ここまで)
(削除) <http://www.gnu.org/software/gdb/bugs/ (削除ここまで)>(削除) ... (削除ここまで)
(削除) Reading symbols from /home/John/myOS/source/kernel/boot/build/DEBUG/myOS.efi...(no debugging symbols found)...done. (削除ここまで)
(削除) (gdb) info files (削除ここまで)
(削除) Symbols from "/home/John/myOS/source/kernel/boot/build/DEBUG/myOS.efi". (削除ここまで)
(削除) Local exec file: (削除ここまで)
(削除) `/home/John/myOS/source/kernel/boot/build/DEBUG/myOS.efi', file type pei-x86-64. (削除ここまで)
(削除) Entry point: 0x3000 (削除ここまで)
(削除) 0x0000000000003000 - 0x000000000000b9ce is .text (削除ここまで)
(削除) 0x000000000000b9ce - 0x000000000000b9d8 is .reloc (削除ここまで)
(削除) 0x000000000000c000 - 0x000000000000e148 is .data (削除ここまで)
(削除) 0x000000000000f000 - 0x000000000000f0f0 is .dynamic (削除ここまで)
(削除) 0x0000000000010000 - 0x0000000000011098 is .rela (削除ここまで)
(削除) 0x0000000000012000 - 0x0000000000013788 is .dynsym (削除ここまで)
(削除) (gdb) file (削除ここまで)
(削除) No executable file now. (削除ここまで)
(削除) No symbol file now. (削除ここまで)
(削除) (gdb) add-symbol-file debug.myOS (削除ここまで).efi (削除) 0x2EE33000 -s .data 0x2EE3c000 (削除ここまで)
(削除) add symbol table from file "debug.myOS.efi" at (削除ここまで)
(削除) .text_addr = 0x2ee33000 (削除ここまで)
(削除) .data_addr = 0x2ee3c000 (削除ここまで)
(削除) (y or n) y (削除ここまで)
(削除) Reading symbols from /home/John/myOS/source/kernel (削除ここまで)/(削除) boot (削除ここまで)/(削除) build (削除ここまで)/(削除) DEBUG/debug (削除ここまで).(削除) myOS.efi...done. (削除ここまで)
(削除) (gdb) set architecture i386:x86-64:intel (削除ここまで)
(削除) The target architecture is assumed to be i386:x86-64:intel (削除ここまで)
(削除) (gdb) target remote :1234 (削除ここまで)
(削除) Remote debugging using :1234 (削除ここまで)
(削除) WaitDebugger () at loader/main.c:80 (削除ここまで)
(削除) 80 while (wait) { (削除ここまで)
(削除) (gdb) set variable wait = 0 (削除ここまで)
</source>
</source>
(削除) We need to unload executable binary by "file" command after sections layout is displayed because otherwise its symbols will override debug symbols loaded by "add-symbol-file" command (at least for data section). You do not need to load it each time because sections addresses will change only after next recompilation. Alternatively "objdump" utility can be used to dump sections. As you can see after setup is done you can normally debug your application using whole power of the GDB. Set your "wait" variable to zero and you will exit from endless loop. Set breakpoints/watchpoints, continue execution, enjoy debugging! (削除ここまで)


(削除) == GUID Partition Table == (削除ここまで)
(追記) Finally, let's create a disk image partitioned with GPT, formatted with fat32 (-fs fat32), overriding destination file if needed (-ov), define disk size (-size 48m), define volume name (-volname NEWOS), the file format which the disk will be encoded (-format UDTO - the same used for DVDs/CDs) and the source folder containing the files that will be copied to the new disk: (追記ここまで)


...
(追記) <source lang="bash"> (追記ここまで)
(追記) $ hdiutil create -fs fat32 -ov -size 48m -volname NEWOS -format UDTO -srcfolder diskImage uefi (追記ここまで).(追記) cdr (追記ここまで)
(追記) </source> (追記ここまで)
(追記) uefi (追記ここまで).(追記) cdr should be ready to be used by QEMU (追記ここまで).


== (削除) Binary Format (削除ここまで)==
===(追記) Launching UEFI applications (追記ここまで)=(追記) == (追記ここまで)
(追記) Once your disk image is ready, you can invoke QEMU as below. (追記ここまで)
(追記) <source lang="bash"> (追記ここまで)
(追記) $ qemu-system-x86_64 -cpu qemu64 -bios /path/to/OVMF.fd -drive file=uefi.disk,if=ide (追記ここまで)
(追記) </source> (追記ここまで)


(削除) (U)EFI generally uses (削除ここまで)the (削除) PE-executable format (削除ここまで), (削除) with its very own subtypes (削除ここまで). (削除) Every (U)EFI application is basically a DLL without symbol tables et al (削除ここまで), and (削除) another subtypes (削除ここまで):
(追記) When OVMF drops into (追記ここまで)the (追記) UEFI shell, you will see an additional entry in the "Mapping table" (追記ここまで), (追記) labeled "FS0" (追記ここまで). (追記) This indicates that the firmware detected the disk, discovered the partition (追記ここまで), and (追記) was able to mount the file system. You can explore the file system by switching to it using the DOS-style syntax "FS0 (追記ここまで):(追記) ", as illustrated below. (追記ここまで)


(削除) * (U)EFI application (10). (削除ここまで)
(追記) [[File:OVMF_browse_fs (追記ここまで).(追記) png]] (追記ここまで)
(削除) * (U)EFI boot service driver (11). (削除ここまで)
(削除) * (U)EFI run-time driver (12) (削除ここまで).


(追記) You can launch a UEFI application by entering its name. (追記ここまで)


(削除) == Calling Conventions == (削除ここまで)
(追記) [[File:OVMF_run_app.png]] (追記ここまで)


(削除) The EFI specifications specify (削除ここまで)the (削除) calling conventions for 32-bit 80x86 and Itanium. The (later) (削除ここまで)UEFI (削除) specifications define (削除ここまで)the (削除) calling conventions for 32-bit 80x86 (削除ここまで), (削除) Itanium and 64-bit 80x86 (削除ここまで)
(追記) Notice that (追記ここまで)the UEFI (追記) shell resumed once (追記ここまで)the (追記) application terminated. Of course if this was a proper bootloader it would never resume (追記ここまで), (追記) but rather launch an OS. (追記ここまで)


(削除) For 32 (削除ここまで)-(削除) bit 80x86 (削除ここまで), the (削除) calling convention used is (削除ここまで)the (削除) standard C calling convention (削除ここまで). (削除) For Itanium (削除ここまで), the (削除) calling convention is defined in the "Intel(R) Itanium(R) System Abstraction Layer Specification" (削除ここまで).
(追記) Some commercial UEFI firmware provides UEFI shells or the capability to launch user (追記ここまで)-(追記) selected UEFI applications (追記ここまで), (追記) such as (追記ここまで)the (追記) firmware that ships with (追記ここまで)the (追記) HP EliteBook line of laptops (追記ここまで). (追記) Most, however (追記ここまで), (追記) do not expose this functionality to (追記ここまで)the (追記) end-user (追記ここまで).


(削除) For 64-bit 80x86, Microsoft's x64 calling convention is used. This calling convention requires the stack (削除ここまで)be (削除) aligned on a 16-byte boundary (from the callee's perspective) (削除ここまで), and (削除) that a 32-byte "shadow space" be reserved on the stack (immediately above the return RIP) (削除ここまで). (削除) The shadow space is not described by (削除ここまで)the (削除) UEFI specifications. This can lead (削除ここまで)to (削除) frustrated assembly language programmers (who are writing code based on (削除ここまで)the (削除) UEFI specifications alone and don't know about the shadow space, and therefore waste '''hours''' trying to figure out why their stack gets trashed by some EFI functions).. (削除ここまで).
(追記) ===Debugging=== (追記ここまで)
(追記) OVMF can (追記ここまで)be (追記) built in debug mode (追記ここまで), and (追記) it will output logging messages to IO port 0x402 (追記ここまで).
(追記) You can use some flags like (追記ここまで)the (追記) ones below (追記ここまで)to (追記) capture (追記ここまで)the (追記) output (追記ここまで).


(追記) <code>-debugcon file:uefi_debug.log -global isa-debugcon.iobase=0x402</code> (追記ここまで)


(削除) == Example in C == (削除ここまで)
(追記) Note that release builds will not output debug messages, or will have reduced output. (追記ここまで)


(削除) Below is an example of an EFI application written in C that displays: "Hello World" (削除ここまで).
(追記) See [[Debugging UEFI applications with GDB]] (追記ここまで).


(追記) ==Running on real hardware== (追記ここまで)
(追記) ===NVRAM variables=== (追記ここまで)
(追記) {{Main|UEFI NVRAM}} (追記ここまで)
(追記) A UEFI firmware will present most of its configuration options through a text or graphical configuration menu, just like a legacy BIOS. Selections made in these menus are stored in the NVRAM chip between reboots. Unlike legacy BIOS, however, the firmware developer has the option to expose some or all of these "NVRAM variables" to the OS and end-user via convenience functions made resident in RAM by the firmware at boot. (追記ここまで)
(追記) (追記ここまで)
(追記) The Linux '''efivarfs''' kernel module will use these functions to list NVRAM variables in the ''/sys/firmware/efi/efivars'' file. NVRAM variables can also be dumped from within the UEFI shell itself with the '''dmpstore''' command. Device boot order is always accessible via NVRAM variables. The Linux program '''efibootmgr''' works specifically with the boot order NVRAM variables. The UEFI shell offers the '''bcfg''' command for the same purpose. (追記ここまで)
(追記) (追記ここまで)
(追記) ===Bootable UEFI applications=== (追記ここまで)
(追記) The boot order NVRAM variables determine where firmware will look for UEFI applications to be launched at boot. Although this can be changed (for example, an OS installer might customize the boot entry for the hard drive to which it was installed) firmware typically looks for a UEFI application named "BOOTIA32.efi" (for 32-bit applications) or "BOOTX64.efi" (for 64-bit applications) stored in the "/EFI/BOOT" path in the boot device's file system. This is the default path and name for OVMF. (追記ここまで)
(追記) (追記ここまで)
(追記) Unlike a UEFI application launched from the shell, if a bootable UEFI application returns BIOS will continue searching for other boot devices. (追記ここまで)
(追記) (追記ここまで)
(追記) ===Exposed functionality=== (追記ここまで)
(追記) Real PCs vary in the amount of UEFI capability they expose to the user. For example, even a class 3 machine may not make any mention of UEFI in its BIOS configuration and may not offer a UEFI shell. Additionally, some BIOS vendors make their UEFI firmware configuration screens look identical to their legacy BIOS configuration screens. Class 2 machines may present somewhat confusing boot menus and configuration options. For example, one laptop manufacturer includes a configuration option to enable/disable UEFI (i.e. switch between UEFI and CSM behavior), named "OS: Windows 8". Another laptop, if it fails to find a bootable UEFI application on the selected boot device (or if that application returns a status other than EFI_SUCCESS) will fall back to CSM behavior and then complain that the drive has a corrupted MBR. With time, and with the emergence of class 3 machines, clarity of UEFI boot behavior will improve. (追記ここまで)
(追記) (追記ここまで)
(追記) To make testing on real hardware easier, you can install a bootable UEFI application to the internal hard drive of the system that provides a boot menu, such as [http://www.rodsbooks.com/refind/ rEFInd]. This may also be convenient for multi-boot scenarios. (追記ここまで)
(追記) (追記ここまで)
(追記) ===PC firmware developers=== (追記ここまで)
(追記) On x86 and x86-64 platforms, the following BIOS developers offer UEFI firmware: (追記ここまで)
(追記) * AMI (Aptio). (追記ここまで)
(追記) * Phoenix (SecureCore, TrustedCore, AwardCore). (追記ここまで)
(追記) * Insyde (InsydeH20). (追記ここまで)
(追記) (追記ここまで)
(追記) == UEFI applications in detail == (追記ここまで)
(追記) === Binary Format === (追記ここまで)
(追記) UEFI executables are regular PE32 / PE32+ (Windows x32 / x64) images, with a specific '''subsystem'''. (追記ここまで)
(追記) Every UEFI application is basically a windows EXE (or DLL) without symbol tables. (追記ここまで)
(追記) (追記ここまで)
(追記) {| class="wikitable" (追記ここまで)
(追記) |+ Types of UEFI images (追記ここまで)
(追記) |- (追記ここまで)
(追記) ! Type (追記ここまで)
(追記) ! Description (追記ここまで)
(追記) ! Subsystem (追記ここまで)
(追記) |- (追記ここまで)
(追記) | Applications || OS loaders and other utility programs. || 10 (追記ここまで)
(追記) |- (追記ここまで)
(追記) | Boot service driver || Drivers used by the firmware when booting (e.g. disk drivers, network drivers). || 11 (追記ここまで)
(追記) |- (追記ここまで)
(追記) | Runtime driver || Drivers which may stay loaded even after the OS loads and exits the boot services. || 12 (追記ここまで)
(追記) |} (追記ここまで)
(追記) (追記ここまで)
(追記) UEFI images must also specify the type of machine code they contain. A UEFI loader will refuse to boot an incompatible image. (追記ここまで)
(追記) (追記ここまで)
(追記) {| class="wikitable" (追記ここまで)
(追記) |+ Types of machines (追記ここまで)
(追記) |- (追記ここまで)
(追記) ! Name / arch (追記ここまで)
(追記) ! Value (追記ここまで)
(追記) |- (追記ここまで)
(追記) |x86||0x014c (追記ここまで)
(追記) |- (追記ここまで)
(追記) |x86_64||0x8664 (追記ここまで)
(追記) |- (追記ここまで)
(追記) |Itanium x64||0x0200 (追記ここまで)
(追記) |- (追記ここまで)
(追記) |UEFI Byte Code||0x0EBC (追記ここまで)
(追記) |- (追記ここまで)
(追記) |ARM<sup>1</sup>||0x01C2 (追記ここまで)
(追記) |- (追記ここまで)
(追記) |AArch (ARM x64)||0xAA64 (追記ここまで)
(追記) |- (追記ここまで)
(追記) |RISC-V x32||0x5032 (追記ここまで)
(追記) |- (追記ここまで)
(追記) |RISC-V x64||0x5064 (追記ここまで)
(追記) |- (追記ここまで)
(追記) |RISC-V x128||0x5128 (追記ここまで)
(追記) |} (追記ここまで)
(追記) (追記ここまで)
(追記) [1] ARM means you can use Thumb / Thumb 2 instructions, but UEFI interfaces are in ARM mode. (追記ここまで)
(追記) (追記ここまで)
(追記) ==== Initialization ==== (追記ここまで)
(追記) Applications must either load an OS and exit boot services, or return from the main function (in which case the boot loader will look for the next app to load). (追記ここまで)
(追記) (追記ここまで)
(追記) Drivers must initialize and then return 0 on success, or an error code. A computer might fail to boot if a required driver fails to load. (追記ここまで)
(追記) (追記ここまで)
(追記) ==== Memory ==== (追記ここまで)
(追記) The memory map returned by UEFI will mark the memory areas which drivers use. (追記ここまで)
(追記) (追記ここまで)
(追記) Once your OS loader finished, your kernel is allowed to reuse the memory where the boot loader was loaded. (追記ここまで)
(追記) (追記ここまで)
(追記) The memory types are <code>Efi{Loader/BootServices/RuntimeServices}{Code/Data}</code>. (追記ここまで)
(追記) (追記ここまで)
(追記) After exiting the boot services, you may reuse whatever non-read-only memory the boot drivers used. (追記ここまで)
(追記) (追記ここまで)
(追記) However, memory used by the runtime drivers must '''never''' be touched - the runtime drivers stay active and loaded for as long as the computer runs. (追記ここまで)
(追記) (追記ここまで)
(追記) One way to see a breakdown of a PE file containing a UEFI application is by<source lang="bash">$ objdump --all-headers /path/to/main.efi</source> (追記ここまで)
(追記) Its output is quite long. Among other things, it shows the '''subsystem''', that is the type of the UEFI image, mentioned earlier. (追記ここまで)
(追記) (追記ここまで)
(追記) === Calling Conventions === (追記ここまで)
(追記) UEFI specifies the following calling conventions: (追記ここまで)
(追記) * '''cdecl''' for x86 UEFI functions (追記ここまで)
(追記) * '''Microsoft's 64-bit calling convention''' for x86-64 UEFI functions (追記ここまで)
(追記) * '''SMC''' for ARM UEFI functions (追記ここまで)
(追記) (追記ここまで)
(追記) This has two impacts on UEFI application developers: (追記ここまで)
(追記) * A UEFI application's main entry point must expect to be called with the corresponding calling convention. (追記ここまで)
(追記) * Any UEFI-provided functions that a UEFI application calls must be called with the corresponding calling convention. (追記ここまで)
(追記) Note that functions strictly internal to the application can use whatever calling convention the developer chooses. (追記ここまで)
(追記) (追記ここまで)
(追記) ==== POSIX-UEFI, GNU-EFI and GCC ==== (追記ここまで)
(追記) {{Main|GNU-EFI}} (追記ここまで)
(追記) cdecl is the standard calling convention used by GCC, so no special attributes or modifiers are needed for writing the main entry point or calling UEFI functions in an x86 UEFI application developed with GNU-EFI. For x86-64, however, the entry point function must be declared with the "___attribute___((ms_abi))" modifier and all calls to UEFI-provided functions must be made through the "uefi_call_wrapper" thunk. This thunk is called with cdecl, but then translates to the Microsoft x86-64 calling convention before calling the requested UEFI function. This is necessary because older releases of GCC do not support specifying calling conventions for function pointers. (追記ここまで)
(追記) (追記ここまで)
(追記) For [[POSIX-UEFI]], which also uses GCC, your entry point looks like the standard main(), and no special ABI is required. Also the build environment takes care of the compiler flags for you, so you can simply call UEFI functions without "uefi_call_wrapper", no matter if you're using the host gcc or a cross-compiler. (追記ここまで)
(追記) (追記ここまで)
(追記) For developer convenience, both POSIX-UEFI and GNU-EFI provides the "EFIAPI" macro, which expands to "cdecl" when targeting x86 and "__attribute__(ms_abi))" when targeting x86-64. Additionally, the "uefi_call_wrapper" thunk will simply pass the call through on x86. This allows the same source code to target x86 and x86-64. For example, the following main function will compile with the correct calling convention on both x86 and x86-64 and the call through the "uefi_call_wrapper" thunk will select the correct calling convention to use when calling the UEFI function (in this case, printing a string). (追記ここまで)
<source lang="c">
<source lang="c">
(削除) #include <efi.h> (削除ここまで)
EFI_STATUS (追記) EFIAPI efi_main (追記ここまで)(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
EFI_STATUS (削除) main (削除ここまで)(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
{
{
SystemTable->ConOut->OutputString(削除) ( (削除ここまで)SystemTable->ConOut, L"Hello World(削除) \r (削除ここまで)\n");
(追記) EFI_STATUS status = uefi_call_wrapper( (追記ここまで)SystemTable->ConOut->OutputString(追記) , (追記ここまで)
return (削除) EFI_SUCCESS (削除ここまで);
(追記) 2, (追記ここまで)
(追記) (追記ここまで)SystemTable->ConOut,
(追記) (追記ここまで)L"Hello(追記) , (追記ここまで)World(追記) ! (追記ここまで)\n");
return (追記) status (追記ここまで);
}
}
</source>
</source>


== (削除) Example in FASM (削除ここまで)==
==(追記) = Language binding = (追記ここまで)==
(追記) UEFI applications are typically (追記ここまで)written in (追記) C, although bindings could be written for any other language that compiles (追記ここまで)to (追記) machine code. Assembly is also an option; a [[uefi.inc]] is available for [[ (追記ここまで)FASM(追記) ]] (追記ここまで)that (追記) allows UEFI applications to be written as below (追記ここまで).
(削除) Below is an example of an EFI application (削除ここまで)written in (削除) x86 assembly ( (削除ここまで)to (削除) be assembled with (削除ここまで)FASM(削除) ) (削除ここまで)that (削除) displays: "Hello World" (削除ここまで).
<source lang="asm">
<source lang="asm">
format pe64 dll efi
format pe64 dll efi
Line 244: Line 581:
section '.text' code executable readable
section '.text' code executable readable


include '(削除) efi (削除ここまで).inc'
include '(追記) uefi (追記ここまで).inc'


main:
main:
(削除) sub rsp, 4 * 8 (削除ここまで); (削除) Reserve space for four arguments. (削除ここまで)
; (追記) initialize UEFI library (追記ここまで)
(削除) mov [Handle], rcx ; ImageHandle (削除ここまで)
(追記) InitializeLib (追記ここまで)
(削除) mov [SystemTable], rdx (削除ここまで); (削除) Pointer (削除ここまで)to (削除) SystemTable. (削除ここまで)
(追記) jc @f (追記ここまで)
(削除) lea rdx (削除ここまで), (削除) [_hello] (削除ここまで)
(削除) mov rcx (削除ここまで), (削除) [SystemTable] (削除ここまで)
; (追記) call uefi function (追記ここまで)to (追記) print to screen (追記ここまで)
(削除) mov rcx (削除ここまで), (削除) [rcx + EFI_SYSTEM_TABLE.ConOut] (削除ここまで)
(追記) uefi_call_wrapper ConOut (追記ここまで), (追記) OutputString (追記ここまで), (追記) ConOut (追記ここまで), (追記) _hello (追記ここまで)
(削除) call [rcx + SIMPLE_TEXT_OUTPUT_INTERFACE.OutputString] (削除ここまで)
(削除) add rsp, 4 * 8 (削除ここまで)
(追記) @@: (追記ここまで)mov eax, EFI_SUCCESS
(削除) (削除ここまで)mov eax, EFI_SUCCESS
retn
retn


section '.data' data readable writeable
section '.data' data readable writeable


(削除) Handle dq ? (削除ここまで)
_hello (追記) du (追記ここまで)'Hello World',13,10,0
(削除) SystemTable dq ? (削除ここまで)
_hello (削除) db (削除ここまで)'Hello World',13,10,0


section '.reloc' fixups data discardable
section '.reloc' fixups data discardable
</source>
</source>


(追記) As a UEFI application contains normal x86 or x86-64 machine code, inline assembly is also an option in compilers that support it. (追記ここまで)
(追記) (追記ここまで)
(追記) === EFI Byte Code=== (追記ここまで)
(追記) UEFI also includes a virtual machine specification based on a byte code format called EFI Byte Code (EBC), which can be used to write platform-independent device drivers, but not UEFI applications. As of 2015 there has been limited use of EBC. (追記ここまで)
(追記) (追記ここまで)
(追記) == Common Problems == (追記ここまで)
(追記) (追記ここまで)
(追記) === My UEFI application hangs/resets after about 5 minutes === (追記ここまで)


=(削除) = Known Firmware Bugs == (削除ここまで)
(追記) When control is handed to your UEFI application by firmware, it sets a watchdog timer for 5 minutes, after which the firmware is reinvoked as it assumes your application has hung. The firmware in this case will normally try to reset the system (although the OVMF firmware in VirtualBox simply causes the screen to go black and hang). To counteract this, you are required to refresh the watchdog timer before it times out. Alternatively, you can disable it completely with code like <source lang (追記ここまで)=(追記) "C">SystemTable->BootServices->SetWatchdogTimer(0, 0, 0, NULL);</source>Obviously this is not a problem for most bootloaders, but can cause an issue if you have an interactive loader which waits for user input. Also note that you are required to disable the watchdog timer if you exit back to the firmware. (追記ここまで)


(削除) For the memory management functions in EFI, an OS is meant to be able to (削除ここまで)use (削除) "memory type" values above 0x80000000 for its own purposes. In the OVFM EFI firmware release "r11337" (for Qemu, etc) there is a bug where the firmware assumes the memory type is within the range of values (削除ここまで)defined (削除) for EFI's own use, and uses the memory type as an array index. The end result is an "array index out of bounds" bug; where the higher memory type (削除ここまで)values (削除) (e.g. perfectly legal values above 0x80000000) cause the 64-bit version of the firmware to crash (page fault), and cause incorrect "attribute" values to be reported by the 32-bit version of the firmware. This same bug is also present in whatever version of the EFI firmware VirtualBox uses (which looks like an older version of OVFM); and I suspect (but don't know) that the bug may be present in a wide variety of firmware that was derived from the tianocore project (not just OVFM). [[User:Brendan|Brendan]] 15:30, 29 July 2011 (UTC) (削除ここまで)
(追記) === My bootloader hangs if I (追記ここまで)use (追記) user (追記ここまで)defined (追記) EFI_MEMORY_TYPE (追記ここまで)values (追記) === (追記ここまで)


(追記) For the memory management functions in EFI, an OS is meant to be able to use "memory type" values above 0x80000000 for its own purposes. In the OVMF EFI firmware release "r11337" (for Qemu, etc) there is a bug where the firmware assumes the memory type is within the range of values defined for EFI's own use, and uses the memory type as an array index. The end result is an "array index out of bounds" bug; where the higher memory type values (e.g. perfectly legal values above 0x80000000) cause the 64-bit version of the firmware to crash (page fault), and cause incorrect "attribute" values to be reported by the 32-bit version of the firmware. This same bug is also present in whatever version of the EFI firmware VirtualBox uses (which looks like an older version of OVMF); and I suspect (but don't know) that the bug may be present in a wide variety of firmware that was derived from the tianocore project (not just OVMF). (追記ここまで)


== See also ==
== See also ==
=== (削除) Wikipedia (削除ここまで)===
=== (追記) Articles (追記ここまで)===
* [[(削除) Wikipedia (削除ここまで):(削除) Extensible_Firmware_Interface|EFI (削除ここまで).(削除) ] (削除ここまで)]
* [[(追記) UEFI Bare Bones]] (追記ここまで)
(追記) * [[EFI System Partition]] (追記ここまで)
(追記) * [[PE]] file format (追記ここまで)
(追記) * [[EDK2]] (追記ここまで)
(追記) * [[POSIX-UEFI]] (追記ここまで)
(追記) * [[GNU-EFI]] (追記ここまで)
(追記) * [https (追記ここまで):(追記) //github (追記ここまで).(追記) com/nebulaeonline/nebulae/tree/UefiBarebones Uefi Barebones MSVC/Clang/Visual Studio (追記ここまで)]


=== External Links ===
=== External Links ===
* [http://www.(削除) intel (削除ここまで).com/(削除) technology (削除ここまで)/(削除) efi (削除ここまで)/(削除) |Intel EFI specifications et al. (削除ここまで)]
(追記) * [https://uefi.org/specifications UEFI specifications et al.] (追記ここまで)
* [http://(削除) www (削除ここまで).(削除) uefi (削除ここまで).(削除) org (削除ここまで)/(削除) home (削除ここまで)/(削除) | (削除ここまで)UEFI (削除) specifications et al. (削除ここまで)]
* [http://www.(追記) tianocore.org/ Intel TianoCore EDK2] (追記ここまで)
* [http://x86asm.net/articles/index.html(削除) | (削除ここまで)Several articles about UEFI(削除) . (削除ここまで)]
(追記) * [https://github (追記ここまで).com/(追記) tianocore (追記ここまで)/(追記) tianocore.github.io (追記ここまで)/(追記) wiki/OVMF OVMF firmware images] for use with [[QEMU] (追記ここまで)]
* [(削除) http (削除ここまで)://www.microsoft.com/(削除) whdc (削除ここまで)/(削除) system (削除ここまで)/(削除) platform/firmware/pecoff (削除ここまで).(削除) mspx| (削除ここまで)PE specification covering the (U)EFI binary format.]
* [(追記) https://web.archive.org/web/20181028201454/ (追記ここまで)http://(追記) wiki (追記ここまで).(追記) phoenix (追記ここまで).(追記) com/wiki (追記ここまで)/(追記) index.php (追記ここまで)/(追記) Main_Page Phoenix (追記ここまで)UEFI (追記) Wiki (追記ここまで)]
* [http://x86asm.net/articles(追記) /others (追記ここまで)/index.html Several articles about UEFI]
* [(追記) https (追記ここまで)://www.microsoft.com/(追記) en-us (追記ここまで)/(追記) download (追記ここまで)/(追記) details (追記ここまで).(追記) aspx?id=19509 (追記ここまで)PE specification covering the (U)EFI binary format(追記) ] (追記ここまで)
(追記) * [https://uefi.blogspot.com/ Blog about UEFI, with bits about UEFI development] (追記ここまで)
(追記) * [https://web.archive.org/web/20160316192235/http://internshipatdell.wikispaces.com/file/view/How+to+build+an+UEFI+application.pptx Presentation guiding through simple UEFI application setup] (追記ここまで)
(追記) * [https://uefi.org/sites/default/files/resources/UEFI-Plugfest-WindowsBootEnvironment.pdf Presentation giving an overview of windows uefi booting] (追記ここまで)
(追記) * [https://gitlab (追記ここまで).(追記) com/bztsrc/posix-uefi POSIX-UEFI] documentation and source (追記ここまで)
(追記) * [[Wikipedia:Extensible_Firmware_Interface|Wikipedia Article on EFI] (追記ここまで)]


[[Category:(削除) X86 (削除ここまで)]]
[[Category:(追記) x86 (追記ここまで)]]
[[Category:(削除) X86-64]] (削除ここまで)
[[Category:(追記) x86 (追記ここまで)-64]]
(削除) [[Category:IA-32]] (削除ここまで)
(削除) [[Category:IA (削除ここまで)-64]]
[[Category:ARM]]
[[Category:ARM]]
[[Category:Firmware]]
[[Category:Firmware]]
(追記) [[Category:UEFI]] (追記ここまで)
(追記) [[de:Unified_Extensible_Firmware_Interface]] (追記ここまで)

Latest revision as of 04:12, 23 October 2025

(U)EFI or (Unified) Extensible Firmware Interface is a specification for x86, x86-64, ARM, and Itanium platforms that defines a software interface between the operating system and the platform firmware/BIOS. The original EFI was developed in the mid-1990s by Intel for use developing firmware/BIOS for Itanium platforms. In 2005 Intel transitioned the specification to a new working group called the Unified EFI Forum, consisting of companies such as AMD, Microsoft, Apple, and Intel itself. All modern PCs ship with UEFI firmware and UEFI is widely supported by both commercial and open source operating systems. Backwards compatibility is provided for legacy operating systems.

UEFI basics

Downloading UEFI images

If you choose VirtualBox for virtualization, then UEFI is already included, no need to download the image manually. You just have to enable it in the VM's preferences by clicking "Settings" / "Systems" / "Enable EFI (special OSes only)" checkbox.

Otherwise for emulation and virtual machines, you'll need an OVMF.fd firmware image. It might be tricky to find, so here are some alternative download links too:

Under Linux, you can also install these with your distro's package manager, for example:

Debian / Ubuntu

# apt-get install ovmf

RedHat / CentOS

# yum install ovmf

MacOS

Use the OVMF-blobs repo.

Windows

Use the OVMF-blobs repo or download the RPM version, then use 7-Zip File Manager to extract the OVMF.fd file from the downloaded archive.

UEFI vs. legacy BIOS

A common misconception is that UEFI and BIOS are mutually exclusive. In reality, both legacy motherboards and UEFI-based motherboards both include BIOS ROMs. The differences are in where they find the bootloader/OS, how they prepare the system before executing it, and what convenience functions they provide.

Platform initialization

On a legacy system, the BIOS performs all the usual platform initialization (memory controller configuration, PCI bus configuration and BAR mapping, graphics card initialization, etc.), but then drops into a backwards-compatible real mode environment. The bootloader must enable the A20 gate, configure a GDT and an IDT, switch to protected mode, and for x86-64 CPUs, configure paging and switch to long mode.

UEFI firmware performs those same steps, but it also enables the A20 gate and prepares either protected mode environment with flat segmentation (for 32-bit x86 processors) or a long mode environment with identity-mapped paging (for x86-64 processors).

Additionally, the platform initialization procedure of UEFI firmware is standardized. This allows UEFI firmware to be extended in a vendor-neutral way.

Boot mechanism

A legacy BIOS loads a 512 byte flat binary blob from the MBR of the boot device into memory at physical address 0x7C00 and jumps to it. The bootloader can return back to the BIOS through INT 0x18. On the other hand, UEFI firmware loads an arbitrary sized UEFI application (a relocatable PE executable file) from a FAT partition on a GPT or MBR partitioned boot device to some address selected at run-time. Then it calls that application's main entry point. The application can return control to the firmware, which will continue searching for another boot device or bring up a diagnostic menu.

System discovery

A legacy bootloader scans memory for structures like the EBDA, SMBIOS, and ACPI tables. It uses PIO to talk to the root PCI controller and scan the PCI bus. It is possible that redundant tables may be present in memory (for example, the MP table in the SMBIOS contains information that's also present in the ACPI DSDT and MADT) and the bootloader can choose which to use.

When UEFI firmware calls a UEFI application's entry point function, it passes a "System Table" structure, which contains pointers to all of the system's ACPI tables, memory map, and other information relevant to an OS. Legacy tables (like MP tables) may not be present in memory.

Convenience functions

A legacy BIOS hooks a variety of interrupts which a bootloader can trigger to access system resources like disks and the screen. These interrupts are not standardized, except by historical convention. Each interrupt uses a different register passing convention.

UEFI firmware establishes many callable functions in memory, which are grouped into sets called "protocols" and are discoverable through the System Table. The behavior of each function in each protocol is defined by specification. UEFI applications can define their own protocols and persist them in memory for other UEFI applications to use. Functions are called with a standardized, modern calling convention supported by many C compilers.

Development environment

Legacy bootloaders can be developed in any environment that can generate flat binary images: NASM, GCC, etc. UEFI applications can be developed in any language that can be compiled and linked into a PE executable file and supports the calling convention used to access functions established in memory by the UEFI firmware. In practice this means one of three development environments: EDK2, GNU-EFI or POSIX-UEFI.

EDK2 is a large and complex, yet feature filled environment with its own build system. It can be configured to use GCC, LLVM, MinGW, Microsoft Visual C++, etc. as a cross-compiler. Not only can it be used to compile UEFI applications, but it can also be used to compile UEFI firmware to be flashed to a BIOS ROM.

GNU-EFI is a set of libraries and headers for compiling UEFI applications with a system's native GCC (does not work with LLVM CLang). It can't be used to compile UEFI firmware. Since it's just a couple of libraries against which a UEFI application can be linked, it is much easier to use than TianoCore ( EDK2 ).

POSIX-UEFI is very similar to GNU-EFI, but it is distributed mainly as a source, not as a binary library, has ANSI C like names and works with GCC as well as LLVM CLang. It's shipped with a Makefile that sets up the compiler flags for you.

Emulation

OVMF, a popular open source UEFI firmware, has been ported to the QEMU (but not Bochs) emulated machine. Because it implements the UEFI specification, it behaves very similarly to commercial UEFI firmware on real machines. (OVMF itself is built with TianoCore, and its source ship with it as well, but pre-built images are available.)

Legacy bootloader or UEFI application?

If you are targeting legacy systems for which UEFI is not available or is not reliable, you should develop a legacy bootloader. This requires intimate knowledge of 16-bit addressing and the backwards-compatibility features of an x86 or x86-64 CPU. If you are targeting modern systems you should develop a UEFI application. Many UEFI firmwares can be configured to emulate a legacy BIOS, but there is even more variation among these emulated environments than among real legacy BIOS.

Although there is a slight learning curve to become familiar with the UEFI development environments, using the System Table, and accessing UEFI-provided protocols (functions), there are far fewer "gotchas" than trying to remain compatible with the wide variety of quickly-becoming-obsolete legacy BIOSs on real machines. UEFI is the standard for all modern PCs.

UEFI class 0-3 and CSM

PCs are categorized as UEFI class 0, 1, 2, or 3. A class 0 machine is a legacy system with a legacy BIOS; i.e. not a UEFI system at all.

A class 1 machine is a UEFI system that runs exclusively in Compatibility Support Module (CSM) mode. CSM is a specification for how UEFI firmware can emulate a legacy BIOS. UEFI firmware in CSM mode loads legacy bootloaders. A class 1 UEFI system may not advertise UEFI support at all, since it isn't exposed to the bootloader. It's only UEFI "within" the BIOS.

A class 2 machine is a UEFI system that can launch UEFI applications but also includes the option to run in CSM mode. The majority of modern PCs are UEFI class 2 machines. Sometimes the choice to run UEFI applications vs. CSM is a one-or-the-other setting in the BIOS configuration, and other times the BIOS will decide which to use after selecting the boot device and checking whether it has a legacy bootloader or a UEFI application.

A class 3 machine is a UEFI system that does not support CSM. UEFI class 3 machines only run UEFI applications and do not implement CSM for backwards compatibility with legacy bootloaders.

Secure Boot

Secure Boot is a digital signature scheme for UEFI applications that consists of four components:

  • PK: Platform Key
  • KEK: Key Exchange Keys
  • db: Whitelist database
  • dbx: Blacklist database

UEFI firmware that supports Secure Boot is always in one of three states:

  • Setup mode, Secure Boot off
  • User mode, Secure Boot off
  • User mode, Secure Boot on

In setup mode, any UEFI application can change or delete the PK, add/remove keys from the KEK, and add/remove whitelist or blacklist entries from the db or dbx.

In user mode, regardless of whether Secure Boot is on or off:

  • The PK may only be changed or deleted by a UEFI application that already has the current PK.
  • Keys can only be added/removed from the KEK by a UEFI application that has the PK.
  • Whitelist and blacklist entries can only be added/removed from the db and dbx by a UEFI application that has any one of the keys in the KEK.

Finally, in user mode with Secure Boot on, UEFI applications must meet one of the following four requirements to be launched:

  • Signed, with signature in db and not in dbx
  • Signed by a key in db and not in dbx
  • Signed by a key in the KEK
  • Unsigned, but a hash of the application is in db and not in dbx

Note that UEFI applications are not signed by the PK, unless the PK also happens to be in the KEK.

Not all UEFI firmwares support Secure Boot, although it is a requirement for Windows 8. Some UEFI firmwares support Secure Boot and there's no option to be disabled, which poses a problem for independent developers that do not have access to the PK or any of the keys in the KEK, and therefore can't install their own key or application signature or hash to the whitelist database. Independent developers should develop on systems that either do not support Secure Boot or has an option for Secure Boot to be turned off.

An easy way out to use a loader that is signed by Microsoft, and allows you to load another binary signed by a key and certificate owned by you (called MOK, Machine Owner's Key). Such a loader is shim, used by RedHat, Fedora, Suse, Ubuntu, Arch and many other distros to load GRUB. The filename of the EFI executable is hardwired in shim, but if you rename your loader to GRUBX64.EFI (or GRUBIA32.EFI), you sign it with your MOK key and certificate using sbsigntool, then you can load any loader in Secure Boot you want.

How to use UEFI

Traditional operating systems like Windows and Linux have an existing software architecture and a large code base to perform system configuration and device discovery. With their sophisticated layers of abstraction they don't directly benefit from UEFI. As a result, their UEFI bootloaders do little but prepare the environment for them to run.

An independent developer may find more value in using UEFI to write feature-full UEFI applications, rather than viewing UEFI as a temporary start-up environment to be jettisoned during the boot process. Unlike legacy bootloaders, which typically interact with BIOS only enough to bring up the OS, a UEFI application can implement sophisticated behavior with the help of UEFI. In other words, an independent developer shouldn't be in a rush to leave "UEFI-land".

A good starting point is writing a UEFI application that uses the System Table to fetch a memory map, and uses the "File" protocol to read files from FAT-formatted disks. The next step might be to use the System Table to locate ACPI tables.

Developing with POSIX-UEFI

Main article: POSIX-UEFI

One option to compile UEFI applications on POSIX like systems is POSIX-UEFI. It provides a libc-like API for your EFI application, and ships with a Makefile that can detect and set up the toolchain for you. It can use GCC or LLVM, and defaults to using the host compiler, but a cross compiler is still recommended.

It uses POSIX style typedefs (like uintn_t instead of UINTN), and it does not ship with the standard EFI headers. You can still get interfaces not covered by POSIX-UEFI (such as GOP) by installing the EFI headers from GNU-EFI or EDK2. Also, it compiles with the MS ABI, meaning that UEFI services can be called natively (i.e., without uefi_call_wrapper) so long as your apps are compiled with it as well. The traditional "Hello, world" UEFI program goes like this.

#include<uefi.h>

intmain(intargc,char**argv)
{
printf("Hello, world!\n");
return0;
}

Makefile looks like this:

TARGET = main.efi
include uefi/Makefile

Run make to build it. The result of this process is a PE executable file main.efi.

Developing with GNU-EFI

Main article: GNU-EFI

GNU-EFI can be used to develop both 32-bit and 64-bit UEFI applications. This section will address 64-bit UEFI applications only, and assumes that the development environment itself is running on an x86_64 system, so that no cross-compiler is needed. For a more thorough walk-through of a proper (non-gnu-efi) development environment, see UEFI App Bare Bones.

GNU-EFI includes four things:

  • crt0-efi-x86_64.o: A CRT0 (C runtime initialization code) that provides an entry point that UEFI firmware will call when launching the application, which will in turn call the "efi_main" function that the developer writes.
  • libgnuefi.a: A library containing a single function (_relocate) that is used by the CRT0.
  • elf_x86_64_efi.lds: A linker script used to link ELF binaries into UEFI applications.
  • efi.h and other headers: Convenience headers that provide structures, typedefs, and constants improve readability when accessing the System Table and other UEFI resources.
  • libefi.a: A library containing convenience functions like CRC computation, string length calculation, and easy text printing.
  • efilib.h: Header for libefi.a.

At a bare minimum, a 64-bit UEFI application will need to link against crt0-efi-x86_64.o and libgnuefi.a using the elf_x86_64_efi.lds linker script. Most likely you will want to use the provided headers and the convenience library as well, and this section will assume that going forward.

The traditional "Hello, world" UEFI program is shown below.

#include<efi.h>
#include<efilib.h>
EFI_STATUS
EFIAPI
efi_main(EFI_HANDLEImageHandle,EFI_SYSTEM_TABLE*SystemTable)
{
InitializeLib(ImageHandle,SystemTable);
Print(L"Hello, world!\n");
returnEFI_SUCCESS;
}

A few notes:

  • efi.h is included so we can use types like EFI_STATUS, EFI_HANDLE, and EFI_SYSTEM_TABLE.
  • When creating a 32-bit UEFI application, EFIAPI is empty; GCC will compile the "efi_main" function using the standard C calling convention. When creating a 64-bit UEFI application, EFIAPI expands to "__attribute__((ms_abi))" and GCC will compile the "efi_main" function using Microsoft's x64 calling convention, as specified by UEFI. Only functions that will be called directly from UEFI (including main, but also callbacks) need to use the UEFI calling convention.
  • "InitializeLib" and "Print" are convenience functions provided by libefi.a with prototypes in efilib.h. "InitializeLib" lets libefi.a store a reference to the ImageHandle and SystemTable provided by BIOS. "Print" uses those stored references to print a string by reaching out to UEFI-provided functions in memory. (Later on we will see how to find and call UEFI-provided functions manually.)

This program is compiled and linked as below.

$ gcc main.c \
 -c \
 -fno-stack-protector \
 -fpic \
 -fshort-wchar \
 -mno-red-zone \
 -I /path/to/gnu-efi/headers \
 -I /path/to/gnu-efi/headers/x86_64 \
 -DEFI_FUNCTION_WRAPPER \
 -o main.o
$ ld main.o \
 /path/to/crt0-efi-x86_64.o \
 -nostdlib \
 -znocombreloc \
 -T /path/to/elf_x86_64_efi.lds \
 -shared \
 -Bsymbolic \
 -L /path/to/libs \
 -l:libgnuefi.a \
 -l:libefi.a \
 -o main.so
$ objcopy -j .text \
 -j .sdata \
 -j .data \
 -j .rodata \
 -j .dynamic \
 -j .dynsym \
 -j .rel \
 -j .rela \
 -j .reloc \
 --target=efi-app-x86_64 \
 main.so \
 main.efi

The result of this process is a 44 kB PE executable file main.efi. On a real project you'll probably want to use make or another build tool, and may need to build a cross-compiler. The way GNU-EFI works is a bit contrived: you are wrapping an ELF file built by your normal compiler into PE.

Emulation with QEMU and OVMF

Any recent version of QEMU with a recent version of OVMF will be sufficient to run a UEFI application. QEMU binaries are available for many platforms, and a binary OVMF image (OVMF.fd) can be found on the TianoCore website. QEMU (without any boot disk) can be invoked as below. (To prevent recent versions of QEMU from attempting a PXE (network) boot when no boot disk is found, use -net none.

The recommended way to use OVMF (for QEMU 1.6 or newer) is with a pflash parameter. The instructions below assume you have an OVMF image split into separate CODE and VARS sections.

$ qemu-system-x86_64 -cpu qemu64 \
 -drive if=pflash,format=raw,unit=0,file=path_to_OVMF_CODE.fd,readonly=on \
 -drive if=pflash,format=raw,unit=1,file=path_to_OVMF_VARS.fd \
 -net none

If you prefer to work on a terminal without a display, or via SSH/telnet, you will want to run QEMU without graphics support, using the -nographic flag.

If OVMF does not find a boot disk with a properly named UEFI application (more on this later) it will drop into a UEFI shell.

OVMF shell.png

You can find a list of shell commands here or you can type help at the shell.

Creating disk images

Main article: Bootable Disk

To launch a UEFI application you will need to create a disk image and present it to QEMU. UEFI firmware expects UEFI applications to be stored in a FAT12, FAT16, or FAT32 file system on a GPT or MBR-partitioned disk. Many firmwares only support FAT32, so that's what you'll want to use. Depending on your platform, there are several different ways to create a disk image containing your UEFI application, but they all start by creating a zeroed disk image file. The minimum FAT32 partition size is 33,548,800 bytes, plus you will need space for the primary and secondary GPT tables, plus some slack space so the partition can be aligned correctly. Throughout these examples we will be creating a 48,000,000 byte (93750 512-byte sectors, or 48 MB) disk image.

$ dd if=/dev/zero of=/path/to/uefi.img bs=512 count=93750

uefi-run helper application

The uefi-run application is useful for quick testing. It creates a temporary FAT image containing your EFI application and starts qemu.

$ uefi-run -b /path/to/OVMF.fd -q /path/to/qemu app.efi -- <extra_qemu_args>

uefi-run is not currently packaged for any distribution. You can install it using cargo (the Rust package manager) though ("cargo install uefi-run").

Linux, root required

This approach requires root privileges and uses gdisk, losetup, and mkdosfs. First, use gdisk to create a GPT partition table with a single EFI System Partition.

$ gdisk /path/to/uefi.img
GPT fdisk (gdisk) version 0.8.10
Partition table scan:
 MBR: not present
 BSD: not present
 APM: not present
 GPT: not present
Creating new GPT entries.
Command (? for help): o
This option deletes all partitions and creates a new protective MBR.
Proceed? (Y/N): y
Command (? for help): n
Partition number (1-128, default 1): 1
First sector (34-93716, default = 2048) or {+-}size{KMGTP}: 2048
Last sector (2048-93716, default = 93716) or {+-}size{KMGTP}: 93716
Current type is 'Linux filesystem'
Hex code or GUID (L to show codes, Enter = 8300): ef00
Changed type of partition to 'EFI System'
Command (? for help): w
Final checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING
PARTITIONS!!
Do you want to proceed? (Y/N): y
OK; writing new GUID partition table (GPT) to uefi.img.
Warning: The kernel is still using the old partition table.
The new table will be used at the next reboot.
The operation has completed successfully.

Now you have disk image with GUID partition table on it and an unformatted EFI partition starting at sector 2048. Unless you deviated from the commands shown above, the disk image will use 512-byte sectors, so the EFI partition starts at byte 1,048,576 and is 46,934,528 bytes in length. Use losetup to present the partition to Linux on a loopback device.

losetup --offset 1048576 --sizelimit 46934528 /dev/loop0 /path/to/uefi.img

(If /dev/loop0 is already in use you will need to select a different loopback device.)

Format the partition for FAT32 with mkdosfs.

mkdosfs -F 32 /dev/loop0

The partition can now be mounted, so that we can copy files to it. In this example we use the "/mnt" directory, but you could also create a local directory for temporary use.

mount /dev/loop0 /mnt

Copy any UEFI applications you want to test to the file system.

$ cp /path/to/main.efi /mnt/
$ ...

Finally, unmount the partition and free the loopback device.

$ umount /mnt
$ losetup -d /dev/loop0

uefi.img is now a disk image containing primary and secondary GPT tables, containing a single partition of type EFI, containing a FAT32 file system, containing one or more UEFI applications.

Linux, root not required

This approach uses parted, mformat, and mcopy and can be performed with user privileges. First, use parted to create primary and secondary GPT headers, and a single EFI partition spanning the same range as the approach above.

$ parted /path/to/uefi.img -s -a minimal mklabel gpt
$ parted /path/to/uefi.img -s -a minimal mkpart EFI FAT16 2048s 93716s
$ parted /path/to/uefi.img -s -a minimal toggle 1 boot

Now create a new temporary image file that will contain the EFI partition data and use mformat to format it with FAT16.

dd if=/dev/zero of=/tmp/part.img bs=512 count=91669
mformat -i /tmp/part.img -h 32 -t 32 -n 64 -c 1

Use mcopy to copy any UEFI applications you want to test to the file system.

$ mcopy -i /tmp/part.img /path/to/main.efi ::
$ ...

Finally, write the partition image into the main disk image.

$ dd if=/tmp/part.img of=/path/to/uefi.img bs=512 count=91669 seek=2048 conv=notrunc

uefi.img is now a disk image containing primary and secondary GPT tables, containing a single partition of type EFI, containing a FAT16 file system, containing one or more UEFI applications.

FreeBSD, root required

This approach requires root privileges and uses mdconfig, gpart, newfs_msdos, and mount_msdosfs. First, create a device node that presents the zeroed disk image as a block device. This will let us work on it using standard partitioning and formatting tools.

$ mdconfig -f /path/to/uefi.img
md0

In this example the new block device is md0. Now create the empty primary and secondary GPT tables on the device.

$ gpart create -s GPT md0
md0 created

Now we can add a partition to the disk. We'll specify an "EFI" partition, which just means that GPT will set that partition's GUID to the special "EFI" type. Not all BIOSs require this, and the partition will still be able to be mounted and browsed normally on Linux, FreeBSD, and Windows.

$ gpart add -t efi md0
md0p1 added

Next, create a FAT16 file system on the new partition. You can specify various parameters for the file system if you'd like, but it isn't necessary. Ideally you would create a FAT32 partition for best firmware compatibility but FreeBSD seems to create FAT32 partitions that OVMF can't read.

$ newfs_msdos -F 16 md0p1
newfs_msdos: trim 2 sectors to adjust to a multiple of 9
/dev/md2p1: 93552 sectors in 11694 FAT16 clusters (4096 bytes/cluster)
BytesPerSec=512 SecPerClust=8 ResSectors=1 FATs=2 RootDirEnts=512 Media=0xf0 FATsecs=46 SecPerTrack=9 Heads=16 HiddenSecs=0 HugeSectors=93681

The partition can now be mounted, so that we can copy files to it. In this example we use the /mnt directory, but you could also create a local directory for temporary use.

$ mount_msdosfs /dev/md0p1 /mnt

Copy any UEFI applications you want to test to the file system.

$ cp /path/to/main.efi /mnt/
$ ...

Finally, unmount the partition and free the block device.

$ umount /mnt
$ mdconfig -d -u md0

uefi.img is now a disk image containing primary and secondary GPT tables, containing a single partition of type EFI, containing a FAT16 file system, containing one or more UEFI applications.

Mac OS (root not required)

Mac OS has a single tool (hdiutil) that creates the disk image and copy files at same time.

Let's say that you're creating a UEFI boot for x86_64. By definition the file name should be BOOTX64.EFI and this file should be located in the /EFI/BOOT folder.

First, let's create a temporary folder that will contains all files and folders required for booting UEFI.

$ mkdir -p diskImage/EFI/BOOT

Secondly, let's copy the boot application to the required location:

$ cp bootx64.efi diskImage/EFI/BOOT/BOOTX64.EFI

Finally, let's create a disk image partitioned with GPT, formatted with fat32 (-fs fat32), overriding destination file if needed (-ov), define disk size (-size 48m), define volume name (-volname NEWOS), the file format which the disk will be encoded (-format UDTO - the same used for DVDs/CDs) and the source folder containing the files that will be copied to the new disk:

$ hdiutil create -fs fat32 -ov -size 48m -volname NEWOS -format UDTO -srcfolder diskImage uefi.cdr

uefi.cdr should be ready to be used by QEMU.

Launching UEFI applications

Once your disk image is ready, you can invoke QEMU as below.

$ qemu-system-x86_64 -cpu qemu64 -bios /path/to/OVMF.fd -drive file=uefi.disk,if=ide

When OVMF drops into the UEFI shell, you will see an additional entry in the "Mapping table", labeled "FS0". This indicates that the firmware detected the disk, discovered the partition, and was able to mount the file system. You can explore the file system by switching to it using the DOS-style syntax "FS0:", as illustrated below.

OVMF browse fs.png

You can launch a UEFI application by entering its name.

OVMF run app.png

Notice that the UEFI shell resumed once the application terminated. Of course if this was a proper bootloader it would never resume, but rather launch an OS.

Some commercial UEFI firmware provides UEFI shells or the capability to launch user-selected UEFI applications, such as the firmware that ships with the HP EliteBook line of laptops. Most, however, do not expose this functionality to the end-user.

Debugging

OVMF can be built in debug mode, and it will output logging messages to IO port 0x402. You can use some flags like the ones below to capture the output.

-debugcon file:uefi_debug.log -global isa-debugcon.iobase=0x402

Note that release builds will not output debug messages, or will have reduced output.

See Debugging UEFI applications with GDB.

Running on real hardware

NVRAM variables

Main article: UEFI NVRAM

A UEFI firmware will present most of its configuration options through a text or graphical configuration menu, just like a legacy BIOS. Selections made in these menus are stored in the NVRAM chip between reboots. Unlike legacy BIOS, however, the firmware developer has the option to expose some or all of these "NVRAM variables" to the OS and end-user via convenience functions made resident in RAM by the firmware at boot.

The Linux efivarfs kernel module will use these functions to list NVRAM variables in the /sys/firmware/efi/efivars file. NVRAM variables can also be dumped from within the UEFI shell itself with the dmpstore command. Device boot order is always accessible via NVRAM variables. The Linux program efibootmgr works specifically with the boot order NVRAM variables. The UEFI shell offers the bcfg command for the same purpose.

Bootable UEFI applications

The boot order NVRAM variables determine where firmware will look for UEFI applications to be launched at boot. Although this can be changed (for example, an OS installer might customize the boot entry for the hard drive to which it was installed) firmware typically looks for a UEFI application named "BOOTIA32.efi" (for 32-bit applications) or "BOOTX64.efi" (for 64-bit applications) stored in the "/EFI/BOOT" path in the boot device's file system. This is the default path and name for OVMF.

Unlike a UEFI application launched from the shell, if a bootable UEFI application returns BIOS will continue searching for other boot devices.

Exposed functionality

Real PCs vary in the amount of UEFI capability they expose to the user. For example, even a class 3 machine may not make any mention of UEFI in its BIOS configuration and may not offer a UEFI shell. Additionally, some BIOS vendors make their UEFI firmware configuration screens look identical to their legacy BIOS configuration screens. Class 2 machines may present somewhat confusing boot menus and configuration options. For example, one laptop manufacturer includes a configuration option to enable/disable UEFI (i.e. switch between UEFI and CSM behavior), named "OS: Windows 8". Another laptop, if it fails to find a bootable UEFI application on the selected boot device (or if that application returns a status other than EFI_SUCCESS) will fall back to CSM behavior and then complain that the drive has a corrupted MBR. With time, and with the emergence of class 3 machines, clarity of UEFI boot behavior will improve.

To make testing on real hardware easier, you can install a bootable UEFI application to the internal hard drive of the system that provides a boot menu, such as rEFInd. This may also be convenient for multi-boot scenarios.

PC firmware developers

On x86 and x86-64 platforms, the following BIOS developers offer UEFI firmware:

  • AMI (Aptio).
  • Phoenix (SecureCore, TrustedCore, AwardCore).
  • Insyde (InsydeH20).

UEFI applications in detail

Binary Format

UEFI executables are regular PE32 / PE32+ (Windows x32 / x64) images, with a specific subsystem. Every UEFI application is basically a windows EXE (or DLL) without symbol tables.

Types of UEFI images
Type Description Subsystem
Applications OS loaders and other utility programs. 10
Boot service driver Drivers used by the firmware when booting (e.g. disk drivers, network drivers). 11
Runtime driver Drivers which may stay loaded even after the OS loads and exits the boot services. 12

UEFI images must also specify the type of machine code they contain. A UEFI loader will refuse to boot an incompatible image.

Types of machines
Name / arch Value
x86 0x014c
x86_64 0x8664
Itanium x64 0x0200
UEFI Byte Code 0x0EBC
ARM1 0x01C2
AArch (ARM x64) 0xAA64
RISC-V x32 0x5032
RISC-V x64 0x5064
RISC-V x128 0x5128

[1] ARM means you can use Thumb / Thumb 2 instructions, but UEFI interfaces are in ARM mode.

Initialization

Applications must either load an OS and exit boot services, or return from the main function (in which case the boot loader will look for the next app to load).

Drivers must initialize and then return 0 on success, or an error code. A computer might fail to boot if a required driver fails to load.

Memory

The memory map returned by UEFI will mark the memory areas which drivers use.

Once your OS loader finished, your kernel is allowed to reuse the memory where the boot loader was loaded.

The memory types are Efi{Loader/BootServices/RuntimeServices}{Code/Data}.

After exiting the boot services, you may reuse whatever non-read-only memory the boot drivers used.

However, memory used by the runtime drivers must never be touched - the runtime drivers stay active and loaded for as long as the computer runs.

One way to see a breakdown of a PE file containing a UEFI application is by

$ objdump --all-headers /path/to/main.efi

Its output is quite long. Among other things, it shows the subsystem, that is the type of the UEFI image, mentioned earlier.

Calling Conventions

UEFI specifies the following calling conventions:

  • cdecl for x86 UEFI functions
  • Microsoft's 64-bit calling convention for x86-64 UEFI functions
  • SMC for ARM UEFI functions

This has two impacts on UEFI application developers:

  • A UEFI application's main entry point must expect to be called with the corresponding calling convention.
  • Any UEFI-provided functions that a UEFI application calls must be called with the corresponding calling convention.

Note that functions strictly internal to the application can use whatever calling convention the developer chooses.

POSIX-UEFI, GNU-EFI and GCC

Main article: GNU-EFI

cdecl is the standard calling convention used by GCC, so no special attributes or modifiers are needed for writing the main entry point or calling UEFI functions in an x86 UEFI application developed with GNU-EFI. For x86-64, however, the entry point function must be declared with the "___attribute___((ms_abi))" modifier and all calls to UEFI-provided functions must be made through the "uefi_call_wrapper" thunk. This thunk is called with cdecl, but then translates to the Microsoft x86-64 calling convention before calling the requested UEFI function. This is necessary because older releases of GCC do not support specifying calling conventions for function pointers.

For POSIX-UEFI, which also uses GCC, your entry point looks like the standard main(), and no special ABI is required. Also the build environment takes care of the compiler flags for you, so you can simply call UEFI functions without "uefi_call_wrapper", no matter if you're using the host gcc or a cross-compiler.

For developer convenience, both POSIX-UEFI and GNU-EFI provides the "EFIAPI" macro, which expands to "cdecl" when targeting x86 and "__attribute__(ms_abi))" when targeting x86-64. Additionally, the "uefi_call_wrapper" thunk will simply pass the call through on x86. This allows the same source code to target x86 and x86-64. For example, the following main function will compile with the correct calling convention on both x86 and x86-64 and the call through the "uefi_call_wrapper" thunk will select the correct calling convention to use when calling the UEFI function (in this case, printing a string).

EFI_STATUSEFIAPIefi_main(EFI_HANDLEImageHandle,EFI_SYSTEM_TABLE*SystemTable)
{
EFI_STATUSstatus=uefi_call_wrapper(SystemTable->ConOut->OutputString,
2,
SystemTable->ConOut,
L"Hello, World!\n");
returnstatus;
}

Language binding

UEFI applications are typically written in C, although bindings could be written for any other language that compiles to machine code. Assembly is also an option; a uefi.inc is available for FASM that allows UEFI applications to be written as below.

formatpe64dllefi
entrymain
section'.text'codeexecutablereadable
include'uefi.inc'
main:
; initialize UEFI library
InitializeLib
jc@f
; call uefi function to print to screen
uefi_call_wrapperConOut,OutputString,ConOut,_hello
@@:moveax,EFI_SUCCESS
retn
section'.data'datareadablewriteable
_hellodu'HelloWorld',13,10,0
section'.reloc'fixupsdatadiscardable

As a UEFI application contains normal x86 or x86-64 machine code, inline assembly is also an option in compilers that support it.

EFI Byte Code

UEFI also includes a virtual machine specification based on a byte code format called EFI Byte Code (EBC), which can be used to write platform-independent device drivers, but not UEFI applications. As of 2015 there has been limited use of EBC.

Common Problems

My UEFI application hangs/resets after about 5 minutes

When control is handed to your UEFI application by firmware, it sets a watchdog timer for 5 minutes, after which the firmware is reinvoked as it assumes your application has hung. The firmware in this case will normally try to reset the system (although the OVMF firmware in VirtualBox simply causes the screen to go black and hang). To counteract this, you are required to refresh the watchdog timer before it times out. Alternatively, you can disable it completely with code like

SystemTable->BootServices->SetWatchdogTimer(0,0,0,NULL);

Obviously this is not a problem for most bootloaders, but can cause an issue if you have an interactive loader which waits for user input. Also note that you are required to disable the watchdog timer if you exit back to the firmware.

My bootloader hangs if I use user defined EFI_MEMORY_TYPE values

For the memory management functions in EFI, an OS is meant to be able to use "memory type" values above 0x80000000 for its own purposes. In the OVMF EFI firmware release "r11337" (for Qemu, etc) there is a bug where the firmware assumes the memory type is within the range of values defined for EFI's own use, and uses the memory type as an array index. The end result is an "array index out of bounds" bug; where the higher memory type values (e.g. perfectly legal values above 0x80000000) cause the 64-bit version of the firmware to crash (page fault), and cause incorrect "attribute" values to be reported by the 32-bit version of the firmware. This same bug is also present in whatever version of the EFI firmware VirtualBox uses (which looks like an older version of OVMF); and I suspect (but don't know) that the bug may be present in a wide variety of firmware that was derived from the tianocore project (not just OVMF).

See also

Articles

External Links

Retrieved from "https://wiki.osdev.org/index.php?title=UEFI&oldid=29725"