Dear coreboot developers,
With Raptor Lake, we introduced the Pre-Memory Sign-of-Life feature which displays an on-screen message while firmware components such as coreboot, Firmware Support Package Memory (FSP-M) or, CSME perform long time operations during pre-memory stages.
We propose to take advantage of a proprietary driver Intel already supports, validates and includes in FSP silicon: the Intel Graphics PEIM (Pre-EFI Initialization Module) driver also known as the GOP (Graphical Output Protocol) driver.
This driver is designed to run in post-memory initialization stages. Therefore, we derived a new version capable of running in pre-memory stages which we called µGOP. This version is specifically designed to perform graphics legacy VGA initialization.
We intend to keep providing such a binary base solution on the long run as it addresses our software convergence goals and is compatible with early platform development stage constraints. libgfxinit supports can always be added later by the open-source community once the Graphics Programmer Reference Manuals are published.
Below, we present the work we performed to run this µGOP driver from coreboot romstage. It allows to initialize graphics with a very similar flow compared to libgfxinit use.
Our goal is to start collecting feedback. We will release all the patches on coreboot.org under the ugop topic soon.
1. µGOP driver interface
The uGOP PEIM provides the following PEIM-to-PEIM protocol under the 31a4622d-0e21-40a2-80db-c44208fce1b5
GUID.
#define PEI_PREMEM_GRAPHICS_PPI_GUID \ { \ 0x31a4622d, 0x0e21, 0x40a2, 0x80, 0xdb, 0xc4, 0x42, 0x08, 0xfc, 0xe1, 0xb5 \ };
The protocol is composed of three fields.
struct { UINT32 Version; PREMEM_PEI_GRAPHICS_INIT PreMemGraphicsPpiInit; PREMEM_PEI_GRAPHICS_EXIT PreMemGraphicsPpiExit; } PEI_MICRO_GRAPHICS_PPI;
- The current
Version
is0x00010000
. Where the upper 16 bits represent the major (1) and the lower 16 bits represent the minor number. PreMemGraphicsPpiInit()
typedef EFI_STATUS (EFIAPI *PREMEM_PEI_GRAPHICS_INIT) ( IN VOID *Vbt );
The
PreMemGraphicsPpiInit()
should be supplied with a pointer to the Video BIOS Table.PreMemGraphicsPpiExit()
does not take any parameters. This function must be called to disable VGA graphics configuration once not necessary anymore. Not performing this operation may lead to undesirable behaviour when other graphics stack starts (GOP in FSP-S or Operating System driver).
2. Integration
As we intend to run µGOP driver in romstage, we want to keep the required coreboot code as small and efficient as possible. For this reason, we discarded re-using the EDK2 code which would have a major impact on the romstage binary size in addition to adding complication to the build scripts. Instead, we implemented a limited set of Pre-EFI Initialization services. The code is small and designed to accommodate a simple PEIM driver such as µGOP.
2.1. PEI services
µGOP depends on a limited of PEI services:
InstallPpi()
to install the PEIM Graphics PPILocatePpi()
to access PEIM-to-PEIM Interface (PPI) DependenciesAllocatePool()
to dynamically allocate memory to handle internal data structure such as display information …GetHobList()
andCreateHob()
to access Hand Off Blocks (HOB) holding runtime dataReportStatusCode()
to report debug information which coreboot prints usingprintk
.
Those services implemented in coreboot are pretty straightforward and fit in less than 300 lines of code.
2.2. PEI services pointer
µGOP expects to find the PEI services pointer in the architecture size word immediately preceding the Interrupt Descriptor Table (IDT) (cf. Platform Initialization (PI) Specification 5.4 PEI Services Table Retrieval). Since coreboot x86/exception module already sets up the IDT and as we do not want to disrupt this configuration we create a copy of the IDT. But we include an extra architecture size word preceding the table to store the PEI services pointer.
Note that FSP memory installs its own IDT but it backups and restores the one we have set up. Therefore, there is no risk of having PEI services pointer conflicts.
2.3. Portable Executable Relocation
As we need to execute the µGOP binary in place, we need to perform a relocation operation of the Portable Executable binary. Since memory space is limited in the pre-memory stages, it is preferable to perform a static relocation operation during the firmware stitching operation.
Fortunately, most of the logic and code is already available as this operation is performed on the FSP-M binary. We only have to add explicit support for EFI binaries (cf. 76762 cbfstool: Add relocation support for EFI binaries).
2.4. Uncompressed VBT
As µGOP requires the Video BIOS Table (VBT) and since memory space is limited in the pre-memory stages, it is preferable to keep VBT in uncompressed form in CBFS. We introduced the CONFIG_VBT_CBFS_COMPRESSION
configuration entry to allow this (cf. 76816 drivers/intel/gma/Kconfig: Add VBT compression configuration entry).
3. Code flow
4. Performances analysis
The analysis below is based on a µGOP binary with eDP and HDMI support.
4.1. Size impact
When CONFIG_UGOP_EARLY_GRAPHICS
is set
ugop.efi
is included as a CBFS fileromstage
includes extra code:pei.c
,ugop.c
andux.c
vbt.bin
is stored uncompressed instead of lzma compressed
CBFS File | UGOP_EARLY_GRAPHICS=n (bytes) | UGOP_EARLY_GRAPHICS=y (bytes) | Delta (bytes) |
---|---|---|---|
µGOP | 0 | 68448 | 68448 |
romstage | 126128 | 136256 | 10128 |
vbt.bin | 1264 | 9216 | 7952 |
Total | 127392 | 213920 | 86528 |
The use of µGOP in coreboot represents a size increase of around 84 KB per region (COREBOOT
, FW_MAIN_A
and FW_MAIN_B
).
4.2. Regular Boot time impact (no Sign-of-Life)
On a Meteor Lake Google Rex board, we performed 5 warm reset cycles (without and with CONFIG_UGOP_EARLY_GRAPHICS
set) and we collected the cbmem -t
outputs. We computed the median time of each duration (time between two timestamps) and then performed a comparison with a threshold of 0.5 ms.
Start ID | Start Description | End ID | End Description | Delta (ms) |
---|---|---|---|---|
947 | CSE received 'CPU Reset Done Ack sent' from PMC | 991 | Die Management Unit (DMU) load completed | +1.0 |
507 | starting to verify body (load+SHA2+RSA) | 508 | finished loading body | +4.7 |
510 | finished verifying body signature (RSA) | 511 | starting TPM PCR extend | -0.8 |
1030 | finished EC verification | 1040 | finished storage device initialization | +1.4 |
The only relevant impact is the verification of the image (507 → 508): +4.7 ms and it can be explained by the 84 KB size increase of the image.
Overall the boot time impact is about 5 ms and concentrated on verstage
.
4.3. Cache-As-Ram
For µGOP to execute properly, we have to provide some memory allocation services (allocate_pool
and create_hob
). These services relies on cache-as-ram memory reservation (.bss
section). We looked at the two new object files:
Object file | .bss section size (bytes) |
---|---|
pei.o | 6730 |
ugop.o | 9 |
6739 |
With µGOP sign-of-life, there is an extra 7 KB cache-as-ram use.
4.4. Conclusion
The SPINOR and cache-as-RAM space use along with the boot performance penalty are limited and comparable to what it would be with libgfxinit.
We also noticed that µGOP is faster to bring-up graphics than libgfxinit. Indeed, according to previously captured numbers on Raptor Lake compared to some number of µGOP on Meteor Lake, µGOP is three times faster to bring up graphics than libgfxinit on an eDP panel (119 ms vs 373 ms).
5. Summary
This Sign-of-Life µGOP driver based implementation presents the following advantages:
- it needs a limited code addition
- it has a limited impact on the performance
- its flow and boot performance impact is comparable to libgfxinit solution
- it is compatible with our software convergence goals
- it can be available during new platform development early stages which help our partners to test the feature and stabilize the platform
Regards,
–
Jeremy
One Emacs to rule them all