summaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2021-07-18 07:13:02 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2021-07-18 07:13:02 +0200
commit8a5144d02a0146c4f0ec577232c0a102d12c8ee7 (patch)
tree85b0459bb60bfaa2a765e21bb7e19a0edc6c2d6a /common
parent2551aad17a15fe06ae3b76b12b5df2207c1e11f6 (diff)
parent368deb2baa56a6ab0f4ec7d7a42559c4db14b063 (diff)
downloadbarebox-8a5144d02a0146c4f0ec577232c0a102d12c8ee7.tar.gz
barebox-8a5144d02a0146c4f0ec577232c0a102d12c8ee7.tar.xz
Merge branch 'for-next/firmware'
Diffstat (limited to 'common')
-rw-r--r--common/blspec.c99
-rw-r--r--common/bootm.c4
-rw-r--r--common/efi/efi.c2
-rw-r--r--common/firmware.c109
-rw-r--r--common/image-fit.c2
-rw-r--r--common/oftree.c4
-rw-r--r--common/state/backend_format_dtb.c2
7 files changed, 146 insertions, 76 deletions
diff --git a/common/blspec.c b/common/blspec.c
index ad80d7a8cd..6cb1fea9e8 100644
--- a/common/blspec.c
+++ b/common/blspec.c
@@ -32,79 +32,33 @@ int blspec_entry_var_set(struct blspec_entry *entry, const char *name,
val ? strlen(val) + 1 : 0, 1);
}
-static int blspec_apply_oftree_overlay(char *file, const char *abspath,
- int dryrun)
-{
- int ret = 0;
- struct fdt_header *fdt;
- struct device_node *overlay;
- char *path;
- char *firmware_path;
-
- path = basprintf("%s/%s", abspath, file);
-
- fdt = read_file(path, NULL);
- if (!fdt) {
- pr_warn("unable to read \"%s\"\n", path);
- ret = -EINVAL;
- goto out;
- }
-
- overlay = of_unflatten_dtb(fdt);
- free(fdt);
- if (IS_ERR(overlay)) {
- ret = PTR_ERR(overlay);
- goto out;
- }
-
- if (dryrun) {
- pr_info("dry run: skip overlay %s\n", path);
- of_delete_node(overlay);
- goto out;
- }
-
- /*
- * Unfortunately the device tree overlay contains only the filename of
- * the firmware and relies on the firmware search paths to find the
- * actual file. Use /lib/firmware in the Linux root directory and hope
- * for the best.
- */
- firmware_path = basprintf("%s/%s", abspath, "/lib/firmware");
- ret = of_firmware_load_overlay(overlay, firmware_path);
- free(firmware_path);
- if (ret) {
- pr_warn("failed to load firmware: skip overlay \"%s\"\n", path);
- of_delete_node(overlay);
- goto out;
- }
-
- ret = of_register_overlay(overlay);
- if (ret) {
- pr_warn("cannot register devicetree overlay \"%s\"\n", path);
- of_delete_node(overlay);
- }
-
-out:
- free(path);
-
- return ret;
-}
-
-static void blspec_apply_oftree_overlays(const char *overlays,
- const char *abspath, int dryrun)
+static int blspec_overlay_fixup(struct device_node *root, void *ctx)
{
+ struct blspec_entry *entry = ctx;
+ const char *overlays;
char *overlay;
char *sep, *freep;
+ overlays = blspec_entry_var_get(entry, "devicetree-overlay");
+
sep = freep = xstrdup(overlays);
while ((overlay = strsep(&sep, " "))) {
+ char *path;
+
if (!*overlay)
continue;
- blspec_apply_oftree_overlay(overlay, abspath, dryrun);
+
+ path = basprintf("%s/%s", entry->rootpath, overlay);
+
+ of_overlay_apply_file(root, path, false);
+
+ free(path);
}
free(freep);
+
+ return 0;
}
/*
@@ -121,6 +75,8 @@ static int blspec_boot(struct bootentry *be, int verbose, int dryrun)
const char *abspath, *devicetree, *options, *initrd, *linuximage;
const char *overlays;
const char *appendroot;
+ const char *old_fws;
+ char *fws;
struct bootm_data data = {
.dryrun = dryrun,
};
@@ -159,7 +115,7 @@ static int blspec_boot(struct bootentry *be, int verbose, int dryrun)
}
if (overlays)
- blspec_apply_oftree_overlays(overlays, abspath, dryrun);
+ of_register_fixup(blspec_overlay_fixup, entry);
if (initrd)
data.initrd_file = basprintf("%s/%s", abspath, initrd);
@@ -183,9 +139,26 @@ static int blspec_boot(struct bootentry *be, int verbose, int dryrun)
(entry->cdev && entry->cdev->dev) ?
dev_name(entry->cdev->dev) : "none");
+ of_overlay_set_basedir(abspath);
+
+ old_fws = firmware_get_searchpath();
+ if (old_fws && *old_fws)
+ fws = basprintf("%s/lib/firmware:%s", abspath, old_fws);
+ else
+ fws = basprintf("%s/lib/firmware", abspath);
+ firmware_set_searchpath(fws);
+ free(fws);
+
ret = bootm_boot(&data);
if (ret)
pr_err("Booting failed\n");
+
+ if (overlays)
+ of_unregister_fixup(blspec_overlay_fixup, entry);
+
+ of_overlay_set_basedir("/");
+ firmware_set_searchpath(old_fws);
+
err_out:
free((char *)data.oftree_file);
free((char *)data.initrd_file);
@@ -490,7 +463,7 @@ static bool entry_is_of_compatible(struct blspec_entry *entry)
goto out;
}
- root = of_unflatten_dtb(fdt);
+ root = of_unflatten_dtb(fdt, size);
if (IS_ERR(root)) {
ret = false;
root = NULL;
diff --git a/common/bootm.c b/common/bootm.c
index 644443a021..89e3e93f2c 100644
--- a/common/bootm.c
+++ b/common/bootm.c
@@ -361,7 +361,7 @@ void *bootm_get_devicetree(struct image_data *data)
if (ret)
return ERR_PTR(ret);
- data->of_root_node = of_unflatten_dtb(of_tree);
+ data->of_root_node = of_unflatten_dtb(of_tree, of_size);
} else if (data->oftree_file) {
size_t size;
@@ -389,7 +389,7 @@ void *bootm_get_devicetree(struct image_data *data)
if (ret)
return ERR_PTR(ret);
- data->of_root_node = of_unflatten_dtb(oftree);
+ data->of_root_node = of_unflatten_dtb(oftree, size);
free(oftree);
diff --git a/common/efi/efi.c b/common/efi/efi.c
index 01003dc00f..7f12342cf9 100644
--- a/common/efi/efi.c
+++ b/common/efi/efi.c
@@ -437,7 +437,7 @@ static int efi_late_init(void)
return -EINVAL;
}
- root = of_unflatten_dtb(fdt);
+ root = of_unflatten_dtb(fdt, size);
free(fdt);
diff --git a/common/firmware.c b/common/firmware.c
index 58509d5da6..b33acff77f 100644
--- a/common/firmware.c
+++ b/common/firmware.c
@@ -11,9 +11,13 @@
#include <libbb.h>
#include <libfile.h>
#include <fs.h>
+#include <globalvar.h>
+#include <magicvar.h>
#include <linux/list.h>
#include <linux/stat.h>
#include <linux/err.h>
+#include <uncompress.h>
+#include <filetype.h>
#define BUFSIZ 4096
@@ -61,13 +65,25 @@ struct firmware_mgr *firmwaremgr_find(const char *id)
* handler. This allows to retrieve the firmware handler with a phandle from
* the device tree.
*/
-struct firmware_mgr *firmwaremgr_find_by_node(const struct device_node *np)
+struct firmware_mgr *firmwaremgr_find_by_node(struct device_node *np)
{
struct firmware_mgr *mgr;
+ char *na, *nb;
- list_for_each_entry(mgr, &firmwaremgr_list, list)
- if (mgr->handler->dev->parent->device_node == np)
+ na = of_get_reproducible_name(np);
+
+ list_for_each_entry(mgr, &firmwaremgr_list, list) {
+ nb = of_get_reproducible_name(mgr->handler->device_node);
+ if (!strcmp(na, nb)) {
+ free(na);
+ free(nb);
return mgr;
+ }
+
+ free(nb);
+ }
+
+ free(na);
return NULL;
}
@@ -206,17 +222,96 @@ out:
return ret;
}
+static char *firmware_path;
+
+const char *firmware_get_searchpath(void)
+{
+ return firmware_path;
+}
+
+void firmware_set_searchpath(const char *path)
+{
+ free(firmware_path);
+ firmware_path = strdup(path);
+}
+
+static bool file_exists(const char *filename)
+{
+ struct stat s;
+
+ return !stat(filename, &s);
+}
+
/*
* firmware_load_file - load a firmware to a device
*/
int firmwaremgr_load_file(struct firmware_mgr *mgr, const char *firmware)
{
- int ret;
- char *name = basprintf("/dev/%s", mgr->handler->id);
+ char *dst;
+ enum filetype type;
+ int ret = 0;
+ char *fw = NULL;
+ int firmwarefd = 0;
+ int devicefd = 0;
+
+ if (!firmware)
+ return -EINVAL;
+
+ if (!mgr->handler->id) {
+ pr_err("id not defined for handler\n");
+ return -ENODEV;
+ }
+
+ dst = basprintf("/dev/%s", mgr->handler->id);
+
+ if (*firmware != '/') {
+ fw = find_path(firmware_path, firmware, file_exists);
+ if (fw)
+ firmware = fw;
+ }
+
+ firmwarefd = open(firmware, O_RDONLY);
+ if (firmwarefd < 0) {
+ printf("could not open %s: %s\n", firmware,
+ errno_str());
+ ret = firmwarefd;
+ goto out;
+ }
+
+ type = file_name_detect_type(firmware);
- ret = copy_file(firmware, name, 0);
+ devicefd = open(dst, O_WRONLY);
+ if (devicefd < 0) {
+ printf("could not open %s: %s\n", dst, errno_str());
+ ret = devicefd;
+ goto out;
+ }
- free(name);
+ if (file_is_compressed_file(type))
+ ret = uncompress_fd_to_fd(firmwarefd, devicefd,
+ uncompress_err_stdout);
+ else
+ ret = copy_fd(firmwarefd, devicefd);
+
+out:
+ free(dst);
+ free(fw);
+
+ if (firmwarefd > 0)
+ close(firmwarefd);
+ if (devicefd > 0)
+ close(devicefd);
return ret;
}
+
+static int firmware_init(void)
+{
+ firmware_path = strdup("/env/firmware");
+ globalvar_add_simple_string("firmware.path", &firmware_path);
+
+ return 0;
+}
+device_initcall(firmware_init);
+
+BAREBOX_MAGICVAR(global.firmware.path, "Firmware search path");
diff --git a/common/image-fit.c b/common/image-fit.c
index 2c5ef7f687..c1a34a4405 100644
--- a/common/image-fit.c
+++ b/common/image-fit.c
@@ -754,7 +754,7 @@ static int fit_do_open(struct fit_handle *handle)
const char *desc = "(no description)";
struct device_node *root;
- root = of_unflatten_dtb_const(handle->fit);
+ root = of_unflatten_dtb_const(handle->fit, handle->size);
if (IS_ERR(root))
return PTR_ERR(root);
diff --git a/common/oftree.c b/common/oftree.c
index 5eaa63ad7e..7028c49aca 100644
--- a/common/oftree.c
+++ b/common/oftree.c
@@ -326,6 +326,8 @@ int of_fix_tree(struct device_node *node)
struct of_fixup *of_fixup;
int ret;
+ of_overlay_load_firmware_clear();
+
list_for_each_entry(of_fixup, &of_fixup_list, list) {
ret = of_fixup->fixup(node, of_fixup->context);
if (ret)
@@ -353,7 +355,7 @@ struct fdt_header *of_get_fixed_tree(struct device_node *node)
if (!node)
return NULL;
- freenp = node = of_copy_node(NULL, node);
+ freenp = node = of_dup(node);
if (!node)
return NULL;
}
diff --git a/common/state/backend_format_dtb.c b/common/state/backend_format_dtb.c
index 48f30db1f5..d0fc948859 100644
--- a/common/state/backend_format_dtb.c
+++ b/common/state/backend_format_dtb.c
@@ -59,7 +59,7 @@ static int state_backend_format_dtb_verify(struct state_backend_format *format,
fdtb->root = NULL;
}
- root = of_unflatten_dtb(buf);
+ root = of_unflatten_dtb(buf, dtb_len);
if (IS_ERR(root)) {
dev_err(fdtb->dev, "Failed to unflatten dtb from buffer with length %zd, %ld\n",
len, PTR_ERR(root));