From: anonymix007 <48598263+anonymix007@users.noreply.github.com> Date: Wed, 4 Sep 2024 09:49:29 +0000 (+0300) Subject: boot: Add .dtbauto section matching in PE section discovery against HWIDs and FW... X-Git-Tag: v257-rc1~19^2~5 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c033267912beaabcdb2198fc94dc20cbf260e070;p=thirdparty%2Fsystemd.git boot: Add .dtbauto section matching in PE section discovery against HWIDs and FW-provided DT --- diff --git a/src/boot/efi/pe.c b/src/boot/efi/pe.c index 26dfcd4291f..00739a7c742 100644 --- a/src/boot/efi/pe.c +++ b/src/boot/efi/pe.c @@ -1,5 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ +#include "chid.h" +#include "devicetree.h" #include "pe.h" #include "util.h" @@ -162,11 +164,46 @@ static bool pe_section_name_equal(const char *a, const char *b) { return true; } -static void pe_locate_sections( +static bool pe_use_this_dtb( + const void *dtb, + size_t dtb_size, + const void *base, + const Device *device, + size_t section_nb) { + + assert(dtb); + + EFI_STATUS err; + + err = devicetree_match(dtb, dtb_size); + if (err == EFI_SUCCESS) + return true; + if (err != EFI_UNSUPPORTED) + return false; + + /* There's nothing to match against if firmware does not provide DTB and there is no .hwids section */ + if (!device || !base) + return false; + + const char *compatible = device_get_compatible(base, device); + if (!compatible) + return false; + + err = devicetree_match_by_compatible(dtb, dtb_size, compatible); + if (err == EFI_SUCCESS) + return true; + if (err == EFI_INVALID_PARAMETER) + log_error_status(err, "Found bad DT blob in PE section %zu", section_nb); + return false; +} + +static void pe_locate_sections_internal( const PeSectionHeader section_table[], size_t n_section_table, const char *const section_names[], size_t validate_base, + const void *device_table, + const Device *device, PeSectionVector sections[]) { assert(section_table || n_section_table == 0); @@ -206,6 +243,20 @@ static void pe_locate_sections( continue; } + /* Special handling for .dtbauto sections compared to plain .dtb */ + if (pe_section_name_equal(section_names[i], ".dtbauto")) { + /* .dtbauto sections require validate_base for matching */ + if (!validate_base) + break; + if (!pe_use_this_dtb( + (const uint8_t *) SIZE_TO_PTR(validate_base) + j->VirtualAddress, + j->VirtualSize, + device_table, + device, + i)) + continue; + } + /* At this time, the sizes and offsets have been validated. Store them away */ sections[i] = (PeSectionVector) { .memory_size = j->VirtualSize, @@ -224,6 +275,73 @@ static void pe_locate_sections( } } +static bool looking_for_dbauto(const char *const section_names[]) { + assert(section_names); + + for (size_t i = 0; section_names[i]; i++) + if (pe_section_name_equal(section_names[i], ".dtbauto")) + return true; + return false; +} + +static void pe_locate_sections( + const PeSectionHeader section_table[], + size_t n_section_table, + const char *const section_names[], + size_t validate_base, + PeSectionVector sections[]) { + + if (!looking_for_dbauto(section_names)) + return pe_locate_sections_internal( + section_table, + n_section_table, + section_names, + validate_base, + /* device_base */ NULL, + /* device */ NULL, + sections); + + /* It doesn't make sense not to provide validate_base here */ + assert(validate_base != 0); + + const void *hwids = NULL; + const Device *device = NULL; + + if (!firmware_devicetree_exists()) { + /* Find HWIDs table and search for the current device */ + PeSectionVector hwids_section = {}; + + pe_locate_sections_internal( + section_table, + n_section_table, + (const char *const[]) { ".hwids", NULL }, + validate_base, + /* device_table */ NULL, + /* device */ NULL, + &hwids_section); + + if (hwids_section.memory_offset != 0) { + hwids = (const uint8_t *) SIZE_TO_PTR(validate_base) + hwids_section.memory_offset; + + EFI_STATUS err = chid_match(hwids, hwids_section.memory_size, &device); + if (err != EFI_SUCCESS) { + log_error_status(err, "HWID matching failed, no DT blob will be selected: %m"); + hwids = NULL; + } + } else + log_info("HWIDs section is missing, no DT blob will be selected"); + } + + return pe_locate_sections_internal( + section_table, + n_section_table, + section_names, + validate_base, + hwids, + device, + sections); +} + static uint32_t get_compatibility_entry_address(const DosFileHeader *dos, const PeFileHeader *pe) { /* The kernel may provide alternative PE entry points for different PE architectures. This allows * booting a 64-bit kernel on 32-bit EFI that is otherwise running on a 64-bit CPU. The locations of any