cmd: eficonfig: add support for setting fdt
We already support creating a load option where the device-path
field contains the concatenation of the binary device-path and
optionally the device path of the initrd which we expose via the
EFI_LOAD_FILE2_PROTOCOL.
Allow to append another device-path pointing to the device-tree
identified by the device-tree GUID.
Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
Reviewed-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
diff --git a/cmd/eficonfig.c b/cmd/eficonfig.c
index 7bb92e5..6108b42 100644
--- a/cmd/eficonfig.c
+++ b/cmd/eficonfig.c
@@ -61,6 +61,7 @@
struct eficonfig_boot_option {
struct eficonfig_select_file_info file_info;
struct eficonfig_select_file_info initrd_info;
+ struct eficonfig_select_file_info fdt_info;
unsigned int boot_index;
u16 *description;
u16 *optional_data;
@@ -1307,6 +1308,10 @@
if (ret != EFI_SUCCESS)
goto out;
+ ret = prepare_file_selection_entry(efi_menu, "Fdt File: ", &bo->fdt_info);
+ if (ret != EFI_SUCCESS)
+ goto out;
+
ret = create_boot_option_entry(efi_menu, "Optional Data: ", bo->optional_data,
eficonfig_boot_add_optional_data, bo);
if (ret != EFI_SUCCESS)
@@ -1387,30 +1392,47 @@
efi_status_t ret;
char *tmp = NULL, *p;
struct efi_load_option lo = {0};
- efi_uintn_t final_dp_size;
+ efi_uintn_t dp_size;
struct efi_device_path *dp = NULL;
efi_uintn_t size = load_option_size;
- struct efi_device_path *final_dp = NULL;
struct efi_device_path *device_dp = NULL;
struct efi_device_path *initrd_dp = NULL;
+ struct efi_device_path *fdt_dp = NULL;
struct efi_device_path *initrd_device_dp = NULL;
+ struct efi_device_path *fdt_device_dp = NULL;
- const struct efi_initrd_dp id_dp = {
+ const struct efi_initrd_dp initrd_prefix = {
.vendor = {
{
DEVICE_PATH_TYPE_MEDIA_DEVICE,
DEVICE_PATH_SUB_TYPE_VENDOR_PATH,
- sizeof(id_dp.vendor),
+ sizeof(initrd_prefix.vendor),
},
EFI_INITRD_MEDIA_GUID,
},
.end = {
DEVICE_PATH_TYPE_END,
DEVICE_PATH_SUB_TYPE_END,
- sizeof(id_dp.end),
+ sizeof(initrd_prefix.end),
}
};
+ const struct efi_initrd_dp fdt_prefix = {
+ .vendor = {
+ {
+ DEVICE_PATH_TYPE_MEDIA_DEVICE,
+ DEVICE_PATH_SUB_TYPE_VENDOR_PATH,
+ sizeof(fdt_prefix.vendor),
+ },
+ EFI_FDT_GUID,
+ },
+ .end = {
+ DEVICE_PATH_TYPE_END,
+ DEVICE_PATH_SUB_TYPE_END,
+ sizeof(initrd_prefix.end),
+ }
+ };
+
bo->file_info.current_path = calloc(1, EFICONFIG_FILE_PATH_BUF_SIZE);
if (!bo->file_info.current_path) {
ret = EFI_OUT_OF_RESOURCES;
@@ -1423,6 +1445,12 @@
goto out;
}
+ bo->fdt_info.current_path = calloc(1, EFICONFIG_FILE_PATH_BUF_SIZE);
+ if (!bo->fdt_info.current_path) {
+ ret = EFI_OUT_OF_RESOURCES;
+ goto out;
+ }
+
bo->description = calloc(1, EFICONFIG_DESCRIPTION_MAX * sizeof(u16));
if (!bo->description) {
ret = EFI_OUT_OF_RESOURCES;
@@ -1455,13 +1483,20 @@
if (lo.file_path)
fill_file_info(lo.file_path, &bo->file_info, device_dp);
- /* Initrd file path(optional) is placed at second instance. */
+ /* Initrd file path (optional) is placed at second instance. */
initrd_dp = efi_dp_from_lo(&lo, &efi_lf2_initrd_guid);
if (initrd_dp) {
fill_file_info(initrd_dp, &bo->initrd_info, initrd_device_dp);
efi_free_pool(initrd_dp);
}
+ /* Fdt file path (optional) is placed as third instance. */
+ fdt_dp = efi_dp_from_lo(&lo, &efi_guid_fdt);
+ if (fdt_dp) {
+ fill_file_info(fdt_dp, &bo->fdt_info, fdt_device_dp);
+ efi_free_pool(fdt_dp);
+ }
+
if (size > 0)
memcpy(bo->optional_data, lo.optional_data, size);
}
@@ -1483,26 +1518,31 @@
ret = EFI_OUT_OF_RESOURCES;
goto out;
}
- initrd_dp = efi_dp_concat((const struct efi_device_path *)&id_dp,
+ initrd_dp = efi_dp_concat((const struct efi_device_path *)&initrd_prefix,
dp, 0);
efi_free_pool(dp);
}
+ if (bo->fdt_info.dp_volume) {
+ dp = eficonfig_create_device_path(bo->fdt_info.dp_volume,
+ bo->fdt_info.current_path);
+ if (!dp) {
+ ret = EFI_OUT_OF_RESOURCES;
+ goto out;
+ }
+ fdt_dp = efi_dp_concat((const struct efi_device_path *)&fdt_prefix,
+ dp, 0);
+ efi_free_pool(dp);
+ }
+
dp = eficonfig_create_device_path(bo->file_info.dp_volume, bo->file_info.current_path);
if (!dp) {
ret = EFI_OUT_OF_RESOURCES;
goto out;
}
- final_dp_size = efi_dp_size(dp) + sizeof(END);
- if (initrd_dp) {
- final_dp = efi_dp_concat(dp, initrd_dp, 1);
- final_dp_size += efi_dp_size(initrd_dp) + sizeof(END);
- } else {
- final_dp = efi_dp_dup(dp);
- }
- efi_free_pool(dp);
- if (!final_dp)
+ ret = efi_load_option_dp_join(&dp, &dp_size, initrd_dp, fdt_dp);
+ if (ret != EFI_SUCCESS)
goto out;
if (utf16_utf8_strlen(bo->optional_data)) {
@@ -1514,17 +1554,20 @@
utf16_utf8_strncpy(&p, bo->optional_data, u16_strlen(bo->optional_data));
}
- ret = eficonfig_set_boot_option(varname, final_dp, final_dp_size, bo->description, tmp);
+ ret = eficonfig_set_boot_option(varname, dp, dp_size, bo->description, tmp);
out:
free(tmp);
free(bo->optional_data);
free(bo->description);
free(bo->file_info.current_path);
free(bo->initrd_info.current_path);
+ free(bo->fdt_info.current_path);
efi_free_pool(device_dp);
efi_free_pool(initrd_device_dp);
efi_free_pool(initrd_dp);
- efi_free_pool(final_dp);
+ efi_free_pool(fdt_device_dp);
+ efi_free_pool(fdt_dp);
+ efi_free_pool(dp);
return ret;
}
diff --git a/include/efi_loader.h b/include/efi_loader.h
index ddf2e41..1236eec 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -1185,4 +1185,18 @@
*/
void efi_add_known_memory(void);
+/**
+ * efi_load_option_dp_join() - join device-paths for load option
+ *
+ * @dp: in: binary device-path, out: joined device-path
+ * @dp_size: size of joined device-path
+ * @initrd_dp: initrd device-path or NULL
+ * @fdt_dp: device-tree device-path or NULL
+ * Return: status_code
+ */
+efi_status_t efi_load_option_dp_join(struct efi_device_path **dp,
+ size_t *dp_size,
+ struct efi_device_path *initrd_dp,
+ struct efi_device_path *fdt_dp);
+
#endif /* _EFI_LOADER_H */
diff --git a/lib/efi_loader/efi_helper.c b/lib/efi_loader/efi_helper.c
index 73d0279..348612c 100644
--- a/lib/efi_loader/efi_helper.c
+++ b/lib/efi_loader/efi_helper.c
@@ -99,6 +99,50 @@
return NULL;
}
+/**
+ * efi_load_option_dp_join() - join device-paths for load option
+ *
+ * @dp: in: binary device-path, out: joined device-path
+ * @dp_size: size of joined device-path
+ * @initrd_dp: initrd device-path or NULL
+ * @fdt_dp: device-tree device-path or NULL
+ * Return: status_code
+ */
+efi_status_t efi_load_option_dp_join(struct efi_device_path **dp,
+ size_t *dp_size,
+ struct efi_device_path *initrd_dp,
+ struct efi_device_path *fdt_dp)
+{
+ if (!dp)
+ return EFI_INVALID_PARAMETER;
+
+ *dp_size = efi_dp_size(*dp);
+
+ if (initrd_dp) {
+ struct efi_device_path *tmp_dp = *dp;
+
+ *dp = efi_dp_concat(tmp_dp, initrd_dp, *dp_size);
+ efi_free_pool(tmp_dp);
+ if (!*dp)
+ return EFI_OUT_OF_RESOURCES;
+ *dp_size += efi_dp_size(initrd_dp) + sizeof(END);
+ }
+
+ if (fdt_dp) {
+ struct efi_device_path *tmp_dp = *dp;
+
+ *dp = efi_dp_concat(tmp_dp, fdt_dp, *dp_size);
+ efi_free_pool(tmp_dp);
+ if (!dp)
+ return EFI_OUT_OF_RESOURCES;
+ *dp_size += efi_dp_size(fdt_dp) + sizeof(END);
+ }
+
+ *dp_size += sizeof(END);
+
+ return EFI_SUCCESS;
+}
+
const struct guid_to_hash_map {
efi_guid_t guid;
const char algo[32];