summaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
authorJianxun Zhang <jianxun.zhang@linux.intel.com>2016-08-03 18:04:14 (GMT)
committerTom Zanussi <tom.zanussi@linux.intel.com>2016-08-03 22:36:45 (GMT)
commit7d3305235702a7c730ea9af9db6b00156e664194 (patch)
treee2c758a0af21ba62e39f92e7517371dea264fc33 /common
parent8fe13a12c26022843a31e0909f34843f78bdacf6 (diff)
downloadmeta-intel-7d3305235702a7c730ea9af9db6b00156e664194.tar.gz
systemd-boot: Load board-specific entry and kernel cmdline
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 <jianxun.zhang@linux.intel.com> Reviewed-by: Saul Wold <sgw@linux.intel.com> Signed-off-by: Tom Zanussi <tom.zanussi@linux.intel.com>
Diffstat (limited to 'common')
-rw-r--r--common/recipes-bsp/systemd-boot/systemd-boot.bbappend20
-rw-r--r--common/recipes-bsp/systemd-boot/systemd-boot/0001-sd-boot-Link-RMC-libraries-into-bootloader.patch31
-rw-r--r--common/recipes-bsp/systemd-boot/systemd-boot/0002-sd-boot-Load-board-specific-boot-entries-from-RMC-da.patch263
-rw-r--r--common/recipes-bsp/systemd-boot/systemd-boot/0003-sd-boot-Support-global-kernel-command-line-fragment.patch66
4 files changed, 380 insertions, 0 deletions
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 @@
1DEPENDS += "rmc"
2
3FILESEXTRAPATHS_prepend := "${THISDIR}/systemd-boot:"
4
5EXTRA_OEMAKE += 'EFI_LDFLAGS="-L${STAGING_DIR_HOST}/usr/lib" EFI_CFLAGS="-I${STAGING_INCDIR}/rmc/efi -DRMC_EFI"'
6
7# Pin systemd revision down for systemd-boot recipe.
8# Patches could not be applied cleanly when systemd in OE is updated,
9# though we don't expect a lot of changes could happen in bootloader.
10# RMC is designed to support a large number of types of boards, so we
11# should do explicit update with validation to prevent regression even
12# resolving conflicts for a new tip could be done in a short time.
13
14# Revision: systemd 230 in OE
15SRCREV = "3a74d4fc90cb322a4784a3515bef7118c8f8c5ba"
16
17SRC_URI += "file://0001-sd-boot-Link-RMC-libraries-into-bootloader.patch \
18 file://0002-sd-boot-Load-board-specific-boot-entries-from-RMC-da.patch \
19 file://0003-sd-boot-Support-global-kernel-command-line-fragment.patch \
20 "
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 @@
1From b7775f24928fca01600cac1077ff3f215aa6362d Mon Sep 17 00:00:00 2001
2From: Jianxun Zhang <jianxun.zhang@linux.intel.com>
3Date: Sat, 21 May 2016 18:52:07 -0700
4Subject: [PATCH 1/3] sd-boot: Link RMC libraries into bootloader
5
6Add two RMC libraries into bootloader binary. EFI stub is not changed
7until we really need rmc in stub.
8
9Upstream-Status: Pending
10
11Signed-off-by: Jianxun Zhang <jianxun.zhang@linux.intel.com>
12---
13 Makefile.am | 2 +-
14 1 file changed, 1 insertion(+), 1 deletion(-)
15
16diff --git a/Makefile.am b/Makefile.am
17index 305099a..ff21ebd 100644
18--- a/Makefile.am
19+++ b/Makefile.am
20@@ -2802,7 +2802,7 @@ $(top_builddir)/src/boot/efi/%.o: $(top_srcdir)/src/boot/efi/%.c $(addprefix $(t
21
22 $(systemd_boot_solib): $(systemd_boot_objects)
23 $(AM_V_CCLD)$(LD) $(efi_ldflags) $(systemd_boot_objects) \
24- -o $@ -lefi -lgnuefi $(shell $(CC) -print-libgcc-file-name); \
25+ -o $@ -lefi -lgnuefi -lrmclefi -lrsmpefi $(shell $(CC) -print-libgcc-file-name); \
26 nm -D -u $@ | grep ' U ' && exit 1 || :
27
28 $(systemd_boot): $(systemd_boot_solib)
29--
302.7.4
31
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 @@
1From f714cdc84b791d84099f7461c4f223677456720f Mon Sep 17 00:00:00 2001
2From: Jianxun Zhang <jianxun.zhang@linux.intel.com>
3Date: Wed, 1 Jun 2016 16:32:22 -0700
4Subject: [PATCH 2/3] sd-boot: Load board-specific boot entries from RMC
5 database
6
7RMC provides a centralized database file on ESP. The DB contains
8fingerprints and any file blobs associated to physical boards.
9Callers can fetch board-specific data with fingerprint info
10collected from board at runtime if there is any record matched
11board's fingerprint.
12
13To let bootloader know which file blob in RMC should be queried,
14a special config file BOOTENTRY.CONFIG is defined as:
15
16boot.conf
17install.conf
18
19Bootloader calls RMC APIs and other functions to perform these
20tasks before it shows boot menu to user:
21
22(1) Load RMC database file from ESP
23(2) Collect fingerprint data from board
24(3) Query BOOTENTRY.CONFIG from RMC DB with fingerprint
25(4) Parse BOOTENTRY.CONFIG to know names of boot entry files
26(5) Query boot entry files one by one from RMC DB, and add
27 them into sd-boot config data.
28
29The final effect is that bootloader will show board-specific
30boot entries in boot menu to user. User then can choose one
31of them to boot system with the selected configuration.
32
33If any of these steps fails, bootloader simply skips loading
34RMC configs or any entry file not successfully fetched from
35RMC DB. Once any entry is loaded successfully from RMC DB,
36bootloader skips loading any boot entries from ESP.
37
38Upstream-Status: Pending
39
40Signed-off-by: Jianxun Zhang <jianxun.zhang@linux.intel.com>
41---
42 src/boot/efi/boot.c | 160 +++++++++++++++++++++++++++++++++++++++++++++++++++-
43 1 file changed, 158 insertions(+), 2 deletions(-)
44
45diff --git a/src/boot/efi/boot.c b/src/boot/efi/boot.c
46index 30c1ead..43b0793 100644
47--- a/src/boot/efi/boot.c
48+++ b/src/boot/efi/boot.c
49@@ -15,6 +15,8 @@
50
51 #include <efi.h>
52 #include <efilib.h>
53+#include <rmcl.h>
54+#include <rsmp.h>
55
56 #include "console.h"
57 #include "disk.h"
58@@ -33,6 +35,9 @@ static const char __attribute__((used)) magic[] = "#### LoaderInfo: systemd-boot
59
60 static const EFI_GUID global_guid = EFI_GLOBAL_VARIABLE;
61
62+static CHAR8* rmc_db;
63+static rmc_fingerprint_t *rmc_fp;
64+
65 enum loader_type {
66 LOADER_UNDEFINED,
67 LOADER_EFI,
68@@ -1702,6 +1707,148 @@ static VOID config_free(Config *config) {
69 FreePool(config->entry_oneshot);
70 }
71
72+/* Derived from line_get_key_value(), we could consolidate two functions later */
73+static CHAR8 *get_line(CHAR8 *content, UINT64 *pos) {
74+ CHAR8 *line;
75+ UINT64 linelen;
76+
77+skip:
78+ line = content + *pos;
79+ if (*line == '\0')
80+ return NULL;
81+
82+ linelen = 0;
83+ while (line[linelen] && !strchra((CHAR8 *)"\n\r", line[linelen]))
84+ linelen++;
85+
86+ /* move pos to next line */
87+ *pos += linelen;
88+ if (content[*pos])
89+ (*pos)++;
90+
91+ /* empty line */
92+ if (linelen == 0)
93+ goto skip;
94+
95+ /* terminate line */
96+ line[linelen] = '\0';
97+
98+ /* remove leading whitespace */
99+ while (strchra((CHAR8 *)" \t", *line)) {
100+ line++;
101+ linelen--;
102+ }
103+
104+ /* remove trailing whitespace */
105+ while (linelen > 0 && strchra((CHAR8 *)" \t", line[linelen-1]))
106+ linelen--;
107+ line[linelen] = '\0';
108+
109+ if (*line == '#')
110+ goto skip;
111+
112+ return line;
113+}
114+
115+/* load rmc database file from ESP and try to get fingerprint. These
116+ * are essential information indicating we could query rmc data for
117+ * this board at least
118+ * return 0 if both database file and fingerprint can be obtained, otherwise
119+ * non-zero value is returned.
120+ *
121+ * Note: db and fp hold valid values only when this function returns 0.
122+ * Caller is responsible to free allocated memory pointed by *db and *fp when
123+ * this function returns 0.
124+ */
125+
126+static UINTN rmc_initialize(EFI_FILE *root_dir, CHAR8 **db, rmc_fingerprint_t **fp) {
127+ UINTN len;
128+ EFI_GUID smbios_guid = SMBIOS_TABLE_GUID;
129+ EFI_GUID smbios3_guid = SMBIOS3_TABLE_GUID;
130+ VOID *smbios_entry = NULL;
131+ UINT64 smbios_struct_addr = 0;
132+ UINT16 smbios_struct_len = 0;
133+ UINTN ret = 1;
134+
135+ if (!db || !fp)
136+ return ret;
137+
138+ *db = NULL;
139+ *fp = NULL;
140+
141+ /* load rmc database */
142+ len = file_read(root_dir, L"\\rmc.db", 0, 0, db);
143+
144+ if (len <= 0)
145+ goto done;
146+
147+ /* locate smbios entry table, try both 32 and 64 bit */
148+ if (LibGetSystemConfigurationTable(&smbios3_guid, &smbios_entry) != EFI_SUCCESS
149+ && LibGetSystemConfigurationTable(&smbios_guid, &smbios_entry) != EFI_SUCCESS)
150+ goto done;
151+
152+ /* call rsmp to get fp */
153+ if (rsmp_get_smbios_strcut(smbios_entry, &smbios_struct_addr, &smbios_struct_len))
154+ goto done;
155+
156+ *fp = AllocateZeroPool(sizeof(rmc_fingerprint_t));
157+
158+ if (rsmp_get_fingerprint_from_smbios_struct((BYTE *) smbios_struct_addr, *fp))
159+ goto done;
160+
161+ ret = 0;
162+done:
163+ if (ret) {
164+ FreePool(*db);
165+ FreePool(*fp);
166+ }
167+
168+ return ret;
169+}
170+
171+/* load RMC entries
172+ * return TRUE when at least one entry is loaded, otherwise, return FALSE
173+ */
174+static BOOLEAN config_load_rmc_entries(Config *config, EFI_HANDLE *device, CHAR16 *loaded_image_path, CHAR8 *db, rmc_fingerprint_t *fp) {
175+ CHAR8 *boot_entry = NULL;
176+ CHAR8 *boot_config = NULL;
177+ rmc_policy_file_t rp;
178+ CHAR8 *line;
179+ UINT64 pos = 0;
180+ BOOLEAN ret = FALSE;
181+
182+ if (!db || !fp)
183+ return ret;
184+
185+ /* query boot entry config file */
186+ if (query_policy_from_db(fp, db, RMC_POLICY_BLOB, "BOOTENTRY.CONFIG", &rp))
187+ return ret;
188+
189+ /* file blob read from rmc db is not necessarily null-terminated, and we
190+ * should keep mem where rmc db lives from change during parsing
191+ */
192+ boot_config = AllocatePool(rp.blob_len * sizeof(CHAR8) + 1);
193+ CopyMem(boot_config, rp.blob, rp.blob_len);
194+ boot_config[rp.blob_len] = '\0';
195+ /* parse boot entry config */
196+ while ((line = get_line(boot_config, &pos))) {
197+ if (query_policy_from_db(fp, db, RMC_POLICY_BLOB, (char *)line, &rp))
198+ continue;
199+ if (rp.blob_len > 0) {
200+ boot_entry = AllocatePool(rp.blob_len * sizeof(CHAR8) + 1);
201+ CopyMem(boot_entry, rp.blob, rp.blob_len);
202+ boot_entry[rp.blob_len] = '\0';
203+ config_entry_add_from_file(config, device,
204+ stra_to_str(line), boot_entry,
205+ loaded_image_path);
206+ /* tell caller success when a RMC entry is loaded */
207+ ret = TRUE;
208+ }
209+ }
210+
211+ return ret;
212+}
213+
214 EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
215 CHAR16 *s;
216 CHAR8 *b;
217@@ -1714,6 +1861,7 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
218 UINT64 init_usec;
219 BOOLEAN menu = FALSE;
220 CHAR16 uuid[37];
221+ BOOLEAN rmc_entry = FALSE;
222
223 InitializeLib(image, sys_table);
224 init_usec = time_usec();
225@@ -1745,6 +1893,8 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
226 return EFI_LOAD_ERROR;
227 }
228
229+ /* Initialize rmc before loading any config */
230+ rmc_initialize(root_dir, &rmc_db, &rmc_fp);
231
232 /* the filesystem path to this image, to prevent adding ourselves to the menu */
233 loaded_image_path = DevicePathToStr(loaded_image->FilePath);
234@@ -1753,11 +1903,15 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
235 ZeroMem(&config, sizeof(Config));
236 config_load_defaults(&config, root_dir);
237
238+ if (rmc_db && rmc_fp)
239+ rmc_entry = config_load_rmc_entries(&config, loaded_image->DeviceHandle, loaded_image_path, rmc_db, rmc_fp);
240+
241 /* scan /EFI/Linux/ directory */
242 config_entry_add_linux(&config, loaded_image, root_dir);
243
244- /* scan /loader/entries/\*.conf files */
245- config_load_entries(&config, loaded_image->DeviceHandle, root_dir, loaded_image_path);
246+ /* scan /loader/entries/\*.conf files only when no RMC entry is loaded */
247+ if (rmc_entry == FALSE)
248+ config_load_entries(&config, loaded_image->DeviceHandle, root_dir, loaded_image_path);
249
250 /* sort entries after version number */
251 config_sort_entries(&config);
252@@ -1851,6 +2005,8 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
253 out:
254 FreePool(loaded_image_path);
255 config_free(&config);
256+ FreePool(rmc_db);
257+ FreePool(rmc_fp);
258 uefi_call_wrapper(root_dir->Close, 1, root_dir);
259 uefi_call_wrapper(BS->CloseProtocol, 4, image, &LoadedImageProtocol, image, NULL);
260 return err;
261--
2622.7.4
263
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 @@
1From a38be4fe8ffed142abbba92f7ad91a8f7b8f1ace Mon Sep 17 00:00:00 2001
2From: Jianxun Zhang <jianxun.zhang@linux.intel.com>
3Date: Mon, 20 Jun 2016 13:08:20 -0700
4Subject: [PATCH 3/3] sd-boot: Support global kernel command line fragment
5
6Query file blob KBOOTPARAM from RMC. If it exists, we append
7it to the new linux boot entry's cmdline. A boot entry could
8be read from a .conf file on ESP, RMC database, or embedded
9linux image. content in KBOOTPARAM is effective in all of
10these cases.
11
12Upstream-Status: Pending
13
14Signed-off-by: Jianxun Zhang <jianxun.zhang@linux.intel.com>
15---
16 src/boot/efi/boot.c | 34 ++++++++++++++++++++++++++++++++++
17 1 file changed, 34 insertions(+)
18
19diff --git a/src/boot/efi/boot.c b/src/boot/efi/boot.c
20index 43b0793..3dcd9a5 100644
21--- a/src/boot/efi/boot.c
22+++ b/src/boot/efi/boot.c
23@@ -847,6 +847,40 @@ static VOID config_add_entry(Config *config, ConfigEntry *entry) {
24 config->entries = ReallocatePool(config->entries,
25 sizeof(VOID *) * config->entry_count, sizeof(VOID *) * i);
26 }
27+
28+ /* rmc: a linux entry could be added from .conf file or an embedded linux image
29+ * we put appending global command line here to cover both of two cases.
30+ */
31+ if (entry->type == LOADER_LINUX && rmc_db && rmc_fp) {
32+ rmc_policy_file_t rmc_kp;
33+
34+ if (!query_policy_from_db(rmc_fp, rmc_db, RMC_POLICY_BLOB, "KBOOTPARAM", &rmc_kp)) {
35+ CHAR8 *cmdline;
36+ CHAR16 *s;
37+ CHAR16 *t;
38+ CHAR16 *p;
39+
40+ cmdline = AllocatePool(rmc_kp.blob_len * sizeof(CHAR8) + 1);
41+ CopyMem(cmdline, rmc_kp.blob, rmc_kp.blob_len);
42+ cmdline[rmc_kp.blob_len] = '\0';
43+ p = stra_to_str(cmdline);
44+ t = p;
45+
46+ while (*t) {
47+ if (*t == '\n')
48+ *t = '\0';
49+ t++;
50+ }
51+
52+ s = PoolPrint(L"%s %s", entry->options, p);
53+ FreePool(entry->options);
54+ FreePool(p);
55+ FreePool(cmdline);
56+
57+ entry->options = s;
58+ }
59+ }
60+
61 config->entries[config->entry_count++] = entry;
62 }
63
64--
652.7.4
66