mirror of
git://git.yoctoproject.org/meta-intel.git
synced 2025-07-19 12:59:03 +02:00

Patch changes: * 0001-sd-boot-Link-RMC-library-into-bootloader-and-stub.patch removed because make is no longer used. * 0001-sd-boot-stub-check-LoadOptions-contains-data.patch removed because it was accepted upstream. * 0001-partially-revert-sd-boot-stub-Obtain-PE-section-offs.patch added to support RMC functionality. Upstream removed a snippet that found the root directory because they didn't need it anymore, but RMC does. * 0002-sd-boot-fix-RMC-compatibility-with-systemd-boot-and-.patch added to support building with meson instead of make. * Others refreshed inc file changes: * Don't commit pin, we can maintain these patches OK for now * EXTRA_OEMAKE -> EXTRA_OEMESON, and removed some superfluous options Signed-off-by: California Sullivan <california.l.sullivan@intel.com>
253 lines
8.6 KiB
Diff
253 lines
8.6 KiB
Diff
From b780c67c780bae2f834d73017044680fabca4268 Mon Sep 17 00:00:00 2001
|
|
From: Jianxun Zhang <jianxun.zhang@linux.intel.com>
|
|
Date: Wed, 1 Jun 2016 16:32:22 -0700
|
|
Subject: [PATCH 3/5] sd-boot: Load board-specific boot entries from RMC
|
|
database
|
|
|
|
RMC provides a centralized database file on ESP. The DB contains
|
|
fingerprints and any file blobs associated to physical boards.
|
|
Callers can fetch board-specific data with fingerprint info
|
|
collected from board at runtime if there is any record matched
|
|
board's fingerprint.
|
|
|
|
To let bootloader know which file blob in RMC should be queried,
|
|
a special config file BOOTENTRY.CONFIG is defined as:
|
|
|
|
boot.conf
|
|
install.conf
|
|
|
|
Bootloader calls RMC APIs and other functions to perform these
|
|
tasks before it shows boot menu to user:
|
|
|
|
(1) Load RMC database file from ESP
|
|
(2) Collect fingerprint data from board
|
|
(3) Query BOOTENTRY.CONFIG from RMC DB with fingerprint
|
|
(4) Parse BOOTENTRY.CONFIG to know names of boot entry files
|
|
(5) Query boot entry files one by one from RMC DB, and add
|
|
them into sd-boot config data.
|
|
|
|
The final effect is that bootloader will show board-specific
|
|
boot entries in boot menu to user. User then can choose one
|
|
of them to boot system with the selected configuration.
|
|
|
|
If any of these steps fails, bootloader simply skips loading
|
|
RMC configs or any entry file not successfully fetched from
|
|
RMC DB. Once any entry is loaded successfully from RMC DB,
|
|
bootloader skips loading any boot entries from ESP.
|
|
|
|
Upstream-Status: Pending
|
|
|
|
Signed-off-by: Jianxun Zhang <jianxun.zhang@linux.intel.com>
|
|
Signed-off-by: California Sullivan <california.l.sullivan@intel.com>
|
|
---
|
|
src/boot/efi/boot.c | 148 +++++++++++++++++++++++++++++++++++++++++++++++++++-
|
|
1 file changed, 146 insertions(+), 2 deletions(-)
|
|
|
|
diff --git a/src/boot/efi/boot.c b/src/boot/efi/boot.c
|
|
index b9c7c8394..93cfaf193 100644
|
|
--- a/src/boot/efi/boot.c
|
|
+++ b/src/boot/efi/boot.c
|
|
@@ -16,6 +16,7 @@
|
|
|
|
#include <efi.h>
|
|
#include <efilib.h>
|
|
+#include <rmc_api.h>
|
|
|
|
#include "console.h"
|
|
#include "disk.h"
|
|
@@ -35,6 +36,9 @@ static const char __attribute__((used)) magic[] = "#### LoaderInfo: systemd-boot
|
|
|
|
static const EFI_GUID global_guid = EFI_GLOBAL_VARIABLE;
|
|
|
|
+static CHAR8* rmc_db;
|
|
+static rmc_fingerprint_t *rmc_fp;
|
|
+
|
|
enum loader_type {
|
|
LOADER_UNDEFINED,
|
|
LOADER_EFI,
|
|
@@ -1684,6 +1688,136 @@ static VOID config_free(Config *config) {
|
|
FreePool(config->entry_oneshot);
|
|
}
|
|
|
|
+/* Derived from line_get_key_value(), we could consolidate two functions later */
|
|
+static CHAR8 *get_line(CHAR8 *content, UINT64 *pos) {
|
|
+ CHAR8 *line;
|
|
+ UINT64 linelen;
|
|
+
|
|
+skip:
|
|
+ line = content + *pos;
|
|
+ if (*line == '\0')
|
|
+ return NULL;
|
|
+
|
|
+ linelen = 0;
|
|
+ while (line[linelen] && !strchra((CHAR8 *)"\n\r", line[linelen]))
|
|
+ linelen++;
|
|
+
|
|
+ /* move pos to next line */
|
|
+ *pos += linelen;
|
|
+ if (content[*pos])
|
|
+ (*pos)++;
|
|
+
|
|
+ /* empty line */
|
|
+ if (linelen == 0)
|
|
+ goto skip;
|
|
+
|
|
+ /* terminate line */
|
|
+ line[linelen] = '\0';
|
|
+
|
|
+ /* remove leading whitespace */
|
|
+ while (strchra((CHAR8 *)" \t", *line)) {
|
|
+ line++;
|
|
+ linelen--;
|
|
+ }
|
|
+
|
|
+ /* remove trailing whitespace */
|
|
+ while (linelen > 0 && strchra((CHAR8 *)" \t", line[linelen-1]))
|
|
+ linelen--;
|
|
+ line[linelen] = '\0';
|
|
+
|
|
+ if (*line == '#')
|
|
+ goto skip;
|
|
+
|
|
+ return line;
|
|
+}
|
|
+
|
|
+/* load rmc database file from ESP and try to get fingerprint. These
|
|
+ * are essential information indicating we could query rmc data for
|
|
+ * this board at least
|
|
+ * return 0 if both database file and fingerprint can be obtained, otherwise
|
|
+ * non-zero value is returned.
|
|
+ *
|
|
+ * Note: db and fp hold valid values only when this function returns 0.
|
|
+ * Caller is responsible to free allocated memory pointed by *db and *fp when
|
|
+ * this function returns 0.
|
|
+ */
|
|
+
|
|
+static UINTN rmc_initialize(EFI_FILE *root_dir, EFI_SYSTEM_TABLE *sys_table, CHAR8 **db, rmc_fingerprint_t **fp) {
|
|
+ UINTN len;
|
|
+ UINTN ret = 1;
|
|
+
|
|
+ if (!db || !fp)
|
|
+ return ret;
|
|
+
|
|
+ *db = NULL;
|
|
+ *fp = NULL;
|
|
+
|
|
+ /* load rmc database */
|
|
+ len = file_read(root_dir, L"\\rmc.db", 0, 0, db);
|
|
+
|
|
+ if (len <= 0)
|
|
+ goto done;
|
|
+
|
|
+ *fp = AllocateZeroPool(sizeof(rmc_fingerprint_t));
|
|
+ /* call rmc to get fingerprint. We will use single-action rmc APIs to query multiple files.
|
|
+ * This should bring a better performance than calling double-action rmc API every time.
|
|
+ */
|
|
+ if (rmc_get_fingerprint(sys_table, *fp))
|
|
+ goto done;
|
|
+
|
|
+ ret = 0;
|
|
+done:
|
|
+ if (ret) {
|
|
+ FreePool(*db);
|
|
+ FreePool(*fp);
|
|
+ }
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+/* load RMC entries
|
|
+ * return TRUE when at least one entry is loaded, otherwise, return FALSE
|
|
+ */
|
|
+static BOOLEAN config_load_rmc_entries(Config *config, EFI_HANDLE *device, CHAR16 *loaded_image_path, CHAR8 *db, rmc_fingerprint_t *fp) {
|
|
+ CHAR8 *boot_entry = NULL;
|
|
+ CHAR8 *boot_config = NULL;
|
|
+ rmc_file_t rp;
|
|
+ CHAR8 *line;
|
|
+ UINT64 pos = 0;
|
|
+ BOOLEAN ret = FALSE;
|
|
+
|
|
+ if (!db || !fp)
|
|
+ return ret;
|
|
+
|
|
+ /* query boot entry config file */
|
|
+ if (rmc_query_file_by_fp(fp, db, "BOOTENTRY.CONFIG", &rp))
|
|
+ return ret;
|
|
+
|
|
+ /* file blob read from rmc db is not necessarily null-terminated, and we
|
|
+ * should keep mem where rmc db lives from change during parsing
|
|
+ */
|
|
+ boot_config = AllocatePool(rp.blob_len * sizeof(CHAR8) + 1);
|
|
+ CopyMem(boot_config, rp.blob, rp.blob_len);
|
|
+ boot_config[rp.blob_len] = '\0';
|
|
+ /* parse boot entry config */
|
|
+ while ((line = get_line(boot_config, &pos))) {
|
|
+ if (rmc_query_file_by_fp(fp, db, (char *)line, &rp))
|
|
+ continue;
|
|
+ if (rp.blob_len > 0) {
|
|
+ boot_entry = AllocatePool(rp.blob_len * sizeof(CHAR8) + 1);
|
|
+ CopyMem(boot_entry, rp.blob, rp.blob_len);
|
|
+ boot_entry[rp.blob_len] = '\0';
|
|
+ config_entry_add_from_file(config, device,
|
|
+ stra_to_str(line), boot_entry,
|
|
+ loaded_image_path);
|
|
+ /* tell caller success when a RMC entry is loaded */
|
|
+ ret = TRUE;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
|
|
CHAR16 *s;
|
|
CHAR8 *b;
|
|
@@ -1696,6 +1830,7 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
|
|
UINT64 init_usec;
|
|
BOOLEAN menu = FALSE;
|
|
CHAR16 uuid[37];
|
|
+ BOOLEAN rmc_entry = FALSE;
|
|
|
|
InitializeLib(image, sys_table);
|
|
init_usec = time_usec();
|
|
@@ -1736,6 +1871,9 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
|
|
}
|
|
}
|
|
|
|
+ /* Initialize rmc before loading any config */
|
|
+ rmc_initialize(root_dir, sys_table, &rmc_db, &rmc_fp);
|
|
+
|
|
/* the filesystem path to this image, to prevent adding ourselves to the menu */
|
|
loaded_image_path = DevicePathToStr(loaded_image->FilePath);
|
|
efivar_set(L"LoaderImageIdentifier", loaded_image_path, FALSE);
|
|
@@ -1743,11 +1881,15 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
|
|
ZeroMem(&config, sizeof(Config));
|
|
config_load_defaults(&config, root_dir);
|
|
|
|
+ if (rmc_db && rmc_fp)
|
|
+ rmc_entry = config_load_rmc_entries(&config, loaded_image->DeviceHandle, loaded_image_path, rmc_db, rmc_fp);
|
|
+
|
|
/* scan /EFI/Linux/ directory */
|
|
config_entry_add_linux(&config, loaded_image, root_dir);
|
|
|
|
- /* scan /loader/entries/\*.conf files */
|
|
- config_load_entries(&config, loaded_image->DeviceHandle, root_dir, loaded_image_path);
|
|
+ /* scan /loader/entries/\*.conf files only when no RMC entry is loaded */
|
|
+ if (rmc_entry == FALSE)
|
|
+ config_load_entries(&config, loaded_image->DeviceHandle, root_dir, loaded_image_path);
|
|
|
|
/* sort entries after version number */
|
|
config_sort_entries(&config);
|
|
@@ -1841,6 +1983,8 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
|
|
out:
|
|
FreePool(loaded_image_path);
|
|
config_free(&config);
|
|
+ FreePool(rmc_db);
|
|
+ FreePool(rmc_fp);
|
|
uefi_call_wrapper(root_dir->Close, 1, root_dir);
|
|
uefi_call_wrapper(BS->CloseProtocol, 4, image, &LoadedImageProtocol, image, NULL);
|
|
return err;
|
|
--
|
|
2.14.3
|
|
|