mirror of
https://github.com/morgan9e/systemd
synced 2026-04-14 08:25:20 +09:00
boot: Add .dtbauto section matching in PE section discovery against HWIDs and FW-provided DT
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user