ru
en

Intel® Whitley UEFI/EDK2: портирование firmware и board bring-up (практическое руководство, 2026)

Платформа Intel® Whitley – одна из последних серверных платформ Xeon, где ещё можно было осмысленно работать с firmware через EDK2. Здесь сформировалась зрелая архитектура UEFI (PEI/DXE, UBA), понятная и пригодная для реального портирования плат. Для многих инженеров Whitley стала точкой входа в серверный BIOS – балансом между доступностью кода и зависимостью от закрытых компонентов вроде FSP.

Однако со временем ситуация вокруг Whitley начала меняться. По мере развития новых поколений серверных платформ и усиления зависимости от проприетарных компонентов, интерес к поддержке устаревающих решений в открытых репозиториях стал снижаться. Поддержка таких платформ требует значительных усилий, при этом практическая ценность для широкого круга разработчиков постепенно уменьшается.

AIC Tucane

В результате этого процесса код, связанный с Whitley, начал постепенно исчезать из основного дерева edk2-platforms. Это отражает общую тенденцию: смещение фокуса в сторону более новых платформ и одновременное сокращение поддержки решений, зависящих от устаревших или закрытых бинарных компонентов. Несмотря на это, накопленный опыт и архитектурные подходы Whitley остаются крайне ценными для понимания серверного firmware.

Именно поэтому возникает логичный вопрос: почему платформа, сыгравшая такую важную роль в развитии серверного firmware, была исключена из основного репозитория? Понимание причин этого решения позволяет не только лучше ориентироваться в текущем состоянии экосистемы EDK2, но и осознанно использовать накопленные знания при работе с существующими системами.

Почему код Whitley исчез из edk2-platforms

Если Вы открываете свежий edk2-platforms и не находите там WhitleyOpenBoardBinPkg — Вам не показалось. Начиная с конца 2025 года, из дерева проекта начали целенаправленно удалять платформы Intel Xeon поколения Skylake-SP / Cascade Lake / Ice Lake (Whitley).

Это не случайность и не «чистка мусора». Причины вполне системные:

  • Зависимость от закрытого FSP
    Ключевые этапы инициализации аппаратной части (память, PCIe, управление питанием) выполняются через FSP – бинарный компонент Intel. Без него платформа не может функционировать.
  • Отсутствие обновлений и поддержки
    Для устаревающих платформ прекращается выпуск новых версий FSP, что приводит к проблемам безопасности и совместимости.
  • Снижение интереса сообщества
    Реальные кейсы использования EDK2 для серверных платформ ограничены, а большинство OEM-решений остаются проприетарными.
  • Изменение стратегии развития платформ
    Новые поколения серверных CPU ещё сильнее завязаны на закрытые компоненты, что делает поддержку старых «частично открытых» решений менее приоритетной.

Зачем сохранять Whitley сегодня

Несмотря на удаление из основного репозитория, Whitley остаётся важной платформой для изучения:

  • это одно из последних поколений, где архитектура firmware остаётся относительно прозрачной
  • здесь хорошо прослеживаются ключевые механизмы EDK2 и UEFI
  • это практическая база для экспериментов, reverse engineering и портирования

Цель данной статьи:

  • сохранить знания о структуре и подходах к портированию
  • предоставить практическое руководство по адаптации firmware под конкретную плату
  • рассмотреть пример портирования на AIC Tucana (на базе JunctionCity)

Обзор

До конца 2025 года в репозиториии edk2-platforms существовали реализации для плат WilsonCityRvp, CooperCityRvp, JunctionCity:

%BOLD%edk2-platforms%END%
└── Platform
    └── Intel
        └── WhitleyOpenBoardPkg
            ├── %BOLD%CooperCityRvp%END%
            ├── %BOLD%JunctionCity%END%
            └── %BOLD%WilsonCityRvp%END%

Соответствующие бинарные файлы FlashDescriptor.bin и Me.bin находились в репозитории edk2-non-osi:

%BOLD%edk2-non-osi%END%
└── Platform
    └── Intel
        └── WhitleyOpenBoardBinPkg
            └── Ifwi
                ├── %BOLD%CooperCityRvp%END%
                │   ├── FlashDescriptor.bin
                │   └── Me.bin
                ├── %BOLD%JunctionCity%END%
                │   ├── FlashDescriptor.bin
                │   └── Me.bin
                └── %BOLD%WilsonCityRvp%END%
                    ├── FlashDescriptor.bin
                    └── Me.bin

Кроме того, в репозитории edk2-platforms находился шаблон для портироания кода – BoardPortTemplate:

%BOLD%edk2-platforms%END%
└── Platform
    └── Intel
        └── WhitleyOpenBoardPkg
            └── %BOLD%BoardPortTemplate%END%

вместе с инструкцией по использованию этого шаблона.

Поскольку мы работаем с серверной платой AIC Tucana (Рис.1), далее мы приведем подробные инструкции по портированию именно для этой платы.

Tucana based server
Рис.1. Hand made Tucana server.

Мы не будем использовать шаблон BoardPortTemplate, а возьмем код JunctionCity, так как он наиболее проработан и вполне соответствует нашей плате.

Прежде чем приступать к портированию, необходимо зафиксировать соглашения по именованию плат и переменных в коде.

Соглашения по именованию плат

Именование плат в файловой системе лишь частично связано с именованием, используемым в коде.

Соглашение TypeBoardName используется в коде несколькими способами:

  • перечисление EFI_PLATFORM_TYPE, например, TypeJunctionCity или TypeTucana
  • UBA Protocol, например gEfiPlatformTypeJunctionCityProtocolGuid
  • иногда в имени неиспользуемого UBA PPI
  • иногда для декорирования имён функций и переменных. Последовательно используется в UBA PEI коде, чтобы избежать конфликтов имён, когда поддерживается несколько экземпляров library class.

Нет требования, чтобы имя каталога платы совпадало с кодом. Самое важное – чтобы разработчики сопоставляли исходный код со своим аппаратным обеспечением. Последовательность желательна, но очень часто один порт платы поддерживает несколько плат и системных продуктов, поэтому строгое соответствие имени каталога файловой системы и содержимого кода не требуется.

Портирование кода для AIC Tucana

Перед началом работы, желательно выбрать достаточно уникальное имя, так как UBA‑функциональность WhitleyOpenBoardPkg спроектирована так, чтобы упростить поддержку множества плат, соответствующих данной платформе.

Наш выбор прост, так как плата уже имеет вполне лаконичное название, мы будем использовать каталог с именем Tucana.

Создадим этот каталог и Скопируем в него содержимое JunctionCity:

 cd edk2-platforms/Platform/Intel/WhitleyOpenBoardPkg/
 mkdir Tucana
 cp -r JunctionCity/* Tucana/

Сразу переименуем каталог Tucana/Uba/TypeJunctionCity:

 mv Temp/Uba/TypeJunctionCity/ Temp/Uba/TypeTucana/

В результате получим следующее дерево каталогов:

./%BOLD%Tucana%END%
├── Library
│   ├── IpmiPlatformHookLib
│   │   ├── IpmiPlatformHookLib.c
│   │   └── IpmiPlatformHookLib.inf
│   └── PeiPlatformHookLib
│       ├── PeiPlatformHooklib.c
│       └── PeiPlatformHooklib.inf
├── PlatformPkg.dsc
├── PlatformPkg.fdf
├── Uba
│   └── Type%BOLD%Tucana%END%
│       ├── Dxe
│       │   ├── IioCfgUpdateDxe
│       │   │   ├── IioCfgUpdateDxe.c
│       │   │   ├── IioCfgUpdateDxe.h
│       │   │   └── IioCfgUpdateDxe.inf
│       │   ├── SlotDataUpdateDxe
│       │   │   ├── SlotDataUpdateDxe.c
│       │   │   ├── SlotDataUpdateDxe.h
│       │   │   └── SlotDataUpdateDxe.inf
│       │   └── UsbOcUpdateDxe
│       │       ├── UsbOcUpdateDxe.c
│       │       ├── UsbOcUpdateDxe.h
│       │       └── UsbOcUpdateDxe.inf
│       └── Pei
│           ├── AcpiTablePcds.c
│           ├── GpioTable.c
│           ├── IioBifurInit.c
│           ├── KtiEparam.c
│           ├── PcdData.c
│           ├── PchEarlyUpdate.c
│           ├── PeiBoardInit.h
│           ├── PeiBoardInitLib.c
│           ├── PeiBoardInitLib.inf
│           ├── SlotTable.c
│           ├── SoftStrapFixup.c
│           └── UsbOC.c
├── build_board.py
└── build_config.cfg

В каталоге Tucana, во всех файлах, необходимо осуществить поиск и замену всех вхождений 'JunctionCity' на 'Tucana'. Делать это нужно аккуратно и независимо от того, яаляется ли строка 'JunctionCity' частью имени функции или какого‑либо другого идентификатора.

Далее во всех файлах с расширением .inf в каталоге Tucana/Uba/TypeTucana/ необходимо заменить значения FILE_GUID на новые. Получить новые уникальные значения GUID можно с помошью утилиты uuidgen:

 bash-5.3# uuidgen
 b4a693b9-8ad6-43e4-897e-97534fcb8c48

Следующим шагом будет добавление нового enum EFI_PLATFORM_TYPE:

diff --git a/Silicon/Intel/WhitleySiliconPkg/Include/PlatformInfoTypes.h b/Silicon/Intel/WhitleySiliconPkg/Include/PlatformInfoTypes.h
index 2c421c1a6d..db67101838 100644
--- a/Silicon/Intel/WhitleySiliconPkg/Include/PlatformInfoTypes.h
+++ b/Silicon/Intel/WhitleySiliconPkg/Include/PlatformInfoTypes.h
@@ -71,6 +71,7 @@ typedef enum {
   //
   TypeBoardPortTemplate = 0x80,               // 0x80
   TypeJunctionCity,
+  TypeTucana,                                 // 0x82
   TypeAowanda,
   EndOfVendorPlatformTypeEnum
 } EFI_PLATFORM_TYPE;

соблюдая нумерацию плат.

Поскольку наша плата AIC Tucana теперь числится под номером 0x82, нам необходимо, в файле Tucana/PlatformPkg.dsc, присвоить ей номер 0x82:

Tucana/PlatformPkg.dsc:

  gPlatformTokenSpaceGuid.PcdBoardId|%BOLD%0x82%END%   # TypeTucana

Теперь необходимо добавить новый GUID протокола UBA DXE в файл WhitleyOpenBoardPkg/PlatformPkg.dec:

diff --git a/Platform/Intel/WhitleyOpenBoardPkg/PlatformPkg.dec b/Platform/Intel/WhitleyOpenBoardPkg/PlatformPkg.dec
index 6cecd7c289..c422f9fff0 100644
--- a/Platform/Intel/WhitleyOpenBoardPkg/PlatformPkg.dec
+++ b/Platform/Intel/WhitleyOpenBoardPkg/PlatformPkg.dec
@@ -168,6 +168,7 @@
   gEfiPlatformTypeWilsonCitySMTProtocolGuid           = { 0xEE55562D, 0x4001, 0xFC27, { 0xDF, 0x16, 0x7B, 0x90, 0xEB, 0xE1, 0xAB, 0x04 } }
   gEfiPlatformTypeCooperCityRPProtocolGuid            = { 0x45c302e1, 0x4b86, 0x89be, { 0xab, 0x0f, 0x5e, 0xb5, 0x57, 0xdf, 0xe8, 0xd8 } }
   gEfiPlatformTypeJunctionCityProtocolGuid            = { 0xB1C2B1C9, 0xB606, 0x4B62, { 0x9D, 0x78, 0xCB, 0xD6, 0x0F, 0xF9, 0x0D, 0x0C } }
+  gEfiPlatformTypeTucanaProtocolGuid                  = { 0x04a127ed, 0x6862, 0x4d23, { 0x90, 0xab, 0x3a, 0x4c, 0xb1, 0xc8, 0x20, 0xe2 } }
   gEfiPlatformTypeAowandaProtocolGuid                 = { 0x65231A3C, 0xC343, 0x4C7E, { 0xA4, 0x5E, 0x0F, 0x99, 0x74, 0xA6, 0x90, 0x83 } }
   gEfiPlatformTypeBoardPortTemplateProtocolGuid       = { 0xecaa1083, 0x9d72, 0x44d1, { 0xb1, 0x42, 0x0e, 0xd8, 0x0a, 0xd1, 0x37, 0xd2 } }
 #

создав его с помощью утилиты uuidgen.

Далее, необходимо добавить плату AIC Tucana в switch функции BoardInitDxeDriverEntry(), в файле WhitleyOpenBoardPkg/Uba/BoardInit/Dxe/BoardInitDxe.c:

diff --git a/Platform/Intel/WhitleyOpenBoardPkg/Uba/BoardInit/Dxe/BoardInitDxe.c b/Platform/Intel/WhitleyOpenBoardPkg/Uba/BoardInit/Dxe/BoardInitDxe.c
index 18c05e2d01..37d9ad93ef 100644
--- a/Platform/Intel/WhitleyOpenBoardPkg/Uba/BoardInit/Dxe/BoardInitDxe.c
+++ b/Platform/Intel/WhitleyOpenBoardPkg/Uba/BoardInit/Dxe/BoardInitDxe.c
@@ -99,6 +99,16 @@ BoardInitDxeDriverEntry (
       ASSERT_EFI_ERROR (Status);
       break;
 
+   case TypeTucana:
+      Status = gBS->InstallProtocolInterface (
+        &Handle,
+        &gEfiPlatformTypeTucanaProtocolGuid,
+        EFI_NATIVE_INTERFACE,
+        NULL
+        );
+      ASSERT_EFI_ERROR (Status);
+      break;
+
    case TypeAowanda:
         Status = gBS->InstallProtocolInterface (
           &Handle,

Затем добавить gEfiPlatformTypeTucanaProtocolGuid в файлы WhitleyOpenBoardPkg/Uba/BoardInit/Dxe/BoardInitDxe.inf, WhitleyOpenBoardPkg/Uba/UbaMain/StaticSkuDataDxe/StaticSkuDataDxe.inf:

diff --git a/Platform/Intel/WhitleyOpenBoardPkg/Uba/BoardInit/Dxe/BoardInitDxe.inf b/Platform/Intel/WhitleyOpenBoardPkg/Uba/BoardInit/Dxe/BoardInitDxe.inf
index ef47d1b1b8..8bff030ac0 100644
--- a/Platform/Intel/WhitleyOpenBoardPkg/Uba/BoardInit/Dxe/BoardInitDxe.inf
+++ b/Platform/Intel/WhitleyOpenBoardPkg/Uba/BoardInit/Dxe/BoardInitDxe.inf
@@ -64,6 +64,7 @@
   gEfiPlatformTypeWilsonCitySMTProtocolGuid              #PRODUCER
   gEfiPlatformTypeCooperCityRPProtocolGuid               #PRODUCER
   gEfiPlatformTypeJunctionCityProtocolGuid               #PRODUCER
+  gEfiPlatformTypeTucanaProtocolGuid                     #PRODUCER
   gEfiPlatformTypeAowandaProtocolGuid                    #PRODUCER
 
 [FixedPcd]
diff --git a/Platform/Intel/WhitleyOpenBoardPkg/Uba/UbaMain/StaticSkuDataDxe/StaticSkuDataDxe.inf b/Platform/Intel/WhitleyOpenBoardPkg/Uba/UbaMain/StaticSkuDataDxe/StaticSkuDataDxe.inf
index ac663d9b43..a74ba7133a 100644
--- a/Platform/Intel/WhitleyOpenBoardPkg/Uba/UbaMain/StaticSkuDataDxe/StaticSkuDataDxe.inf
+++ b/Platform/Intel/WhitleyOpenBoardPkg/Uba/UbaMain/StaticSkuDataDxe/StaticSkuDataDxe.inf
@@ -59,4 +59,5 @@
   gEfiPlatformTypeWilsonCitySMTProtocolGuid OR
   gEfiPlatformTypeWilsonCityRPProtocolGuid  OR
   gEfiPlatformTypeJunctionCityProtocolGuid  OR
+  gEfiPlatformTypeTucanaProtocolGuid        OR
   gEfiPlatformTypeAowandaProtocolGuid

К этому надо относиться очень внимательно. Например, если вы забудете о файле WhitleyOpenBoardPkg/Uba/UbaMain/StaticSkuDataDxe/StaticSkuDataDxe.inf, вы не сможете загружать операционные системы, а найти подобную ошибку в будущем, будет весьма сложно.

В заключение, следует добавить опцию сборки в файл edk2-platforms/Platform/Intel/build.cfg:

diff --git a/Platform/Intel/build.cfg b/Platform/Intel/build.cfg
index a5c3262240..f8ae3fc6d5 100644
--- a/Platform/Intel/build.cfg
+++ b/Platform/Intel/build.cfg
@@ -70,5 +70,6 @@ CooperCityRvp = WhitleyOpenBoardPkg/CooperCityRvp/build_config.cfg
 WilsonCityRvp = WhitleyOpenBoardPkg/WilsonCityRvp/build_config.cfg
 BoardTiogaPass = PurleyOpenBoardPkg/BoardTiogaPass/build_config.cfg
 JunctionCity = WhitleyOpenBoardPkg/JunctionCity/build_config.cfg
+Tucana = WhitleyOpenBoardPkg/Tucana/build_config.cfg
 Aowanda = WhitleyOpenBoardPkg/Aowanda/build_config.cfg
 AlderlakePRvp = AlderlakeOpenBoardPkg/AlderlakePRvp/build_config.cfg

Теперь можно осуществить тестовую сборку. Однако с этим мы торопиться не будем.

Распаковка оригинального BIOS

На плате AIC Tucana флешки BIOS и BMC не распаяны, а находятся в так называемых кроватках. Поэтому считать оригинальную прошивку BIOS не составляет большого труда. Сделать это можно, например, с помошью дешевого программатора CH341A. Мы уже рассказывали о нем в статье, посвященной плате VisionFive 2 и говорили о том, что перед использованием программатор CH341A надо несколько доработать.

Считать прошивку BIOS AIC Tucana можно с помощью утилиты flashrom следующим образом:

 bash-5.3# flashrom --programmer ch341a_spi -VV -c W25Q256JV_Q -r BIOS-Tucana-0.bin

Далее нам понадобится утилита ifdtool, входящая в состав исходников Coreboot. Собрать утилиту ifdtool очень просто:

 wget https://coreboot.org/releases/coreboot-26.03.tar.xz
 tar xJvf coreboot-26.03.tar.xz
 cd coreboot-26.03/util/ifdtool/
 make

Полученный исполняемый файл ifdtool можно скопировать в каталог, где мы сохранили образ прошивки и распаковать оригинальный файл BIOS-Tucana-0.bin:

 ./ifdtool -p %BOLD%icl%END% -x BIOS-Tucana-0.bin

Здесь, icl – аббревиатура нашей платформы Ice Lake-SP (Gen3).

В результате мы получим следующие пять файлов:

 flashregion_0_flashdescriptor.bin
 flashregion_15_ptt.bin
 flashregion_1_bios.bin
 flashregion_2_intel_me.bin
 flashregion_5_device_exp.bin

Для чего нам все это нужно?

Если говорить простыми словами, в оригинальной прошивке могут находиться регионы, которых нет в репозитори edk2-non-osi или их версия не соответствует нашей плате. Поэтому в первую очередь нас будут интересовать регон Intel Me и оригинальный дескриптор flashdescriptor.bin, в котором содержится необходимая информация о расположении всех регионов в образе BIOS.

В данной статье мы не будем подробно рассматривать структуру образа UEFI/BIOS, а сосредоточимся на практической задаче: получить работоспособный образ на основе кода EDK II с использованием нужных нам регионов оригинальной прошивки.

Создадим в репозитории edk2-non-osi каталог edk2-non-osi/Platform/Intel/WhitleyOpenBoardBinPkg/Ifwi/Tucana/ и поместим в него необходимые регионы, предварительно переименовав файлы так, чтобы получить следующее дерево:

%BOLD%edk2-non-osi%END%
└── Platform
    └── Intel
        └── WhitleyOpenBoardBinPkg
            └── Ifwi
                └── %BOLD%Tucana%END%
                    ├── License.txt
                    ├── descriptor.bin
                    ├── devexp1.bin
                    ├── me.bin
                    └── ptt.bin

Теперь, нам необходимо изменить скрипт сборки так, чтобы при создании образа UEFI/BIOS использовалась информация, содержащаяся в файле descriptor.bin и все регионы, которые мы разместили в репозитории edk2-non-osi. Все изменения, можно представить в виде следующей разности:

--- JunctionCity/build_board.py	2026-04-17 23:27:43.669191538 +0300
+++ Tucana/build_board.py	2026-04-17 23:27:43.681191538 +0300
@@ -1,5 +1,5 @@
 # @ build_board.py
-# Extensions for building JunctionCity using build_bios.py
+# Extensions for building Tucana using build_bios.py
 #
 #
 # Copyright (c) 2021 - 2023, Intel Corporation. All rights reserved.
@@ -173,9 +173,11 @@
     final_ifwi = os.path.join(fv_path, "{}.bin".format(board_fd))
 
     ifwi_ingredients_path = os.path.join(config["WORKSPACE_PLATFORM_BIN"], "Ifwi", config["BOARD"])
-    flash_descriptor = os.path.join(ifwi_ingredients_path, "FlashDescriptor.bin")
-    intel_me = os.path.join(ifwi_ingredients_path, "Me.bin")
-    _merge_files((flash_descriptor, intel_me, final_fd), final_ifwi)
+    flash_descriptor = os.path.join(ifwi_ingredients_path, "descriptor.bin")
+    intel_me = os.path.join(ifwi_ingredients_path, "me.bin")
+    ptt = os.path.join(ifwi_ingredients_path, "ptt.bin")
+    devexp1 = os.path.join(ifwi_ingredients_path, "devexp1.bin")
+    _merge_files((flash_descriptor, intel_me, ptt, devexp1, final_fd), final_ifwi)
     if os.path.isfile(final_fd):
         print("IFWI image can be found at {}".format(final_ifwi))
     return None

Наконец мы готовы к сборке образа UEFI/BIOS.

Сборка

Для сборки UEFI/BIOS необходимы четыре репозитория, причем именно те срезы, которые еще содержат код для нашей платформы. Вам нет необходимости заниматься рутиной поиска нужных версий в открытых репозиториях Tianocore и готовить собственные ветки. Мы уже проделали эту работу и вы можете апробовать это на ветках tucana следующих зеркал:

Непосредственно сборку можно осуществить следующим образом:

 #!/bin/bash

 git clone -b tucana https://git.radix-linux.su/Tianocore/FSP.git
 git clone -b tucana https://git.radix-linux.su/Tianocore/edk2.git
 git clone -b tucana https://git.radix-linux.su/Tianocore/edk2-non-osi.git
 git clone -b tucana https://git.radix-linux.su/Tianocore/edk2-platforms.git

 ( cd edk2 ; git submodule update --init --recursive )

 #
 # Set Environment:
 # ===============

 export EDK_TOOLS_PATH="$PWD/edk2/BaseTools"
 export PACKAGES_PATH="$PWD/edk2:$PWD/edk2-platforms:$PWD/edk2-non-osi:$PWD/FSP"

 . edk2/edksetup.sh

 make -C edk2/BaseTools

 #
 # Build:
 # =====
 ( cd edk2-platforms/Platform/Intel
   python3 build_bios.py --toolchain GCC5 --RELEASE --platform %BOLD%Tucana%END% \
 )

В результате сборки будет создан каталог Build и получен файл Build/WhitleyOpenBoardPkg/RELEASE_GCC5/FV/TUCANA.bin. Это и есть образ, который можно записать на флешку:

 bash-5.3# flashrom --programmer ch341a_spi -VV -c W25Q256JV_Q -w TUCANA.bin

и проверить его работоспособность.

(Продолжение следует).


В заключение можно сказать, что платформа Whitley, несмотря на её удаление из edk2-platforms, остаётся важным этапом в развитии серверного firmware. Она позволяет понять архитектуру UEFI на практике и служит основой для изучения и экспериментов.