From 0c2c24508d810a59709d598474b20eff4b81c4f9 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Tue, 17 Nov 2020 13:21:15 +0100 Subject: usb: fastboot: Fix error path fastboot_bind() can fail in multiple ways. Roll back things already done in the error path. Signed-off-by: Sascha Hauer --- drivers/usb/gadget/f_fastboot.c | 48 ++++++++++++++++++++++++++++++----------- 1 file changed, 35 insertions(+), 13 deletions(-) diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c index da3e0c7a8f..96924c4cb9 100644 --- a/drivers/usb/gadget/f_fastboot.c +++ b/drivers/usb/gadget/f_fastboot.c @@ -207,34 +207,43 @@ static int fastboot_bind(struct usb_configuration *c, struct usb_function *f) ret = fastboot_generic_init(&f_fb->fastboot, opts->common.export_bbu); if (ret) - return ret; + goto err_wq_unregister; /* DYNAMIC interface numbers assignments */ id = usb_interface_id(c, f); - if (id < 0) - return id; + if (id < 0) { + ret = id; + goto fb_generic_free; + } + interface_desc.bInterfaceNumber = id; id = usb_string_id(c->cdev); - if (id < 0) - return id; + if (id < 0) { + ret = id; + goto fb_generic_free; + } fastboot_string_defs[0].id = id; interface_desc.iInterface = id; us = usb_gstrings_attach(cdev, fastboot_strings, 1); if (IS_ERR(us)) { ret = PTR_ERR(us); - return ret; + goto fb_generic_free; } f_fb->in_ep = usb_ep_autoconfig(gadget, &fs_ep_in); - if (!f_fb->in_ep) - return -ENODEV; + if (!f_fb->in_ep) { + ret = -ENODEV; + goto fb_generic_free; + } f_fb->in_ep->driver_data = c->cdev; f_fb->out_ep = usb_ep_autoconfig(gadget, &fs_ep_out); - if (!f_fb->out_ep) - return -ENODEV; + if (!f_fb->out_ep) { + ret = -ENODEV; + goto fb_generic_free; + } f_fb->out_ep->driver_data = c->cdev; hs_ep_out.bEndpointAddress = fs_ep_out.bEndpointAddress; @@ -244,7 +253,7 @@ static int fastboot_bind(struct usb_configuration *c, struct usb_function *f) if (!f_fb->out_req) { puts("failed to alloc out req\n"); ret = -EINVAL; - return ret; + goto fb_generic_free; } f_fb->out_req->complete = rx_handler_command; @@ -254,15 +263,28 @@ static int fastboot_bind(struct usb_configuration *c, struct usb_function *f) if (!f_fb->in_req) { puts("failed alloc req in\n"); ret = -EINVAL; - return ret; + goto err_free_out_req; } f_fb->in_req->complete = fastboot_complete; ret = usb_assign_descriptors(f, fb_fs_descs, fb_hs_descs, NULL); if (ret) - return ret; + goto err_free_in_req; return 0; + +err_free_in_req: + free(f_fb->in_req->buf); + usb_ep_free_request(f_fb->in_ep, f_fb->in_req); +err_free_out_req: + free(f_fb->out_req->buf); + usb_ep_free_request(f_fb->out_ep, f_fb->out_req); +fb_generic_free: + fastboot_generic_free(&f_fb->fastboot); +err_wq_unregister: + wq_unregister(&f_fb->wq); + + return ret; } static void fastboot_unbind(struct usb_configuration *c, struct usb_function *f) -- cgit v1.2.3 From 51178d4979c9caeef95d616dcd3d47bdcd81a58e Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Thu, 12 Nov 2020 18:23:46 +0100 Subject: fs: introduce unsetenv() to prepare for changing setenv(var, "") behavior Currently, we treat setenv(var, "") and setenv(var, NULL) the same and delete var, which is surprising and leads to subtle quirks: - setenv(var, "") is specified by POSIX to set var to an empty string, but barebox uses it to delete variables - nv.user= calls nv_set with NULL parameter, but nv user="" doesn't Make the API more POSIX-like by providing unsetenv with the expected semantics. Most user code can then use unsetenv without worrying about whether "" or NULL is the magic deletion value. Signed-off-by: Ahmad Fatoum Signed-off-by: Sascha Hauer --- commands/readlink.c | 2 +- commands/setenv.c | 7 ++++++- fs/fs.c | 2 +- include/environment.h | 5 +++++ net/ifup.c | 2 +- 5 files changed, 14 insertions(+), 4 deletions(-) diff --git a/commands/readlink.c b/commands/readlink.c index fdcf175f56..81ad25c733 100644 --- a/commands/readlink.c +++ b/commands/readlink.c @@ -50,7 +50,7 @@ static int do_readlink(int argc, char *argv[]) return 0; err: - setenv(argv[optind + 1], ""); + unsetenv(argv[optind + 1]); return 1; } diff --git a/commands/setenv.c b/commands/setenv.c index ad26770655..6992f604f5 100644 --- a/commands/setenv.c +++ b/commands/setenv.c @@ -10,6 +10,7 @@ static int do_setenv(int argc, char *argv[]) { char *equal; + int ret; if (argc < 2) return COMMAND_ERROR_USAGE; @@ -21,8 +22,12 @@ static int do_setenv(int argc, char *argv[]) argv[2] = &equal[1]; } + if (argv[2]) + ret = setenv(argv[1], argv[2]); + else + ret = unsetenv(argv[1]); - return setenv(argv[1], argv[2]) ? COMMAND_ERROR : COMMAND_SUCCESS; + return ret ? COMMAND_ERROR : COMMAND_SUCCESS; } BAREBOX_CMD_HELP_START(setenv) diff --git a/fs/fs.c b/fs/fs.c index f41e4b9b72..00b8645fb0 100644 --- a/fs/fs.c +++ b/fs/fs.c @@ -3066,7 +3066,7 @@ static int automount_mount(struct dentry *dentry) setenv("automount_path", am->path); export("automount_path"); ret = run_command(am->cmd); - setenv("automount_path", NULL); + unsetenv("automount_path"); if (ret) { printf("running automount command '%s' failed\n", diff --git a/include/environment.h b/include/environment.h index 9488e4e1ac..19e522cfb6 100644 --- a/include/environment.h +++ b/include/environment.h @@ -87,6 +87,11 @@ int env_push_context(void); int export(const char *); +static inline int unsetenv(const char *var) +{ + return setenv(var, NULL); +} + #endif /* _ENVIRONMENT_H_ */ /** diff --git a/net/ifup.c b/net/ifup.c index a74037939b..1870f74017 100644 --- a/net/ifup.c +++ b/net/ifup.c @@ -86,7 +86,7 @@ static int source_env_network(struct eth_device *edev) env_push_context(); for (i = 0; i < ARRAY_SIZE(vars); i++) - setenv(vars[i], ""); + unsetenv(vars[i]); cmd = basprintf("source /env/network/%s", edev->devname); ret = run_command(cmd); -- cgit v1.2.3 From 656a6f0e97770bb8a2a1a76734a87abbbeff7d56 Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Thu, 12 Nov 2020 18:23:47 +0100 Subject: setenv: align with POSIX in handling of setenv(var, "") setenv(var, "") to delete var is a barebox idiosyncrasy. Previous commit added unsetenv and changed all users of setenv(var, ""), so lets set the behavior of setenv to what's expected: set var to the empty string. Previously, "" was turned into NULL, which meant it wasn't possible to set variables to the empty string from the shell. This is now possible. Signed-off-by: Ahmad Fatoum Signed-off-by: Sascha Hauer --- commands/setenv.c | 3 +-- common/env.c | 12 +++++++++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/commands/setenv.c b/commands/setenv.c index 6992f604f5..9aeb8f010b 100644 --- a/commands/setenv.c +++ b/commands/setenv.c @@ -18,8 +18,7 @@ static int do_setenv(int argc, char *argv[]) equal = strrchr(argv[1], '='); if (equal) { equal[0] = '\0'; - if (equal[1]) - argv[2] = &equal[1]; + argv[2] = &equal[1]; } if (argv[2]) diff --git a/common/env.c b/common/env.c index fbaaac4f2f..2830551bc0 100644 --- a/common/env.c +++ b/common/env.c @@ -251,15 +251,21 @@ static int dev_setenv(const char *name, const char *val) return -ENODEV; } +/** + * setenv - set environment variables + * @_name - Variable name + * @value - the value to set, empty string not handled specially + * + * Returns 0 for success and a negative error code otherwise + * Use unsetenv() to unset. + */ + int setenv(const char *_name, const char *value) { char *name = strdup(_name); int ret = 0; struct list_head *list; - if (value && !*value) - value = NULL; - if (strchr(name, '.')) { ret = dev_setenv(name, value); if (ret) -- cgit v1.2.3 From 3a1e315c56bf2b742176e7a2ed8aa48c94c8dab0 Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Wed, 18 Nov 2020 12:14:45 +0100 Subject: fb: sync enable device parameter with internal state So far fb.enable only reflected whether the fb was enabled/disabled via device parameter. Enabling/disabling the fb via ioctl left the parameter untouched. Remedy this. While at it, have setting of fb.enable if the underlying fb_enable/fb_disable fails as well. Signed-off-by: Ahmad Fatoum Signed-off-by: Sascha Hauer --- drivers/video/fb.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/drivers/video/fb.c b/drivers/video/fb.c index 2d82bc01fa..113c1419a1 100644 --- a/drivers/video/fb.c +++ b/drivers/video/fb.c @@ -119,22 +119,25 @@ int fb_disable(struct fb_info *info) return 0; } +static int fb_enable_get(struct param_d *param, void *priv) +{ + struct fb_info *info = priv; + + info->p_enable = info->enabled; + return 0; +} + static int fb_enable_set(struct param_d *param, void *priv) { struct fb_info *info = priv; - int enable; if (!info->mode) return -EINVAL; - enable = info->p_enable; - - if (enable) - fb_enable(info); + if (info->p_enable) + return fb_enable(info); else - fb_disable(info); - - return 0; + return fb_disable(info); } static struct fb_videomode *fb_num_to_mode(struct fb_info *info, int num) @@ -314,7 +317,7 @@ int register_framebuffer(struct fb_info *info) if (ret) goto err_free; - dev_add_param_bool(dev, "enable", fb_enable_set, NULL, + dev_add_param_bool(dev, "enable", fb_enable_set, fb_enable_get, &info->p_enable, info); if (IS_ENABLED(CONFIG_DRIVER_VIDEO_EDID)) -- cgit v1.2.3 From e1ddb7e8580df72f0ac6350511eaf899c10e35e1 Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Wed, 18 Nov 2020 19:22:16 +0100 Subject: bootm: adapt help text and naming for bootm.provide_machine_id The Kconfig help text as well the function name machine_id_set_bootarg() suggest that enabling the Kconfig option is sufficient to have barebox pass the machine id to the kernel. This is not the case, so change the naming/documentation to make this clearer. Signed-off-by: Ahmad Fatoum Reviewed-by: Bastian Krause Signed-off-by: Sascha Hauer --- common/Kconfig | 19 ++++++++++--------- common/bootm.c | 2 +- common/machine_id.c | 4 ++-- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/common/Kconfig b/common/Kconfig index 9b73aa8454..ffdce2f96c 100644 --- a/common/Kconfig +++ b/common/Kconfig @@ -989,19 +989,20 @@ config RESET_SOURCE useful for any kind of system recovery or repair. config MACHINE_ID - bool "pass machine-id to kernel" + bool "compute unique machine-id" depends on FLEXIBLE_BOOTARGS depends on SHA1 help - Sets the linux.bootargs.machine_id global variable with a value of - systemd.machine_id=UID. The UID is a persistent device-specific - id. It is a hash over device-specific information provided by various - sources. + Compute a persistent machine-specific id and store it to $global.machine_id. + The id is a hash of device-specific information added via + machine_id_set_hashable(). If multiple sources are available, the + information provided by the last call prior to the late initcall + set_machine_id() is used to generate the machine id from. Thus when + updating barebox the machine id might change. - Note: if multiple sources provide hashable device-specific information - (via machine_id_set_hashable()) the information provided by the last call - prior to the late initcall set_machine_id() is used to generate the - machine id from. Thus when updating barebox the machine id might change. + global.bootm.provide_machine_id may be used to automatically set + the linux.bootargs.machine_id global variable with a value of + systemd.machine_id=${global.machine_id} Note: if no hashable information is available no machine id will be passed to the kernel. diff --git a/common/bootm.c b/common/bootm.c index f70ef10100..59efc61099 100644 --- a/common/bootm.c +++ b/common/bootm.c @@ -856,4 +856,4 @@ BAREBOX_MAGICVAR(global.bootm.verify, "bootm default verify level"); BAREBOX_MAGICVAR(global.bootm.verbose, "bootm default verbosity level (0=quiet)"); BAREBOX_MAGICVAR(global.bootm.appendroot, "Add root= option to Kernel to mount rootfs from the device the Kernel comes from (default, device can be overridden via global.bootm.root_dev)"); BAREBOX_MAGICVAR(global.bootm.root_dev, "bootm default root device (overrides default device in global.bootm.appendroot)"); -BAREBOX_MAGICVAR(global.bootm.provide_machine_id, "If true, add systemd.machine_id= with value of global.machine_id to Kernel"); +BAREBOX_MAGICVAR(global.bootm.provide_machine_id, "If true, append systemd.machine_id=$global.machine_id to Kernel command line"); diff --git a/common/machine_id.c b/common/machine_id.c index c1309ccafd..6480806cd2 100644 --- a/common/machine_id.c +++ b/common/machine_id.c @@ -24,7 +24,7 @@ void machine_id_set_hashable(const void *hashable, size_t len) __machine_id_hashable_length = len; } -static int machine_id_set_bootarg(void) +static int machine_id_set_globalvar(void) { struct digest *digest = NULL; unsigned char machine_id[SHA1_DIGEST_SIZE]; @@ -64,6 +64,6 @@ out: return ret; } -late_initcall(machine_id_set_bootarg); +late_initcall(machine_id_set_globalvar); BAREBOX_MAGICVAR(global.machine_id, "Persistent device-specific, hexadecimal, 32-character id"); -- cgit v1.2.3 From 1d6ac29259c2cd77fc2d57c1a243277a41b585a4 Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Mon, 23 Nov 2020 15:12:39 +0100 Subject: boot: drop uneeded header #includes Boot entry providers register themselves, so there is no need for the common boot code to know about bootchooser or blspec or include their headers. Remove them as well as other headers that aren't strictly necessary and, if needed, include headers they include directly. Signed-off-by: Ahmad Fatoum Signed-off-by: Sascha Hauer --- common/boot.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/common/boot.c b/common/boot.c index 90d504e3c3..586507e1ec 100644 --- a/common/boot.c +++ b/common/boot.c @@ -9,22 +9,19 @@ * General Public License for more details. */ -#include -#include +#include #include #include #include #include #include #include -#include #include -#include #include #include #include #include -#include +#include #include -- cgit v1.2.3 From 1344966f25a03f0a0a092bbad50e1cce3a3cd310 Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Mon, 23 Nov 2020 17:14:30 +0100 Subject: commands: boot: fix error code/clean up behavior when not booting The boot command won't boot if: - There are no boot entries: we should still clean up before returning an error - A menu or list of found entries should be displayed: we should exit with success - We were doing a dry run: we should propagate the boot entry boot method's exit code Do the necessary. Signed-off-by: Ahmad Fatoum Signed-off-by: Sascha Hauer --- commands/boot.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/commands/boot.c b/commands/boot.c index d7795bde72..18f4e36ec7 100644 --- a/commands/boot.c +++ b/commands/boot.c @@ -97,19 +97,16 @@ static int do_boot(int argc, char *argv[]) if (list_empty(&entries->entries)) { printf("Nothing bootable found\n"); - return COMMAND_ERROR; - } - - if (do_list) { - bootsources_list(entries); + ret = COMMAND_ERROR; goto out; } - if (do_menu) { + if (do_list) + bootsources_list(entries); + else if (do_menu) bootsources_menu(entries, timeout); - goto out; - } + ret = 0; out: bootentries_free(entries); free(freep); -- cgit v1.2.3 From bf2253c2f4d00dde0c81604c17a5f0d508a37550 Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Mon, 23 Nov 2020 17:14:31 +0100 Subject: commands: boot: display each list entry in a separate line The boot entry lines could get quite long for bootspec entries and then follow-up commit will make them even longer, thus split the lines into two lines and indent the second. Signed-off-by: Ahmad Fatoum Signed-off-by: Sascha Hauer --- common/boot.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/common/boot.c b/common/boot.c index 586507e1ec..c6ec22873d 100644 --- a/common/boot.c +++ b/common/boot.c @@ -351,11 +351,10 @@ void bootsources_list(struct bootentries *bootentries) { struct bootentry *entry; - printf("%-20s\n", "title"); - printf("%-20s\n", "------"); + printf("title\n------\n"); bootentries_for_each_entry(bootentries, entry) - printf("%-20s %s\n", entry->title, entry->description); + printf("%s\n\t%s\n", entry->title, entry->description); } BAREBOX_MAGICVAR(global.boot.default, "default boot order"); -- cgit v1.2.3 From de224e9fda73e6c20cd57c0c3b1ca4bdeb8304be Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Mon, 23 Nov 2020 17:14:32 +0100 Subject: commands: boot: include blspec path name in entry title barebox linux-appendroot option having the same bootspec file in different partitions. boot -m will display the same title though, which doesn't help readability. Append the name of the config file to make the menu more useful in that case. Signed-off-by: Ahmad Fatoum Signed-off-by: Sascha Hauer --- common/blspec.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/common/blspec.c b/common/blspec.c index a07343f427..4e4ad29eb3 100644 --- a/common/blspec.c +++ b/common/blspec.c @@ -649,7 +649,8 @@ int blspec_scan_directory(struct bootentries *bootentries, const char *root) hwdevname = xstrdup(dev_name(entry->cdev->dev->parent)); } - entry->entry.title = xstrdup(blspec_entry_var_get(entry, "title")); + entry->entry.title = xasprintf("%s (%s)", blspec_entry_var_get(entry, "title"), + configname); entry->entry.description = basprintf("blspec entry, device: %s hwdevice: %s", devname ? devname : "none", hwdevname ? hwdevname : "none"); -- cgit v1.2.3 From 582d32b7d1acec818e4c225fa0ecd528125d8193 Mon Sep 17 00:00:00 2001 From: Rouven Czerwinski Date: Mon, 23 Nov 2020 10:28:38 +0100 Subject: ARM: vexpress: enable virt and vexpress boards The recent cleanup of the vexpress arch moved to a multi board configuration, however did not adjust the defconfig to build the virt and vexpress boards. Build both in the defconfig. Signed-off-by: Rouven Czerwinski Signed-off-by: Sascha Hauer --- arch/arm/configs/vexpress_defconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/configs/vexpress_defconfig b/arch/arm/configs/vexpress_defconfig index caa9f512d6..f17af2bb95 100644 --- a/arch/arm/configs/vexpress_defconfig +++ b/arch/arm/configs/vexpress_defconfig @@ -1,4 +1,6 @@ CONFIG_ARCH_VEXPRESS=y +CONFIG_MACH_VIRT=y +CONFIG_MACH_VEXPRESS=y CONFIG_AEABI=y CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS=y CONFIG_MALLOC_SIZE=0x0 -- cgit v1.2.3 From d96c54acb8c0fd05446ce9bffd931510d2b229e1 Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Thu, 26 Nov 2020 19:31:51 +0100 Subject: hush: remove non-functional code name is unused except for printing and value is modified, but never read back. They currently serve no purpose, so drop them. The actual splitting by '=' happens in set_local_var later. Signed-off-by: Ahmad Fatoum Signed-off-by: Sascha Hauer --- common/hush.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/common/hush.c b/common/hush.c index ec0d5129b7..a6fc4485bf 100644 --- a/common/hush.c +++ b/common/hush.c @@ -798,16 +798,9 @@ static int run_pipe_real(struct p_context *ctx, struct pipe *pi) * This junk is all to decide whether or not to export this * variable. */ int export_me = 0; - char *name, *value; - name = xstrdup(child->argv[i]); - hush_debug("Local environment set: %s\n", name); - value = strchr(name, '='); + hush_debug("Local environment set: %s\n", child->argv[i]); - if (value) - *value = 0; - - free(name); p = insert_var_value(child->argv[i]); rcode = set_local_var(p, export_me); if (rcode) -- cgit v1.2.3 From 205864b2ea133d752d45368582c5d6d3e4cdcb75 Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Thu, 26 Nov 2020 19:31:52 +0100 Subject: commands: nv: fix set/remove of multiple variables in one go Multiple nonopt arguments seems to have never worked, because the value was always extracted out of the first non-opt argument. After the first iteration, it'll have it's '=' stripped and thus value == NULL for all i > 0. Fix this. Before: $ nv a=1 b=2 c=3 $ echo "[$nv.a $nv.b $nv.c]" [1 ] After: $ nv a=1 b=2 c=3 $ echo "[$nv.a $nv.b $nv.c]" [1 2 3] Fixes: 0c2fccceb625 ("nv: Allow to set/remove multiple variables with one command") Signed-off-by: Ahmad Fatoum Signed-off-by: Sascha Hauer --- commands/nv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commands/nv.c b/commands/nv.c index 8d4192402c..fa865811dc 100644 --- a/commands/nv.c +++ b/commands/nv.c @@ -55,7 +55,7 @@ static int do_nv(int argc, char *argv[]) for (i = 0; i < argc; i++) { int ret; - value = strchr(argv[0], '='); + value = strchr(argv[i], '='); if (value) { *value = 0; value++; -- cgit v1.2.3 From 870f45338872b5ac02b2f87b6409036a6292ecf3 Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Thu, 26 Nov 2020 19:31:53 +0100 Subject: commands: nv: pass empty string for nv Setting a variable via the nv command results in the call chain nvar_add() -> nv_save() -> __nv_save(). __nv_save isn't supposed to be called with val=NULL argument however: dprintf(fd, "%s", val); Avoid this from happening by translating NULL into the empty string. This aligns nv with the behavior of hush and setenv (but not global, this will need to be looked at separately). Signed-off-by: Ahmad Fatoum Signed-off-by: Sascha Hauer --- commands/nv.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/commands/nv.c b/commands/nv.c index fa865811dc..a1cff08ee4 100644 --- a/commands/nv.c +++ b/commands/nv.c @@ -59,6 +59,8 @@ static int do_nv(int argc, char *argv[]) if (value) { *value = 0; value++; + } else { + value = ""; } if (do_remove) { -- cgit v1.2.3 From 8f57bc80c3e6a9f1c5318b52b98e9cc3268d10a8 Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Thu, 26 Nov 2020 19:31:54 +0100 Subject: commands: implement and use parse_assignment helper We have the split by '=' snippet at multiple locations that parse key=value pairs. Consolidate them to a single location. This makes code a bit easier to read at the cost of an extra 8 bytes (LZO-compressed THUMB2 barebox, static inline version is bigger). No functional change. Signed-off-by: Ahmad Fatoum Signed-off-by: Sascha Hauer --- commands/export.c | 4 +--- commands/global.c | 6 +----- commands/nv.c | 9 ++------- commands/setenv.c | 10 ++++------ common/bootchooser.c | 4 +--- common/fastboot.c | 4 +--- common/hush.c | 3 +-- include/command.h | 1 + include/string.h | 1 + lib/string.c | 11 +++++++++++ 10 files changed, 24 insertions(+), 29 deletions(-) diff --git a/commands/export.c b/commands/export.c index 8972b7d528..c69f1595c6 100644 --- a/commands/export.c +++ b/commands/export.c @@ -20,10 +20,8 @@ static int do_export(int argc, char *argv[]) return COMMAND_ERROR_USAGE; while (i < argc) { - if ((ptr = strchr(argv[i], '='))) { - *ptr++ = 0; + if ((ptr = parse_assignment(argv[i]))) setenv(argv[i], ptr); - } if (export(argv[i])) { printf("could not export: %s\n", argv[i]); return 1; diff --git a/commands/global.c b/commands/global.c index 15b6a9f3d3..cf8e9a5b48 100644 --- a/commands/global.c +++ b/commands/global.c @@ -37,11 +37,7 @@ static int do_global(int argc, char *argv[]) return COMMAND_ERROR_USAGE; for (i = 0; i < argc; i++) { - value = strchr(argv[i], '='); - if (value) { - *value = 0; - value++; - } + value = parse_assignment(argv[i]); if (do_remove) globalvar_remove(argv[i]); diff --git a/commands/nv.c b/commands/nv.c index a1cff08ee4..c60bb41677 100644 --- a/commands/nv.c +++ b/commands/nv.c @@ -55,13 +55,8 @@ static int do_nv(int argc, char *argv[]) for (i = 0; i < argc; i++) { int ret; - value = strchr(argv[i], '='); - if (value) { - *value = 0; - value++; - } else { - value = ""; - } + + value = parse_assignment(argv[i]) ?: ""; if (do_remove) { ret = nvvar_remove(argv[i]); diff --git a/commands/setenv.c b/commands/setenv.c index 9aeb8f010b..99604c35c3 100644 --- a/commands/setenv.c +++ b/commands/setenv.c @@ -9,17 +9,15 @@ static int do_setenv(int argc, char *argv[]) { - char *equal; + char *val; int ret; if (argc < 2) return COMMAND_ERROR_USAGE; - equal = strrchr(argv[1], '='); - if (equal) { - equal[0] = '\0'; - argv[2] = &equal[1]; - } + val = parse_assignment(argv[1]); + if (val) + argv[2] = val; if (argv[2]) ret = setenv(argv[1], argv[2]); diff --git a/common/bootchooser.c b/common/bootchooser.c index 7aa59d8a82..e982c22730 100644 --- a/common/bootchooser.c +++ b/common/bootchooser.c @@ -151,14 +151,12 @@ static int pr_setenv(struct bootchooser *bc, const char *fmt, ...) if (!str) return -ENOMEM; - val = strchr(str, '='); + val = parse_assignment(str); if (!val) { ret = -EINVAL; goto err; } - *val++ = '\0'; - oldval = getenv(str); if (!oldval || strcmp(oldval, val)) { if (bc->state) diff --git a/common/fastboot.c b/common/fastboot.c index 1b6dc28d8e..10b4ccf716 100644 --- a/common/fastboot.c +++ b/common/fastboot.c @@ -823,14 +823,12 @@ static void cb_oem_setenv(struct fastboot *fb, const char *cmd) pr_debug("%s: \"%s\"\n", __func__, cmd); - value = strchr(var, '='); + value = parse_assignment(var); if (!value) { ret = -EINVAL; goto out; } - *value++ = 0; - ret = setenv(var, value); if (ret) goto out; diff --git a/common/hush.c b/common/hush.c index a6fc4485bf..109bae4d3f 100644 --- a/common/hush.c +++ b/common/hush.c @@ -1117,12 +1117,11 @@ static int set_local_var(const char *s, int flg_export) /* Assume when we enter this function that we are already in * NAME=VALUE format. So the first order of business is to * split 's' on the '=' into 'name' and 'value' */ - value = strchr(name, '='); + value = parse_assignment(name); if (!value) { free(name); return -1; } - *value++ = 0; remove_quotes_in_str(value); diff --git a/include/command.h b/include/command.h index 860eae3e35..ccae568f87 100644 --- a/include/command.h +++ b/include/command.h @@ -13,6 +13,7 @@ #include #include #include +#include #ifndef __ASSEMBLY__ diff --git a/include/string.h b/include/string.h index b51566fd00..ef0b5e199e 100644 --- a/include/string.h +++ b/include/string.h @@ -14,5 +14,6 @@ void *__nokasan_default_memset(void *, int, __kernel_size_t); void *__default_memcpy(void * dest,const void *src,size_t count); void *__nokasan_default_memcpy(void * dest,const void *src,size_t count); +char *parse_assignment(char *str); #endif /* __STRING_H */ diff --git a/lib/string.c b/lib/string.c index b63041c5fb..dbb66fe4d2 100644 --- a/lib/string.c +++ b/lib/string.c @@ -899,3 +899,14 @@ int match_string(const char * const *array, size_t n, const char *string) return -EINVAL; } EXPORT_SYMBOL(match_string); + +char *parse_assignment(char *str) +{ + char *value; + + value = strchr(str, '='); + if (value) + *value++ = '\0'; + + return value; +} -- cgit v1.2.3 From 1ac440d8149184f3de289e8596bfa516b8a65d66 Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Tue, 24 Nov 2020 11:24:29 +0100 Subject: watchdog: implement watchdog_get_alias_id_from On device-tree enabled platforms, the Linux kernel will first attempt to use watchdog%d as watchdog name, where %d is the alias id. Add a function that given a barebox struct watchdog and the device tree root node of the kernel device tree, computes the corresponding kernel alias id. This may then later be used to pass an appropriate argument on the kernel command line. Signed-off-by: Ahmad Fatoum Signed-off-by: Sascha Hauer --- drivers/of/base.c | 77 +++++++++++++++++++++++++++++++++++++--------- drivers/watchdog/wd_core.c | 19 ++++++++++++ include/of.h | 8 +++++ include/watchdog.h | 8 +++++ 4 files changed, 97 insertions(+), 15 deletions(-) diff --git a/drivers/of/base.c b/drivers/of/base.c index c39da558d1..dcb5ccd018 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -149,6 +149,31 @@ static void of_alias_add(struct alias_prop *ap, struct device_node *np, ap->alias, ap->stem, ap->id, np->full_name); } +static struct device_node *of_alias_resolve(struct device_node *root, struct property *pp) +{ + /* Skip those we do not want to proceed */ + if (!of_prop_cmp(pp->name, "name") || + !of_prop_cmp(pp->name, "phandle") || + !of_prop_cmp(pp->name, "linux,phandle")) + return NULL; + + return of_find_node_by_path_from(root, of_property_get_value(pp)); +} + +static int of_alias_id_parse(const char *start, int *len) +{ + const char *end = start + strlen(start); + + /* walk the alias backwards to extract the id and work out + * the 'stem' string */ + while (isdigit(*(end-1)) && end > start) + end--; + + *len = end - start; + + return simple_strtol(end, NULL, 10); +} + /** * of_alias_scan - Scan all properties of 'aliases' node * @@ -175,28 +200,15 @@ void of_alias_scan(void) list_for_each_entry(pp, &of_aliases->properties, list) { const char *start = pp->name; - const char *end = start + strlen(start); struct device_node *np; struct alias_prop *ap; int id, len; - /* Skip those we do not want to proceed */ - if (!of_prop_cmp(pp->name, "name") || - !of_prop_cmp(pp->name, "phandle") || - !of_prop_cmp(pp->name, "linux,phandle")) - continue; - - np = of_find_node_by_path(of_property_get_value(pp)); + np = of_alias_resolve(root_node, pp); if (!np) continue; - /* walk the alias backwards to extract the id and work out - * the 'stem' string */ - while (isdigit(*(end-1)) && end > start) - end--; - len = end - start; - - id = simple_strtol(end, NULL, 10); + id = of_alias_id_parse(start, &len); if (id < 0) continue; @@ -235,6 +247,41 @@ int of_alias_get_id(struct device_node *np, const char *stem) } EXPORT_SYMBOL_GPL(of_alias_get_id); +int of_alias_get_id_from(struct device_node *root, struct device_node *np, + const char *stem) +{ + struct device_node *aliasnp, *entrynp; + struct property *pp; + + if (!root) + return of_alias_get_id(np, stem); + + aliasnp = of_find_node_by_path_from(root, "/aliases"); + if (!aliasnp) + return -ENODEV; + + for_each_property_of_node(aliasnp, pp) { + const char *start = pp->name; + int id, len; + + entrynp = of_alias_resolve(root_node, pp); + if (entrynp != np) + continue; + + id = of_alias_id_parse(start, &len); + if (id < 0) + continue; + + if (strncasecmp(start, stem, len)) + continue; + + return id; + } + + return -ENODEV; +} +EXPORT_SYMBOL_GPL(of_alias_get_id_from); + const char *of_alias_get(struct device_node *np) { struct alias_prop *app; diff --git a/drivers/watchdog/wd_core.c b/drivers/watchdog/wd_core.c index 665338af61..643c53268f 100644 --- a/drivers/watchdog/wd_core.c +++ b/drivers/watchdog/wd_core.c @@ -261,6 +261,25 @@ struct watchdog *watchdog_get_default(void) } EXPORT_SYMBOL(watchdog_get_default); +int watchdog_get_alias_id_from(struct watchdog *wd, struct device_node *root) +{ + struct device_node *dstnp, *srcnp = wd->hwdev ? wd->hwdev->device_node : NULL; + char *name; + + if (!srcnp) + return -ENODEV; + + name = of_get_reproducible_name(srcnp); + dstnp = of_find_node_by_reproducible_name(root, name); + free(name); + + if (!dstnp) + return -ENODEV; + + return of_alias_get_id_from(root, wd->hwdev->device_node, "watchdog"); +} +EXPORT_SYMBOL(watchdog_get_alias_id_from); + struct watchdog *watchdog_get_by_name(const char *name) { struct watchdog *tmp; diff --git a/include/of.h b/include/of.h index 08a02e1105..6181da8c61 100644 --- a/include/of.h +++ b/include/of.h @@ -254,6 +254,8 @@ extern int of_count_phandle_with_args(const struct device_node *np, extern void of_alias_scan(void); extern int of_alias_get_id(struct device_node *np, const char *stem); +extern int of_alias_get_id_from(struct device_node *root, struct device_node *np, + const char *stem); extern const char *of_alias_get(struct device_node *np); extern int of_modalias_node(struct device_node *node, char *modalias, int len); @@ -677,6 +679,12 @@ static inline int of_alias_get_id(struct device_node *np, const char *stem) return -ENOSYS; } +static inline int of_alias_get_id_from(struct device_node *root, struct device_node *np, + const char *stem) +{ + return -ENOSYS; +} + static inline const char *of_alias_get(struct device_node *np) { return NULL; diff --git a/include/watchdog.h b/include/watchdog.h index 81414ef8ec..4d755a5a79 100644 --- a/include/watchdog.h +++ b/include/watchdog.h @@ -13,6 +13,8 @@ enum wdog_hw_runnning { WDOG_HW_NOT_RUNNING = PARAM_TRISTATE_FALSE }; +struct device_node; + struct watchdog { int (*set_timeout)(struct watchdog *, unsigned); const char *name; @@ -44,6 +46,7 @@ int watchdog_register(struct watchdog *); int watchdog_deregister(struct watchdog *); struct watchdog *watchdog_get_default(void); struct watchdog *watchdog_get_by_name(const char *name); +int watchdog_get_alias_id_from(struct watchdog *, struct device_node *); int watchdog_set_timeout(struct watchdog*, unsigned); int watchdog_inhibit_all(void); #else @@ -76,6 +79,11 @@ static inline int watchdog_inhibit_all(void) { return -ENOSYS; } + +static inline int watchdog_get_alias_id_from(struct watchdog *wd, struct device_node *np) +{ + return -ENOSYS; +} #endif #define WATCHDOG_DEFAULT_PRIORITY 100 -- cgit v1.2.3 From f382be77f8c02cbaa94dc2664c3ab0d46775cab9 Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Tue, 24 Nov 2020 11:24:30 +0100 Subject: boot: introduce option to pass barebox-enabled watchdog to systemd Like Linux, barebox supports co-existence of multiple watchdog devices. On boot, barebox enables only the default watchdog, which is defined as the watchdog with highest non-zero priority. The kernel handles all watchdogs the same and defers to userspace, which watchdogs to service. It can be useful to have barebox tell the system, which watchdog it activated, so it can service the same. Having this feature behind a global variable adds 354 bytes to a LZO compressed THUMB2 barebox. Users can opt out by toggling the Kconfig option, which defaults to off. Signed-off-by: Ahmad Fatoum Signed-off-by: Sascha Hauer --- common/Kconfig | 10 ++++++++++ common/boot.c | 16 +++++++++++++--- common/oftree.c | 25 +++++++++++++++++++++++++ include/boot.h | 3 +++ 4 files changed, 51 insertions(+), 3 deletions(-) diff --git a/common/Kconfig b/common/Kconfig index ffdce2f96c..d1baee60e6 100644 --- a/common/Kconfig +++ b/common/Kconfig @@ -1007,6 +1007,16 @@ config MACHINE_ID Note: if no hashable information is available no machine id will be passed to the kernel. +config SYSTEMD_OF_WATCHDOG + bool "inform devicetree-enabled kernel of used watchdog" + depends on WATCHDOG && OFTREE && FLEXIBLE_BOOTARGS + help + Sets the linux.bootargs.dyn.watchdog global variable with a value of + systemd.watchdog-device=/dev/WDOG if barebox succeeded in enabling + the watchdog WDOG prior to boot. WDOG is the alias of the watchdog + in the kernel device tree. If the kernel is booted without a device + tree or with one that lacks aliases, nothing is added. + menu "OP-TEE loading" config OPTEE_SIZE diff --git a/common/boot.c b/common/boot.c index c6ec22873d..1657608d33 100644 --- a/common/boot.c +++ b/common/boot.c @@ -116,6 +116,13 @@ void boot_set_watchdog_timeout(unsigned int timeout) boot_watchdog_timeout = timeout; } +static struct watchdog *boot_enabled_watchdog; + +struct watchdog *boot_get_enabled_watchdog(void) +{ + return boot_enabled_watchdog; +} + static char *global_boot_default; static char *global_user; @@ -143,10 +150,13 @@ int boot_entry(struct bootentry *be, int verbose, int dryrun) printf("Booting entry '%s'\n", be->title); if (IS_ENABLED(CONFIG_WATCHDOG) && boot_watchdog_timeout) { - ret = watchdog_set_timeout(watchdog_get_default(), - boot_watchdog_timeout); - if (ret) + boot_enabled_watchdog = watchdog_get_default(); + + ret = watchdog_set_timeout(boot_enabled_watchdog, boot_watchdog_timeout); + if (ret) { pr_warn("Failed to enable watchdog: %s\n", strerror(-ret)); + boot_enabled_watchdog = NULL; + } } ret = be->boot(be, verbose, dryrun); diff --git a/common/oftree.c b/common/oftree.c index 36906e86fc..075b9d6b8b 100644 --- a/common/oftree.c +++ b/common/oftree.c @@ -14,6 +14,8 @@ #include #include #include +#include +#include #define MAX_LEVEL 32 /* how deeply nested we will go */ @@ -139,6 +141,26 @@ static int of_fixup_bootargs_bootsource(struct device_node *root, return ret; } +static void watchdog_build_bootargs(struct watchdog *watchdog, struct device_node *root) +{ + int alias_id; + char *buf; + + if (!watchdog) + return; + + alias_id = watchdog_get_alias_id_from(watchdog, root); + if (alias_id < 0) + return; + + buf = basprintf("systemd.watchdog-device=/dev/watchdog%d", alias_id); + if (!buf) + return; + + globalvar_add_simple("linux.bootargs.dyn.watchdog", buf); + free(buf); +} + static int of_fixup_bootargs(struct device_node *root, void *unused) { struct device_node *node; @@ -147,6 +169,9 @@ static int of_fixup_bootargs(struct device_node *root, void *unused) int instance = reset_source_get_instance(); struct device_d *dev; + if (IS_ENABLED(CONFIG_SYSTEMD_OF_WATCHDOG)) + watchdog_build_bootargs(boot_get_enabled_watchdog(), root); + str = linux_bootargs_get(); if (!str) return 0; diff --git a/include/boot.h b/include/boot.h index 4054c27d93..3d5dd1cb6e 100644 --- a/include/boot.h +++ b/include/boot.h @@ -42,7 +42,10 @@ int bootentry_register_provider(int (*fn)(struct bootentries *bootentries, const #define bootentries_for_each_entry(bootentries, entry) \ list_for_each_entry(entry, &bootentries->entries, list) +struct watchdog; + void boot_set_watchdog_timeout(unsigned int timeout); +struct watchdog *boot_get_enabled_watchdog(void); struct bootentries *bootentries_alloc(void); void bootentries_free(struct bootentries *bootentries); int bootentry_create_from_name(struct bootentries *bootentries, -- cgit v1.2.3 From 8b65d4b7c5ef484343d3e955ab01b178af80502c Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Thu, 3 Dec 2020 11:42:56 +0100 Subject: usb: host: ehci: fix mismatch in format string sz is of type size_t. Use the appropriate format string specifier for printing it. Signed-off-by: Ahmad Fatoum Signed-off-by: Sascha Hauer --- drivers/usb/host/ehci-hcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 38999927c5..287849102d 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -240,7 +240,7 @@ static int ehci_td_buffer(struct qTD *td, dma_addr_t addr, size_t sz) } if (idx == buffer_count) { - pr_debug("out of buffer pointers (%u bytes left)\n", sz); + pr_debug("out of buffer pointers (%zu bytes left)\n", sz); return -ENOMEM; } -- cgit v1.2.3 From 10e0637d0387051e7524c9a8b964939c459938c9 Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Thu, 3 Dec 2020 11:42:57 +0100 Subject: commands: memtester: fix mismatched format string expression is of type size_t. Use the appropriate format string specifier for printing it. Signed-off-by: Ahmad Fatoum Signed-off-by: Sascha Hauer --- commands/memtester/memtester.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commands/memtester/memtester.c b/commands/memtester/memtester.c index 8b64d32329..130dc97c83 100644 --- a/commands/memtester/memtester.c +++ b/commands/memtester/memtester.c @@ -139,7 +139,7 @@ static int do_memtester(int argc, char **argv) { wantbytes = (size_t) strtoull_suffix(argv[optind], 0, 0); if (wantbytes < 2 * sizeof(ul)) { - printf("need at least %ldB of memory to test\n", 2 * sizeof(ul)); + printf("need at least %zuB of memory to test\n", 2 * sizeof(ul)); return COMMAND_ERROR_USAGE; } wantmb = (wantbytes >> 20); -- cgit v1.2.3 From 8bc9efc85b8af8a23a0c86b04e2265730a220ade Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 11 Dec 2020 10:54:03 +0100 Subject: spi: store names in struct spi_device_id as pointers Instead of putting an array for the names into struct spi_device_id use pointers. This saves around 3000 bytes of binary space in a ARM32 barebox build. Signed-off-by: Sascha Hauer --- include/linux/mod_devicetable.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h index 1fbb3dc5c1..2c04454260 100644 --- a/include/linux/mod_devicetable.h +++ b/include/linux/mod_devicetable.h @@ -21,7 +21,7 @@ struct pci_device_id { #define SPI_NAME_SIZE 32 struct spi_device_id { - char name[SPI_NAME_SIZE]; + const char *name; unsigned long driver_data; }; -- cgit v1.2.3