TianoCore EDK II
TianoCore EDK II, often referred to as EDK II, is an open-source firmware development environment designed to implement the Unified Extensible Firmware Interface (UEFI) and Platform Initialization (PI) specifications.[1][2] It provides a modern, feature-rich, cross-platform toolkit for building UEFI-based firmware, supporting multiple processor architectures including IA-32, x64, ARM, and RISC-V, as well as various operating systems and toolchains such as GCC and Visual Studio.[1][2] The project traces its origins to June 2004, when Intel released its EFI Development Kit (EDK) foundation code under an open-source license as part of the Tiano initiative, aimed at advancing extensible firmware standards.[1] This evolved into the more comprehensive EDK II framework, managed by the TianoCore community, which includes contributions from major technology companies like Intel, HPE, and Microsoft.[1] EDK II has become the de facto reference implementation for UEFI, enabling the creation of bootloaders, drivers, and applications that operate in pre-OS environments.[1][3] Key features of EDK II include modular driver development using C-based programming models, support for secure boot mechanisms, and integration with standards like ACPI for power management and hardware abstraction.[1][2] It is licensed under the BSD-2-Clause Plus Patent License, promoting widespread adoption, and is actively maintained on GitHub with over 1,000 issues and regular releases.[2] Adopted by more than 200 companies, EDK II powers firmware on millions of devices worldwide, from servers and PCs to embedded systems.[1]Introduction
Overview
TianoCore EDK II, commonly referred to as EDK II, serves as the reference implementation of the Unified Extensible Firmware Interface (UEFI) and Platform Initialization (PI) specifications, providing a standardized foundation for firmware development across diverse hardware platforms. It enables the creation of bootable firmware that initializes hardware, loads operating systems, and supports extensible runtime services in compliance with these industry standards.[1] EDK II functions as a cross-platform toolkit designed for developing UEFI drivers, applications, and complete firmware images, supporting a wide range of processor architectures including x86, ARM, and RISC-V.[2] This environment includes modular components such as libraries, protocols, and build tools that facilitate the construction of production-grade firmware volumes.[1] As an open-source project under the TianoCore community, EDK II is hosted on GitHub, allowing global contributors to collaborate on its maintenance and enhancement through a permissive BSD license with patent grants.[2] It evolved from Intel's original Tiano project, which laid the groundwork for open-source EFI implementations.[1]Purpose and Scope
TianoCore EDK II provides a modern, feature-rich, cross-platform firmware development environment designed to enable the creation of UEFI and UEFI Platform Initialization (PI) compliant firmware implementations.[1] Its primary purpose is to offer a modular and extensible framework that supports the development of production-grade firmware, emphasizing firmware as a service to streamline platform initialization and boot processes across diverse hardware.[4] This environment promotes standardization and interoperability by adhering to established specifications, allowing developers to focus on platform-specific innovations without reinventing core firmware components.[5] Key benefits of EDK II include robust support for multiple processor architectures, such as IA-32, x64, ARM, AArch64, and RISC-V, which enables firmware development for a wide range of systems from embedded devices to servers.[6] It achieves improved modularity over earlier frameworks through the use of packages and modules, facilitating code reuse, easier maintenance, and scalable development.[7] As an open-source project governed by the TianoCore community, EDK II drives ongoing innovation via collaborative contributions, ensuring timely updates and adaptations to evolving hardware needs.[4] The scope of EDK II is limited to pre-operating system firmware, encompassing boot-time initialization, driver execution, and runtime services as defined in the UEFI 2.11 and PI 1.9 specifications (as of November 2024).[8] It does not extend to operating system kernel development or full hardware abstraction layers outside the UEFI standards, thereby concentrating on providing a standardized foundation for secure and efficient platform booting. This targeted focus supports innovation in embedded and server environments by enabling customized extensions while maintaining compliance and portability.[1]History
Origins and Early Development
The Tiano project originated in the early 2000s as Intel's initiative to develop an open-source implementation of the Extensible Firmware Interface (EFI), serving as a successor to the traditional 16-bit x86 legacy PC BIOS. Announced by Intel in June 2004, the project released its "Foundation Code" under an open-source license, positioning Tiano as Intel's preferred EFI implementation and laying the groundwork for extensible firmware development.[1] By around 2005, the project transitioned into the EFI Development Kit (EDK), which provided a structured codebase to address the needs of the EFI 1.10 specification, including support for the EFI Driver Model and broader platform compatibility. This evolution enabled developers to create UEFI drivers, applications, and firmware images more effectively, building directly on Tiano's foundation while incorporating updates to align with industry standards.[9][10] The launch of EDK II occurred between 2006 and 2007, driven by community feedback highlighting limitations in the original EDK's build processes and version management. Key improvements in EDK II included enhanced build description files (such as .dsc and .inf formats), support for multiple toolchains (e.g., Visual Studio, GCC, and LLVM/Clang), and a package-based architecture using XML metadata for modular distribution and interoperability across operating systems like Windows, Linux, and OS X. These changes facilitated better version control and scalability, making EDK II a more robust, cross-platform environment.[7][11] Intel spearheaded the formation of the TianoCore community around this time, with early collaboration from HP and Microsoft to foster open-source UEFI development. HP contributed as an early adopter, providing feedback to refine EDK II's features, while Microsoft supported toolchain integration and broader ecosystem adoption. This partnership helped establish TianoCore as a collaborative hub, supporting the UEFI specification as the target standard for firmware interoperability.[1][12][13]Key Milestones and Releases
In 2008, TianoCore EDK II achieved a significant milestone with the release of the UEFI Development Kit 2008 (UDK2008), providing stable support for the UEFI 2.0 specification and marking the transition to a more modular development environment, enabling broader adoption for UEFI-compliant firmware on Intel platforms.[14] By 2010, EDK II aligned with the UEFI Platform Initialization (PI) 1.2 specification through the UDK2010 release, incorporating firmware phases such as SEC and PEI to support more robust initialization processes.[15] This update enhanced compatibility with evolving UEFI standards, including UEFI 2.3, and facilitated platform innovation by integrating PI-compliant binary image generation.[16] In 2016, the project shifted its primary version control from SourceForge to GitHub, following the EDK II 1.24 updates from 2015, streamlining collaboration and release management for the open-source community. This migration improved accessibility to the codebase and supported more frequent stable tags like UDK2015.[17][18][19] Recent releases up to 2025 have expanded EDK II's capabilities, including integration of RISC-V architecture support starting with refactors in 2022—building on initial porting efforts around 2020—and full MMU and toolchain enhancements by 2024.[20] Enhanced security features, such as TPM 2.0 integration via libraries like Tcg2PhysicalPresenceLib, were solidified in releases around 2016 and refined in subsequent updates for measured boot chains.[21] Build specification updates culminated in EDK2-BuildSpecification version 1.28, released on April 30, 2025, which refined processes for binary image compliance with UEFI 2.5 and PI 1.4.[22] These advancements also tied into build system improvements, such as better support for reproducible builds in stable tags like edk2-stable202505.[23] Community expansions have included the formation of the EDK2-Test working group, which maintains the test infrastructure repository and conducts bug triage meetings to validate UEFI and PI compliance. Additionally, efforts toward modularity have been advanced through sub-projects like edk2-platforms, enabling customizable platform configurations and boot-time optimizations.Architecture
Core Components and Packages
The EDK II project organizes its codebase into packages, which are self-contained directories containing source code, libraries, and metadata files that define modules and their dependencies. These packages form the foundational structure for developing UEFI and PI-compliant firmware, enabling modular development and reuse across platforms.[24] The MdePkg serves as the core package, providing the minimum infrastructure required to build UEFI and PI modules, including base libraries and protocol definitions essential for firmware initialization and operation. It includes foundational libraries such as those for memory allocation and management (e.g., BaseMemoryLib for dynamic memory operations) and I/O handling (e.g., IoLib for port I/O access), which abstract hardware interactions to ensure portability. Additionally, MdePkg defines key protocol interfaces for UEFI services, including the Boot Services Protocol for loading images and managing devices, the Runtime Services Protocol for post-boot operations like time and variable services, and the Device Path Protocol for representing device locations in a tree structure.[25] The MdeModulePkg extends the base functionality with core modules that implement standard UEFI components, such as boot services for image loading and device management, along with drivers for common buses like USB (e.g., UsbBusDxe) and PCI (e.g., PciBusDxe). These modules provide reusable implementations for platform-independent features, allowing developers to integrate them into custom firmware volumes.[24][26] The IntelFrameworkPkg offers legacy support for compatibility with earlier EFI specifications, including libraries and modules tailored for Intel platforms that bridge older framework elements to the modern UEFI/PI architecture. It contains protocol definitions and drivers compliant with the Intel Platform Innovation Framework, facilitating transitions from proprietary EFI implementations.[27][24] Core components in EDK II revolve around the UEFI driver model, which uses the Driver Binding Protocol to manage driver attachment to devices. This protocol enables binding mechanisms where drivers produce controller handles and supported protocols, allowing the firmware to dispatch drivers dynamically during boot via services like ConnectController(). Dispatching occurs through the handle database, where drivers register their binding functions (Supported(), Start(), and Stop()) to initialize, configure, or unload based on device needs, ensuring efficient resource management without direct hardware access in the driver entry point.[28][29] EDK II's package structure supports extensibility by allowing developers to create custom packages or add modules to existing ones, such as hardware-specific drivers, through standard INF, DEC, and DSC files that integrate seamlessly into the build system for platform adaptations.[30]Module Types and Firmware Phases
The Platform Initialization (PI) specification defines a structured boot process for firmware, which TianoCore EDK II implements through distinct execution phases and corresponding module types. These phases ensure secure and modular initialization of the platform, starting from the initial reset and progressing to operating system handoff. EDK II modules are classified by type to align with these phases, enabling developers to create components that execute in specific environments with appropriate services available.[31] The Security (SEC) phase is the entry point of the firmware execution, responsible for handling platform restart events, establishing a root of trust, and performing early authentication of the firmware image. In EDK II, this phase operates without permanent memory, using temporary RAM provided by the chipset, and includes initial CPU and chipset initialization to enable secure boot measurements. SEC modules in EDK II, such as the SEC core, serve as the reset vector and are typically implemented as platform-specific firmware volumes that authenticate and decompress the subsequent PEI phase. The SEC phase transitions to the PEI phase by passing a Hand-Off Block (HOB) list containing platform information, such as the location of the PEI firmware volume.[31][32] Following SEC, the Pre-EFI Initialization (PEI) phase initializes permanent system memory and basic hardware components, creating a foundation for higher-level execution. PEI modules, known as PEI Modules (PEIMs), are dispatched by the PEI core to perform tasks like memory discovery, temporary-to-permanent RAM migration, and creation of additional HOBs for data handoff. In EDK II, PEI modules are position-independent executables that run in the PEI environment, supporting modular hardware initialization without relying on full UEFI services. The phase concludes with a handover to the DXE phase, where the PEI core locates and transfers control to the DXE firmware volume via a specific handover protocol, ensuring all necessary HOBs are available for subsequent use.[31][32] The Driver Execution Environment (DXE) phase represents the bulk of platform initialization, where the DXE core provides core UEFI services and a dispatcher manages the loading and execution of drivers. DXE drivers in EDK II, including both runtime and boot-time variants, enable device enumeration, protocol production, and full hardware configuration, such as bus initialization and resource allocation. This phase supports modular drivers that can be dynamically loaded, promoting reusability across platforms. UEFI applications, another module type in this phase, execute as user-mode code with access to the full boot services table but unload after completion. The DXE phase transitions to the Boot Device Selection (BDS) phase by invoking the BDS architectural protocol, which signals the completion of driver dispatch.[31][32] The BDS phase implements platform-specific boot policy, including console initialization, boot option enumeration, and operating system loading attempts. In EDK II, BDS functionality is typically provided by a DXE driver that produces the BDS Architectural Protocol to manage the boot process, such as selecting from UEFI boot variables or falling back to a boot manager. If boot fails, it may reinvoke the DXE dispatcher for additional driver loading. This phase marks the end of firmware execution, handing off control to the loaded operating system loader. Transitions between all phases rely on standardized protocols and HOBs to maintain state and ensure secure, ordered progression without data loss.[31][32]Build System
Tools and Build Processes
The EDK II build system relies on BaseTools, a Python-based suite of utilities that processes module description files (such as INF and DSC formats), generates platform-specific makefiles, performs auto-generation of code, and handles linking to produce UEFI-compliant firmware images.[33] These tools are maintained as a separate repository and can be installed via pip as theedk2-basetools package or built from source within the EDK II workspace to ensure compatibility with the build environment.[33] BaseTools form the core of the EDK II automation, enabling developers to focus on firmware logic rather than manual compilation steps.[34]
As of 2022, the recommended way to build EDK II projects is using Stuart, a Python-based build runner that provides cross-platform consistency, improved dependency management, and support for Python 3.[35] To initiate a build with Stuart, developers first clone the EDK II repository from GitHub and run stuart_setup to create a workspace.conf file, followed by stuart_update to resolve dependencies, and then stuart_build with options like -p MdeModulePkg/MdeModulePkg.dsc -a X64 -t GCC5 to specify the platform, architecture, toolchain, and build type (e.g., DEBUG or RELEASE).[35] The legacy edksetup.sh (Unix-like) or edksetup.bat (Windows) scripts and build command remain available for compatibility but are not the primary method.[36] The process supports multiple operating systems, including Windows, Linux, and macOS, allowing builds in native or virtualized environments.[37] For cross-compilation, the system accommodates targets like x86 (IA32/X64) and ARM architectures by specifying the appropriate architecture flags.[38]
Tool chain selection occurs through configuration files in the Conf directory, where developers choose from supported compilers such as GCC (versions 4.5 and later for Linux/macOS) or Microsoft Visual Studio (e.g., VS2022 for Windows).[39] The TOOL_CHAIN_TAG in target.txt defines the compiler, with predefined options like GCC5 or VS2022x86 that integrate seamlessly with BaseTools for source code compilation and binary generation.[36] This flexibility enables building firmware for diverse hardware platforms without altering core source code.[34]
BaseTools automates the sequence: parsing inputs, generating dependency makefiles, compiling modules, and linking into firmware volumes or executables like EFI applications.[33] Outputs are placed in the Build directory, structured by module, architecture, and build type for easy inspection.[36]
Post-build validation integrates with EDK2-Test, the official test infrastructure for EDK II firmware, which provides a framework of conformance tests for UEFI and PI specifications to verify functionality, security, and compatibility after compilation.[40] Developers run these tests on emulated or physical hardware to ensure the built firmware meets standards, with coverage including boot services, protocol implementations, and secure boot mechanisms. This step is essential for maintaining reliability in production deployments.[40]