On Wed, 2016-08-03 at 11:04 -0700, Jianxun Zhang wrote: > Invoke RMC APIs in this bootloader to query board-specific data > from RMC database(DB) file on ESP. Data can be boot entries or a > global kernel boot command line fragment specific to a type of > board supported in RMC DB. > > Bootloader queries a file blob named BOOTENTRY.CONFIG from RMC > DB first. In success, bootloader parses BOOTENTRY.CONFIG to get > name of each boot entry file associated to the type of running > board, and then tries to load the entry into internal config data > structure. Once any entry is loaded from RMC DB, bootloader skips > loading conf files on ESP. > > BOOTENTRY.CONFIG has a very simple format - every line is a boot > entry file's name. For example, to specify two boot entries in it: > > boot.conf > install.conf > > Bootloader also seeks another file named KBOOTPARAM in RMC dB. > when it can obtain this file associated to the type of running > board, it appends what in file to the end of kernel command > line before it boots up kernel. The appending is effective on > every boot entry, so it is called "global" cmdline fragment. > > When Bootloader doesn't get config, an entry or cmdline fragment > for the type of board, it simply moves to the next step. > > Signed-off-by: Jianxun Zhang <[email protected]>
Reviewed-by: Saul Wold <[email protected]> > --- > .../recipes-bsp/systemd-boot/systemd-boot.bbappend | 20 ++ > ...d-boot-Link-RMC-libraries-into-bootloader.patch | 31 +++ > ...d-board-specific-boot-entries-from-RMC-da.patch | 263 > +++++++++++++++++++++ > ...pport-global-kernel-command-line-fragment.patch | 66 ++++++ > 4 files changed, 380 insertions(+) > create mode 100644 common/recipes-bsp/systemd-boot/systemd- > boot.bbappend > create mode 100644 common/recipes-bsp/systemd-boot/systemd- > boot/0001-sd-boot-Link-RMC-libraries-into-bootloader.patch > create mode 100644 common/recipes-bsp/systemd-boot/systemd- > boot/0002-sd-boot-Load-board-specific-boot-entries-from-RMC-da.patch > create mode 100644 common/recipes-bsp/systemd-boot/systemd- > boot/0003-sd-boot-Support-global-kernel-command-line-fragment.patch > > diff --git a/common/recipes-bsp/systemd-boot/systemd-boot.bbappend > b/common/recipes-bsp/systemd-boot/systemd-boot.bbappend > new file mode 100644 > index 0000000..f42434c > --- /dev/null > +++ b/common/recipes-bsp/systemd-boot/systemd-boot.bbappend > @@ -0,0 +1,20 @@ > +DEPENDS += "rmc" > + > +FILESEXTRAPATHS_prepend := "${THISDIR}/systemd-boot:" > + > +EXTRA_OEMAKE += 'EFI_LDFLAGS="-L${STAGING_DIR_HOST}/usr/lib" > EFI_CFLAGS="-I${STAGING_INCDIR}/rmc/efi -DRMC_EFI"' > + > +# Pin systemd revision down for systemd-boot recipe. > +# Patches could not be applied cleanly when systemd in OE is > updated, > +# though we don't expect a lot of changes could happen in > bootloader. > +# RMC is designed to support a large number of types of boards, so > we > +# should do explicit update with validation to prevent regression > even > +# resolving conflicts for a new tip could be done in a short time. > + > +# Revision: systemd 230 in OE > +SRCREV = "3a74d4fc90cb322a4784a3515bef7118c8f8c5ba" > + > +SRC_URI += "file://0001-sd-boot-Link-RMC-libraries-into- > bootloader.patch \ > + file://0002-sd-boot-Load-board-specific-boot-entries- > from-RMC-da.patch \ > + file://0003-sd-boot-Support-global-kernel-command-line- > fragment.patch \ > + " > diff --git a/common/recipes-bsp/systemd-boot/systemd-boot/0001-sd- > boot-Link-RMC-libraries-into-bootloader.patch b/common/recipes- > bsp/systemd-boot/systemd-boot/0001-sd-boot-Link-RMC-libraries-into- > bootloader.patch > new file mode 100644 > index 0000000..c8867a2 > --- /dev/null > +++ b/common/recipes-bsp/systemd-boot/systemd-boot/0001-sd-boot-Link- > RMC-libraries-into-bootloader.patch > @@ -0,0 +1,31 @@ > +From b7775f24928fca01600cac1077ff3f215aa6362d Mon Sep 17 00:00:00 > 2001 > +From: Jianxun Zhang <[email protected]> > +Date: Sat, 21 May 2016 18:52:07 -0700 > +Subject: [PATCH 1/3] sd-boot: Link RMC libraries into bootloader > + > +Add two RMC libraries into bootloader binary. EFI stub is not > changed > +until we really need rmc in stub. > + > +Upstream-Status: Pending > + > +Signed-off-by: Jianxun Zhang <[email protected]> > +--- > + Makefile.am | 2 +- > + 1 file changed, 1 insertion(+), 1 deletion(-) > + > +diff --git a/Makefile.am b/Makefile.am > +index 305099a..ff21ebd 100644 > +--- a/Makefile.am > ++++ b/Makefile.am > +@@ -2802,7 +2802,7 @@ $(top_builddir)/src/boot/efi/%.o: > $(top_srcdir)/src/boot/efi/%.c $(addprefix $(t > + > + $(systemd_boot_solib): $(systemd_boot_objects) > + $(AM_V_CCLD)$(LD) $(efi_ldflags) $(systemd_boot_objects) \ > +- -o $@ -lefi -lgnuefi $(shell $(CC) -print-libgcc- > file-name); \ > ++ -o $@ -lefi -lgnuefi -lrmclefi -lrsmpefi $(shell > $(CC) -print-libgcc-file-name); \ > + nm -D -u $@ | grep ' U ' && exit 1 || : > + > + $(systemd_boot): $(systemd_boot_solib) > +-- > +2.7.4 > + > diff --git a/common/recipes-bsp/systemd-boot/systemd-boot/0002-sd- > boot-Load-board-specific-boot-entries-from-RMC-da.patch > b/common/recipes-bsp/systemd-boot/systemd-boot/0002-sd-boot-Load- > board-specific-boot-entries-from-RMC-da.patch > new file mode 100644 > index 0000000..ddad940 > --- /dev/null > +++ b/common/recipes-bsp/systemd-boot/systemd-boot/0002-sd-boot-Load- > board-specific-boot-entries-from-RMC-da.patch > @@ -0,0 +1,263 @@ > +From f714cdc84b791d84099f7461c4f223677456720f Mon Sep 17 00:00:00 > 2001 > +From: Jianxun Zhang <[email protected]> > +Date: Wed, 1 Jun 2016 16:32:22 -0700 > +Subject: [PATCH 2/3] 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 <[email protected]> > +--- > + src/boot/efi/boot.c | 160 > +++++++++++++++++++++++++++++++++++++++++++++++++++- > + 1 file changed, 158 insertions(+), 2 deletions(-) > + > +diff --git a/src/boot/efi/boot.c b/src/boot/efi/boot.c > +index 30c1ead..43b0793 100644 > +--- a/src/boot/efi/boot.c > ++++ b/src/boot/efi/boot.c > +@@ -15,6 +15,8 @@ > + > + #include <efi.h> > + #include <efilib.h> > ++#include <rmcl.h> > ++#include <rsmp.h> > + > + #include "console.h" > + #include "disk.h" > +@@ -33,6 +35,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, > +@@ -1702,6 +1707,148 @@ 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, CHAR8 **db, > rmc_fingerprint_t **fp) { > ++ UINTN len; > ++ EFI_GUID smbios_guid = SMBIOS_TABLE_GUID; > ++ EFI_GUID smbios3_guid = SMBIOS3_TABLE_GUID; > ++ VOID *smbios_entry = NULL; > ++ UINT64 smbios_struct_addr = 0; > ++ UINT16 smbios_struct_len = 0; > ++ 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; > ++ > ++ /* locate smbios entry table, try both 32 and 64 bit */ > ++ if (LibGetSystemConfigurationTable(&smbios3_guid, > &smbios_entry) != EFI_SUCCESS > ++ && > LibGetSystemConfigurationTable(&smbios_guid, &smbios_entry) != > EFI_SUCCESS) > ++ goto done; > ++ > ++ /* call rsmp to get fp */ > ++ if (rsmp_get_smbios_strcut(smbios_entry, > &smbios_struct_addr, &smbios_struct_len)) > ++ goto done; > ++ > ++ *fp = AllocateZeroPool(sizeof(rmc_fingerprint_t)); > ++ > ++ if (rsmp_get_fingerprint_from_smbios_struct((BYTE *) > smbios_struct_addr, *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_policy_file_t rp; > ++ CHAR8 *line; > ++ UINT64 pos = 0; > ++ BOOLEAN ret = FALSE; > ++ > ++ if (!db || !fp) > ++ return ret; > ++ > ++ /* query boot entry config file */ > ++ if (query_policy_from_db(fp, db, RMC_POLICY_BLOB, > "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 (query_policy_from_db(fp, db, RMC_POLICY_BLOB, > (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; > +@@ -1714,6 +1861,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(); > +@@ -1745,6 +1893,8 @@ EFI_STATUS efi_main(EFI_HANDLE image, > EFI_SYSTEM_TABLE *sys_table) { > + return EFI_LOAD_ERROR; > + } > + > ++ /* Initialize rmc before loading any config */ > ++ rmc_initialize(root_dir, &rmc_db, &rmc_fp); > + > + /* the filesystem path to this image, to prevent adding > ourselves to the menu */ > + loaded_image_path = DevicePathToStr(loaded_image- > >FilePath); > +@@ -1753,11 +1903,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); > +@@ -1851,6 +2005,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.7.4 > + > diff --git a/common/recipes-bsp/systemd-boot/systemd-boot/0003-sd- > boot-Support-global-kernel-command-line-fragment.patch > b/common/recipes-bsp/systemd-boot/systemd-boot/0003-sd-boot-Support- > global-kernel-command-line-fragment.patch > new file mode 100644 > index 0000000..6d077f1 > --- /dev/null > +++ b/common/recipes-bsp/systemd-boot/systemd-boot/0003-sd-boot- > Support-global-kernel-command-line-fragment.patch > @@ -0,0 +1,66 @@ > +From a38be4fe8ffed142abbba92f7ad91a8f7b8f1ace Mon Sep 17 00:00:00 > 2001 > +From: Jianxun Zhang <[email protected]> > +Date: Mon, 20 Jun 2016 13:08:20 -0700 > +Subject: [PATCH 3/3] sd-boot: Support global kernel command line > fragment > + > +Query file blob KBOOTPARAM from RMC. If it exists, we append > +it to the new linux boot entry's cmdline. A boot entry could > +be read from a .conf file on ESP, RMC database, or embedded > +linux image. content in KBOOTPARAM is effective in all of > +these cases. > + > +Upstream-Status: Pending > + > +Signed-off-by: Jianxun Zhang <[email protected]> > +--- > + src/boot/efi/boot.c | 34 ++++++++++++++++++++++++++++++++++ > + 1 file changed, 34 insertions(+) > + > +diff --git a/src/boot/efi/boot.c b/src/boot/efi/boot.c > +index 43b0793..3dcd9a5 100644 > +--- a/src/boot/efi/boot.c > ++++ b/src/boot/efi/boot.c > +@@ -847,6 +847,40 @@ static VOID config_add_entry(Config *config, > ConfigEntry *entry) { > + config->entries = ReallocatePool(config- > >entries, > + sizeof(VOI > D *) * config->entry_count, sizeof(VOID *) * i); > + } > ++ > ++ /* rmc: a linux entry could be added from .conf file or an > embedded linux image > ++ * we put appending global command line here to cover both > of two cases. > ++ */ > ++ if (entry->type == LOADER_LINUX && rmc_db && rmc_fp) { > ++ rmc_policy_file_t rmc_kp; > ++ > ++ if (!query_policy_from_db(rmc_fp, rmc_db, > RMC_POLICY_BLOB, "KBOOTPARAM", &rmc_kp)) { > ++ CHAR8 *cmdline; > ++ CHAR16 *s; > ++ CHAR16 *t; > ++ CHAR16 *p; > ++ > ++ cmdline = AllocatePool(rmc_kp.blob_len * > sizeof(CHAR8) + 1); > ++ CopyMem(cmdline, rmc_kp.blob, > rmc_kp.blob_len); > ++ cmdline[rmc_kp.blob_len] = '\0'; > ++ p = stra_to_str(cmdline); > ++ t = p; > ++ > ++ while (*t) { > ++ if (*t == '\n') > ++ *t = '\0'; > ++ t++; > ++ } > ++ > ++ s = PoolPrint(L"%s %s", entry->options, p); > ++ FreePool(entry->options); > ++ FreePool(p); > ++ FreePool(cmdline); > ++ > ++ entry->options = s; > ++ } > ++ } > ++ > + config->entries[config->entry_count++] = entry; > + } > + > +-- > +2.7.4 > + > -- > 2.7.4 > -- _______________________________________________ meta-intel mailing list [email protected] https://lists.yoctoproject.org/listinfo/meta-intel
