Repository navigation
feat(hii): read the HII database from the EFI configuration table - #27
Merged
Merged
Conversation
extract_db() read the HII database only from the HIID ACPI table or through the OCP HiiDB efivar. The standard way is to follow the EFI System Table: HiiDatabaseDxe installs the exported database in the configuration table under gEfiHiiDatabaseProtocolGuid (PcdHiiOsRuntimeSupport, TRUE by default in edk2). Try that first. /sys/firmware/efi/config_table holds the address of the EFI_CONFIGURATION_TABLE array. Scan it for the gEfiHiiDatabaseProtocolGuid entry, at most 256 entries as the count is not exposed, and read the database it points to from /dev/mem. The table does not record the size, so walk the package lists by their PackageLength up to the zero padding that HiiDatabaseDxe leaves after them. When a step fails, print the reason to stderr and fall back to the HIID table and then the OCP variable as before. Not every kernel creates config_table (it is absent on the aarch64 hosts tried). There the step fails before /dev/mem is opened and the next source is tried. Document the order in the README. Tested: cargo test --lib hii::extract; uefisettings hii get on an x86 OVMF guest read the database from the configuration table.
Member
|
Thank you! |
xaionaro
added a commit
that referenced
this pull request
Nov 11, 2026
Firmware may export its HII database at ExitBootServices() into a runtime buffer that it lists in the EFI Configuration Table under EFI_HII_DATABASE_PROTOCOL_GUID (UEFI 2.11 sections 33.2.11.1, 4.6.5, 34.8.1). Upstream e719af3 ("feat(hii): read the HII database from the EFI configuration table", PR #27) reads that buffer in extract_db: it takes the entries' address from /sys/firmware/efi/config_table and reads the entries and the buffer from /dev/mem. This change replaces that reader with one built on the System Table reader: - one reader of the entries, at the firmware's width (e719af3 read 32-bit firmware's 20-byte entries 24 bytes apart): read_entries; - RuntimeMemory bounds every read: System Table, entries, export; - checked arithmetic on every firmware value. The buffer holds what ExportPackageLists() writes (section 34.8.6): package lists back to back, each from its EFI_HII_PACKAGE_LIST_HEADER, whose PackageLength includes it (section 33.3.1.2). The configuration table gives only a pointer (section 4.6.1), so the headers give the extent: the export ends at a header of zeros, which edk2 leaves in the zeroed buffer that it allocates a quarter larger (edk2-stable202608 MdeModulePkg/Universal/HiiDatabaseDxe/Database.c:3600-3621), or where its runtime region leaves no room for another header. A PackageLength shorter than its header, one past the region, a package list whose packages, walked by their EFI_HII_PACKAGE_HEADER.Length, do not end with an EFI_HII_PACKAGE_END package, a header alone, exactly at its PackageLength (section 33.3.1.1), package lists past the 16 MiB cap of HII database files, and an export without a package list are refused. Whether the pointer is virtual is left open (sections 4.6.1, 33.2.11.1) and edk2 converts no configuration table (MdeModulePkg/Core/RuntimeDxe/Runtime.c:358), so it is taken as physical first (PointerSpace::Physical). The methods are named acpi, efivar and systab (HiiMethod). A caller names one (HiiSource::Method) or takes the automatic order (HiiSource::Auto, the default): acpi, then efivar, then systab. Upstream 3af9ff3 tried the configuration table first; the automatic order tries it last, as the vendor ACPI tables need no /dev/mem, and the OCP variable keeps the buffer that those machines read before. Each method tells its source absent apart from other errors (HiiMethodError): - absent: no vendor ACPI table file exists; the HiiDB variable does not exist (HiiDbVariableAbsent); Linux locates no System Table, as on a BIOS boot or an aarch64 boot without UEFI (SystemTableError::NotBootedByEfi, NoUefiInFdt, NoSystemTable); the System Table lists no export (HiiExportError::NotListed); - refused: a MemoryAccessDenied (kernel lockdown, the kernel's checks of /dev/mem or /proc/kcore) or EACCES/EPERM in any layer of the error; - failed: anything else, such as a source that fails its checks or a missing memory map. The automatic order moves on past absent and failed methods and stops at a refused one, so that no later method reads around what the kernel or the administrator refused. NoHiiDatabase lists each method tried, in order, with its error, and is the only report of a method that gave no database: upstream's messages of the configuration table's failure go. At debug level each method's error and the method that gave the database are logged, and at warn level each method that failed before the one that gave it, which the CLI prints with RUST_LOG=warn. How the acpi and efivar methods read is unchanged. identify looks for the database by the same methods, in the same order: an ACPI table file or the HiiDB variable exists, or the System Table lists the export. The systab method answers no where its source is absent, or where the build reads no firmware memory map, and fails where it is refused or fails. HiiBackend gains extract_db_from, read_hiidb_from and set_from, which read through HiiSourceOptions (the methods and the memory of the efivar method), and identify_machine_using, which identify_machine calls with the automatic order. SystemTableError gains RegionEndsBefore. EFI_HII_DATABASE_PROTOCOL_GUID is the one constant of that GUID: upstream's HII_DATABASE_GUID goes, as do its tests, whose cases the tests of read_sysfs_hex, into_table, read_export and read_hii_export cover. README.md says in one line that the automatic order reads the configuration table last, and clippy.toml that DevMem is again the only caller of read_physical_memory_at. Test Plan: RUSTFLAGS='-D warnings' cargo test -j1 --locked --lib -- \ extract:: system_table:: source:: against stubs of the selector, the classification and the export reader, on an earlier tree, whose 53 tests of this filter lack 11 of this commit's 64: 16 failed, 37 passed; all pass in the run below RUSTFLAGS='-D warnings' cargo test -j1 --locked --lib with NotBootedByEfi and NoSystemTable classed as failed: hii_db_published_once_any_file_exists, finds_its_source_absent_where_linux_locates_no_system_table and probe_answers_false_where_the_source_is_absent failed, 815 passed RUSTFLAGS='-D warnings' cargo test -j1 --locked --lib with an FDT without linux,uefi-system-table failing and NoUefiInFdt classed as failed: finds_its_source_absent_where_the_fdt_gives_no_uefi, probe_answers_false_where_the_source_is_absent, uefi_system_table_reads_its_property_of_chosen and arm64_refuses_what_locates_no_system_table failed, 814 passed RUSTFLAGS='-D warnings' cargo test -j1 --locked --lib without the walk of each list's packages to its End package: the 2 new tests of read_export failed, 816 passed RUSTFLAGS='-D warnings' cargo test -j1 --locked --lib without the warning: auto_warns_of_each_failed_method_that_it_reads_past failed, 817 passed RUSTFLAGS='-D warnings' cargo test -j1 --locked --lib --bins lib 818 passed, bin 50 passed, 0 failed 25 mutants, one per check of the export reader, of the classification and of identify's answer (a guard disabled, the pointer space, the GUID or a class changed), 3 more of those checks (a header's room at the region's end left unread, the address taken as physical only, an export past the cap classed absent), and 8 of the End package walk, its class and the warning (an End package that ends before the PackageLength or is longer than its header, no End package, a package shorter than its header or past the PackageLength, a Type above EFI_HII_PACKAGE_END taken as END, absent methods warned of, an unterminated export classed absent), each followed by RUSTFLAGS='-D warnings' cargo test -j1 --locked --lib 36 killed, each by a named failing test identify_machine() given the acpi method only, not the automatic order: no test fails; nothing in the tree calls identify_machine(), and a unit test of it would read this machine's /sys/firmware Signed-off-by: Dmitrii Okunev <xaionaro@meta.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
extract_db() read the HII database only from the HIID ACPI table or through the OCP HiiDB efivar. The standard way is to follow the EFI System Table: HiiDatabaseDxe installs the exported database in the configuration table under gEfiHiiDatabaseProtocolGuid (PcdHiiOsRuntimeSupport, TRUE by default in edk2).
Try that first. /sys/firmware/efi/config_table holds the address of the EFI_CONFIGURATION_TABLE array. Scan it for the gEfiHiiDatabaseProtocolGuid entry, at most 256 entries as the count is not exposed, and read the database it points to from /dev/mem. The table does not record the size, so walk the package lists by their PackageLength up to the zero padding that HiiDatabaseDxe leaves after them. When a step fails, print the reason to stderr and fall back to the HIID table and then the OCP variable as before.
Not every kernel creates config_table (it is absent on the aarch64 hosts tried). There the step fails before /dev/mem is opened and the next source is tried.
Document the order in the README.
Tested: cargo test --lib hii::extract; uefisettings hii get on an x86 OVMF guest read the database from the configuration table.