diff options
Diffstat (limited to 'commands')
74 files changed, 2248 insertions, 402 deletions
diff --git a/commands/Kconfig b/commands/Kconfig index 3e21dc4c05..8d0816c4d0 100644 --- a/commands/Kconfig +++ b/commands/Kconfig @@ -60,6 +60,14 @@ config CMD_RISCV_CPUINFO help Show info about RISC-V CPU +config CMD_BOOTROM + bool "bootrom command" + depends on ARCH_IMX8M + help + Interact with bootrom on i.MX8M + + bootrom [-la] + config CMD_DEVINFO tristate default y @@ -115,6 +123,14 @@ config CMD_DRVINFO help List compiled-in device drivers and the devices they support. +config CMD_EFI_HANDLE_DUMP + tristate + default y + depends on EFI + prompt "efi_handle_dump" + help + Dump information on EFI handles + config CMD_HELP tristate default y @@ -193,12 +209,13 @@ config CMD_MEMINFO config CMD_ARM_MMUINFO bool "mmuinfo command" - depends on CPU_V7 + depends on CPU_V7 || CPU_V8 + select MMUINFO help Say yes here to get a mmuinfo command to show some - MMU and cache information using the cp15 registers. + MMU and cache information using the cp15/model-specific registers. - Example: + Example for ARMv7: PAR result for 0x00110000: privileged read: 0x00110090 @@ -240,6 +257,14 @@ config CMD_REGULATOR the regulator command lists the currently registered regulators and their current state. +config CMD_PM_DOMAIN + bool + depends on PM_GENERIC_DOMAINS + prompt "pm_domain command" + help + The pm_domain command lists the currently registered power domains and + their current state. + config CMD_NVMEM bool depends on NVMEM @@ -318,6 +343,15 @@ config CMD_SLICE command can be used to print informations about slices and also to manipulate them on the command line for debugging purposes. +config CMD_FCB + depends on BAREBOX_UPDATE_IMX_NAND_FCB + tristate + prompt "fcb" + help + Several i.MX SoCs booting from NAND flash need a so called Flash Control Block + at the beginning of the NAND device. The fcb command prints information about + the FCB. + # end Information commands endmenu @@ -435,12 +469,15 @@ config CMD_GO help Start application at address or file - Usage: go ADDR [ARG...] + Usage: go [-si] ADDR [ARG...] Start application at ADDR passing ARG as arguments. If addr does not start with a digit it is interpreted as a filename in which case the file is memmapped and executed + Options: + -s pass all arguments as strings referenced by argc, argv arguments (default) + -i pass up to four integer arguments using default calling convention config CMD_LOADB depends on CONSOLE_FULL @@ -626,6 +663,42 @@ config CMD_MOUNT -o OPTIONS set file system OPTIONS -v verbose +config CMD_FINDMNT + tristate + prompt "findmnt" + help + Find a file system + + Usage: findmnt [ DEVICE | -T FILE ] + + findmnt will list all mounted filesystems or search + for a filesystem when given the mountpoint or the + source device as an argument + + Options: + -T mount target file path + +config CMD_PARTED + tristate + depends on PARTITION + select PARTITION_MANIPULATION + prompt "parted" + help + parted - edit partition tables + + Usage: parted <device> [command [options...]...] + + parted is a partition manipulation program with a behaviour similar to + GNU Parted + + commands: + print print partitions + mklabel <type> create a new partition table + rm <num> remove a partition + mkpart <name> <fstype> <start> <end> create a new partition + unit <unit> change display/input units + refresh refresh a partition table + config CMD_UBI tristate default y if MTD_UBI @@ -939,6 +1012,22 @@ config CMD_LS -C column format (opposite of long format) -R list subdirectories recursively +config CMD_STAT + tristate + prompt "stat" + select PRINTF_UUID + help + Display file status + + Usage: stat [-LcC] [FILEDIR...] + + Display status information about the specified files or directories. + + Options: + -L follow symlinks + -c DIR lookup file relative to directory DIR + -C DIR change root to DIR before file lookup + config CMD_MD5SUM tristate select COMPILE_HASH @@ -988,10 +1077,11 @@ config CMD_RM help Remove files - Usage: rm [-r] FILES... + Usage: rm [-rf] FILES... Options: -r remove directories and their contents recursively + -f ignore nonexistent files config CMD_RMDIR tristate @@ -1168,15 +1258,17 @@ config CMD_SLEEP config CMD_TEST tristate depends on SHELL_HUSH + select FNMATCH default y prompt "test" help - Minimal test command like in /bin/sh + Minimal test command like in /bin/sh with support for bash-style + [[ expression ]] tests as well. Usage: test [EXPR] Options: - !, =, !=, -eq, -ne, -ge, -gt, -le, -lt, -o, -a, -z, -n, -d, -e, + !, =, ==, !=, -eq, -ne, -ge, -gt, -le, -lt, -o, -a, -z, -n, -d, -e, -f, -L; see 'man test' on your PC for more information. config CMD_TRUE @@ -1344,7 +1436,7 @@ config CMD_EDIT depends on CONSOLE_FULL || CONSOLE_SIMPLE prompt "edit" help - A small fill-screen editor. + A small full-screen editor. Usage: edit FILE @@ -1668,6 +1760,7 @@ config CMD_MEMSET config CMD_MEMTEST tristate + select MEMTEST prompt "memtest" help The memtest command can test the registered barebox memory. @@ -1888,6 +1981,18 @@ config CMD_I2C -w use word (16 bit) wide access -v verbose +config CMD_PWM + bool + depends on PWM + prompt "PWM commands: pwm" + help + pwm - set or show pwm state + + Usage: pwm [dDPfwisv] + + Controls the pwm values such as period and duty cycle, or shows + the current values. + config CMD_LED bool depends on LED @@ -1911,12 +2016,14 @@ config CMD_NAND help NAND flash handling - Usage: nand [-adb] NANDDEV + Usage: nand [-adbgi] NANDDEV Options: -a register a bad block aware device ontop of a normal NAND device -d deregister a bad block aware device -b OFFS mark block at OFFSet as bad + -g OFFS mark block at OFFSet as good + -i info. Show information about bad blocks config CMD_NANDTEST tristate @@ -2117,6 +2224,15 @@ config CMD_FIRMWARELOAD Provides the "firmwareload" command which deals with devices which need firmware to work. It is also used to upload firmware to FPGA devices. +config CMD_KALLSYMS + depends on KALLSYMS + bool + prompt "kallsyms" + help + query kallsyms table + + Usage: kallsyns [SYMBOL | ADDRESS] + config CMD_KEYSTORE depends on CRYPTO_KEYSTORE bool @@ -2147,6 +2263,21 @@ config CMD_LSMOD help List loaded barebox modules. +config CMD_OF_COMPATIBLE + tristate + select OFTREE + prompt "of_compatible" + help + Check DT node's compatible + + Usage: [-fFnk] [COMPAT] + + Options: + -f dtb work on dtb instead of internal devicetree + -F apply fixups on devicetree before compare + -n node node path or alias to compare its compatible (default is /) + -k compare $global.of.kernel.add_machine_compatible as well + config CMD_OF_DIFF tristate select OFTREE @@ -2214,6 +2345,20 @@ config CMD_OF_DISPLAY_TIMINGS -s path select display-timings and register oftree fixup -f dtb work on dtb. Has no effect on -s option +config CMD_OF_FIXUP + tristate + select OFTREE + depends on KALLSYMS + prompt "of_fixup" + help + List and enable/disable fixups + + Usage: of_fixup [-de] [fixups...] + + Options: + -d disable fixup + -e re-enable fixup + config CMD_OF_FIXUP_STATUS tristate select OFTREE @@ -2267,6 +2412,19 @@ config CMD_TIME Note: This command depends on COMMAND being interruptible, otherwise the timer may overrun resulting in incorrect results +config CMD_UPTIME + bool "uptime" + help + uptime - Tell how long barebox has been running + + Usage: uptime [-n] + + This command formats the number of elapsed nanoseconds + as measured with the current clocksource. + + Options: + -n output elapsed time in nanoseconds + config CMD_STATE tristate depends on STATE @@ -2298,6 +2456,13 @@ config CMD_UBSAN This is a test command for the undefined behavior sanitizer. It triggers various undefined behavior, and detect it. +config CMD_STACKSMASH + tristate "stacksmash" + depends on STACKPROTECTOR || STACK_GUARD_PAGE || COMPILE_TEST + help + This commands trashes the stack to test stackprotector and + guard page. This command does not return. + # end Miscellaneous commands endmenu diff --git a/commands/Makefile b/commands/Makefile index 0aae8893d6..30e1f8403e 100644 --- a/commands/Makefile +++ b/commands/Makefile @@ -26,6 +26,7 @@ obj-$(CONFIG_CMD_POWEROFF) += poweroff.o obj-$(CONFIG_CMD_GO) += go.o obj-$(CONFIG_CMD_PARTITION) += partition.o obj-$(CONFIG_CMD_LS) += ls.o +obj-$(CONFIG_CMD_STAT) += stat.o obj-$(CONFIG_CMD_CD) += cd.o obj-$(CONFIG_CMD_PWD) += pwd.o obj-$(CONFIG_CMD_MKDIR) += mkdir.o @@ -35,6 +36,7 @@ obj-$(CONFIG_CMD_RM) += rm.o obj-$(CONFIG_CMD_CAT) += cat.o obj-$(CONFIG_CMD_MOUNT) += mount.o obj-$(CONFIG_CMD_UMOUNT) += umount.o +obj-$(CONFIG_CMD_FINDMNT) += findmnt.o obj-$(CONFIG_CMD_REGINFO) += reginfo.o obj-$(CONFIG_CMD_CRC) += crc.o obj-$(CONFIG_CMD_CLEAR) += clear.o @@ -68,6 +70,7 @@ obj-$(CONFIG_CMD_GPIO) += gpio.o obj-$(CONFIG_CMD_UNCOMPRESS) += uncompress.o obj-$(CONFIG_CMD_I2C) += i2c.o obj-$(CONFIG_CMD_SPI) += spi.o +obj-$(CONFIG_CMD_PWM) += pwm.o obj-$(CONFIG_CMD_MIPI_DBI) += mipi_dbi.o obj-$(CONFIG_CMD_UBI) += ubi.o obj-$(CONFIG_CMD_UBIFORMAT) += ubiformat.o @@ -79,12 +82,15 @@ obj-$(CONFIG_CMD_WD) += wd.o obj-$(CONFIG_CMD_LED_TRIGGER) += trigger.o obj-$(CONFIG_CMD_USB) += usb.o obj-$(CONFIG_CMD_TIME) += time.o +obj-$(CONFIG_CMD_UPTIME) += uptime.o obj-$(CONFIG_CMD_OFTREE) += oftree.o +obj-$(CONFIG_CMD_OF_COMPATIBLE) += of_compatible.o obj-$(CONFIG_CMD_OF_DIFF) += of_diff.o obj-$(CONFIG_CMD_OF_PROPERTY) += of_property.o obj-$(CONFIG_CMD_OF_NODE) += of_node.o obj-$(CONFIG_CMD_OF_DUMP) += of_dump.o obj-$(CONFIG_CMD_OF_DISPLAY_TIMINGS) += of_display_timings.o +obj-$(CONFIG_CMD_OF_FIXUP) += of_fixup.o obj-$(CONFIG_CMD_OF_FIXUP_STATUS) += of_fixup_status.o obj-$(CONFIG_CMD_OF_OVERLAY) += of_overlay.o obj-$(CONFIG_CMD_MAGICVAR) += magicvar.o @@ -101,6 +107,7 @@ obj-$(CONFIG_CMD_READLINK) += readlink.o obj-$(CONFIG_CMD_LET) += let.o obj-$(CONFIG_CMD_LN) += ln.o obj-$(CONFIG_CMD_CLK) += clk.o +obj-$(CONFIG_CMD_KALLSYMS) += kallsyms.o obj-$(CONFIG_CMD_KEYSTORE) += keystore.o obj-$(CONFIG_CMD_TFTP) += tftp.o obj-$(CONFIG_CMD_FILETYPE) += filetype.o @@ -116,6 +123,7 @@ obj-$(CONFIG_CMD_READF) += readf.o obj-$(CONFIG_CMD_MENUTREE) += menutree.o obj-$(CONFIG_CMD_2048) += 2048.o obj-$(CONFIG_CMD_REGULATOR) += regulator.o +obj-$(CONFIG_CMD_PM_DOMAIN) += pm_domain.o obj-$(CONFIG_CMD_LSPCI) += lspci.o obj-$(CONFIG_CMD_IMD) += imd.o obj-$(CONFIG_CMD_HWCLOCK) += hwclock.o @@ -139,5 +147,8 @@ obj-$(CONFIG_CMD_BTHREAD) += bthread.o obj-$(CONFIG_CMD_UBSAN) += ubsan.o obj-$(CONFIG_CMD_SELFTEST) += selftest.o obj-$(CONFIG_CMD_TUTORIAL) += tutorial.o +obj-$(CONFIG_CMD_STACKSMASH) += stacksmash.o +obj-$(CONFIG_CMD_PARTED) += parted.o +obj-$(CONFIG_CMD_EFI_HANDLE_DUMP) += efi_handle_dump.o UBSAN_SANITIZE_ubsan.o := y diff --git a/commands/boot.c b/commands/boot.c index 5fd59f8642..e4699520e8 100644 --- a/commands/boot.c +++ b/commands/boot.c @@ -44,7 +44,7 @@ static int do_boot(int argc, char *argv[]) do_list = 1; break; case 'd': - dryrun = 1; + dryrun++; break; case 'M': /* To simplify scripting, an empty string is treated as 1 */ @@ -145,7 +145,7 @@ BAREBOX_CMD_HELP_TEXT("one succeeds.") BAREBOX_CMD_HELP_TEXT("") BAREBOX_CMD_HELP_TEXT("Options:") BAREBOX_CMD_HELP_OPT ("-v","Increase verbosity") -BAREBOX_CMD_HELP_OPT ("-d","Dryrun. See what happens but do no actually boot") +BAREBOX_CMD_HELP_OPT ("-d","Dryrun. See what happens but do no actually boot (pass twice to run scripts)") BAREBOX_CMD_HELP_OPT ("-l","List available boot sources") BAREBOX_CMD_HELP_OPT ("-m","Show a menu with boot options") BAREBOX_CMD_HELP_OPT ("-M INDEX","Show a menu with boot options with entry INDEX preselected") diff --git a/commands/cat.c b/commands/cat.c index 17c31ed083..503520dc64 100644 --- a/commands/cat.c +++ b/commands/cat.c @@ -40,7 +40,7 @@ static int do_cat(int argc, char *argv[]) fd = open(argv[args], O_RDONLY); if (fd < 0) { err = 1; - printf("could not open %s: %s\n", argv[args], errno_str()); + printf("could not open %s: %m\n", argv[args]); goto out; } diff --git a/commands/clk.c b/commands/clk.c index b1741b9da4..606519091e 100644 --- a/commands/clk.c +++ b/commands/clk.c @@ -67,7 +67,7 @@ static int do_clk_set_rate(int argc, char *argv[]) } BAREBOX_CMD_HELP_START(clk_set_rate) -BAREBOX_CMD_HELP_TEXT("Set clock CLK to RATE") +BAREBOX_CMD_HELP_TEXT("Set clock CLK rate to HZ") BAREBOX_CMD_HELP_END BAREBOX_CMD_START(clk_set_rate) diff --git a/commands/detect.c b/commands/detect.c index 70eca57537..ad1745adce 100644 --- a/commands/detect.c +++ b/commands/detect.c @@ -12,7 +12,7 @@ static int do_detect(int argc, char *argv[]) { - struct device_d *dev; + struct device *dev; int opt, i, ret, err; int option_list = 0; int option_all = 0; diff --git a/commands/devinfo.c b/commands/devinfo.c index e171ecc62c..6001b00cfa 100644 --- a/commands/devinfo.c +++ b/commands/devinfo.c @@ -6,9 +6,9 @@ #include <complete.h> #include <driver.h> -static int do_devinfo_subtree(struct device_d *dev, int depth) +static int do_devinfo_subtree(struct device *dev, int depth) { - struct device_d *child; + struct device *child; struct cdev *cdev, *cdevl; int i; @@ -46,7 +46,7 @@ static int do_devinfo_subtree(struct device_d *dev, int depth) static int do_devinfo(int argc, char *argv[]) { - struct device_d *dev; + struct device *dev; struct param_d *param; int i; int first; @@ -102,9 +102,22 @@ static int do_devinfo(int argc, char *argv[]) printf("\n"); } #ifdef CONFIG_OFDEVICE - if (dev->device_node) { - printf("Device node: %s\n", dev->device_node->full_name); - of_print_nodes(dev->device_node, 0, ~0); + if (dev->of_node) { + struct device *main_dev = dev->of_node->dev; + + printf("DMA Coherent: %s%s\n", + dev_is_dma_coherent(dev) ? "true" : "false", + dev->dma_coherent == DEV_DMA_COHERENCE_DEFAULT ? " (default)" : ""); + + printf("Device node: %pOF", dev->of_node); + if (!main_dev) { + printf(" (unpopulated)\n"); + } else if (main_dev != dev) { + printf(" (populated by %s)\n", dev_name(main_dev)); + } else { + printf("\n"); + of_print_nodes(dev->of_node, 0, ~0); + } } #endif } diff --git a/commands/devunbind.c b/commands/devunbind.c index 3f9cd7b849..d30193b285 100644 --- a/commands/devunbind.c +++ b/commands/devunbind.c @@ -10,7 +10,7 @@ static int do_devunbind(int argc, char *argv[]) { bool unregister = false; - struct device_d *dev; + struct device *dev; int ret = COMMAND_SUCCESS, i, opt; while ((opt = getopt(argc, argv, "fl")) > 0) { @@ -20,9 +20,14 @@ static int do_devunbind(int argc, char *argv[]) break; case 'l': list_for_each_entry(dev, &active_device_list, active) { + void *rm_dev; + BUG_ON(!dev->driver); - if (dev->bus->remove) - printf("%pS(%s, %s)\n", dev->bus->remove, + + rm_dev = dev->bus->remove ?: dev->driver->remove; + + if (rm_dev) + printf("%pS(%s, %s)\n", rm_dev, dev->driver->name, dev_name(dev)); } return 0; @@ -47,13 +52,12 @@ static int do_devunbind(int argc, char *argv[]) continue; } - if (!dev->driver || !dev->bus->remove) { - printf("skipping unbound %s\n", argv[i]); + if (!device_remove(dev)) { + printf("no remove callback registered for %s\n", argv[i]); ret = COMMAND_ERROR; continue; } - dev->bus->remove(dev); dev->driver = NULL; list_del(&dev->active); } diff --git a/commands/dfu.c b/commands/dfu.c index 1734947fe0..2116747f68 100644 --- a/commands/dfu.c +++ b/commands/dfu.c @@ -10,8 +10,8 @@ #include <getopt.h> #include <fs.h> #include <xfuncs.h> -#include <usb/dfu.h> -#include <usb/gadget-multi.h> +#include <linux/usb/dfu.h> +#include <linux/usb/gadget-multi.h> #include <linux/err.h> /* dfu /dev/self0(bootloader)sr,/dev/nand0.root.bb(root) diff --git a/commands/digest.c b/commands/digest.c index b7ed4d50af..e57920e582 100644 --- a/commands/digest.c +++ b/commands/digest.c @@ -190,7 +190,7 @@ err: BAREBOX_CMD_HELP_START(digest) BAREBOX_CMD_HELP_TEXT("Calculate a digest over a FILE or a memory area.") BAREBOX_CMD_HELP_TEXT("Options:") -BAREBOX_CMD_HELP_OPT ("-a <algo>\t", "hash or signature algorithm to use") +BAREBOX_CMD_HELP_OPT ("-a <algo>\t", "hash or signature algorithm name/driver to use") BAREBOX_CMD_HELP_OPT ("-k <key>\t", "use supplied <key> (ASCII or hex) for MAC") BAREBOX_CMD_HELP_OPT ("-K <file>\t", "use key from <file> (binary) for MAC") BAREBOX_CMD_HELP_OPT ("-s <hex>\t", "verify data against supplied <hex> (hash, MAC or signature)") diff --git a/commands/dmesg.c b/commands/dmesg.c index 15ad449639..8a60f07507 100644 --- a/commands/dmesg.c +++ b/commands/dmesg.c @@ -11,6 +11,42 @@ #include <getopt.h> #include <clock.h> +static int str_to_loglevel(const char *str) +{ + int ret; + unsigned long level; + + ret = kstrtoul(str, 10, &level); + if (!ret) { + if (level > MSG_VDEBUG) + goto unknown; + return level; + } + + if (!strcmp(str, "vdebug")) + return MSG_VDEBUG; + if (!strcmp(str, "debug")) + return MSG_DEBUG; + if (!strcmp(str, "info")) + return MSG_INFO; + if (!strcmp(str, "notice")) + return MSG_NOTICE; + if (!strcmp(str, "warn")) + return MSG_WARNING; + if (!strcmp(str, "err")) + return MSG_ERR; + if (!strcmp(str, "crit")) + return MSG_CRIT; + if (!strcmp(str, "alert")) + return MSG_ALERT; + if (!strcmp(str, "emerg")) + return MSG_EMERG; +unknown: + printf("dmesg: unknown loglevel %s\n", str); + + return -EINVAL; +} + static unsigned dmesg_get_levels(const char *__args) { char *args = xstrdup(__args); @@ -18,28 +54,19 @@ static unsigned dmesg_get_levels(const char *__args) unsigned flags = 0; while (1) { + int level; + str = strsep(&levels, ","); if (!str) break; - if(!strcmp(str, "vdebug")) - flags |= BAREBOX_LOG_PRINT_VDEBUG; - else if(!strcmp(str, "debug")) - flags |= BAREBOX_LOG_PRINT_DEBUG; - else if(!strcmp(str, "info")) - flags |= BAREBOX_LOG_PRINT_INFO; - else if(!strcmp(str, "notice")) - flags |= BAREBOX_LOG_PRINT_NOTICE; - else if(!strcmp(str, "warn")) - flags |= BAREBOX_LOG_PRINT_WARNING; - else if(!strcmp(str, "err")) - flags |= BAREBOX_LOG_PRINT_ERR; - else if(!strcmp(str, "crit")) - flags |= BAREBOX_LOG_PRINT_CRIT; - else if(!strcmp(str, "alert")) - flags |= BAREBOX_LOG_PRINT_ALERT; - else if(!strcmp(str, "emerg")) - flags |= BAREBOX_LOG_PRINT_EMERG; + level = str_to_loglevel(str); + if (level < 0) { + flags = 0; + break; + } + + flags |= BIT(level); } free(args); @@ -49,11 +76,12 @@ static unsigned dmesg_get_levels(const char *__args) static int do_dmesg(int argc, char *argv[]) { - int opt, i; + int opt, ret, i; int delete_buf = 0, emit = 0; unsigned flags = 0, levels = 0; + char *set = NULL; - while ((opt = getopt(argc, argv, "ctderl:")) > 0) { + while ((opt = getopt(argc, argv, "ctderl:n:")) > 0) { switch (opt) { case 'c': delete_buf = 1; @@ -70,16 +98,30 @@ static int do_dmesg(int argc, char *argv[]) case 'l': levels = dmesg_get_levels(optarg); if (!levels) - return COMMAND_ERROR_USAGE; + return COMMAND_ERROR; break; case 'r': flags |= BAREBOX_LOG_PRINT_RAW | BAREBOX_LOG_PRINT_TIME; break; + case 'n': + set = optarg; + break; default: return COMMAND_ERROR_USAGE; } } + if (set) { + int level = str_to_loglevel(set); + + if (level < 0) + return COMMAND_ERROR; + + barebox_loglevel = level; + + return 0; + } + if (emit) { char *buf; int len = 0; @@ -106,7 +148,9 @@ static int do_dmesg(int argc, char *argv[]) return 0; } - log_print(flags, levels); + ret = log_print(flags, levels); + if (ret) + return 1; if (delete_buf) log_clean(10); @@ -114,12 +158,19 @@ static int do_dmesg(int argc, char *argv[]) return 0; } + BAREBOX_CMD_HELP_START(dmesg) +BAREBOX_CMD_HELP_TEXT("print or control the barebox message buffer") +BAREBOX_CMD_HELP_TEXT("Loglevels can be specified as number (0=emerg, 7=vdebug)") +BAREBOX_CMD_HELP_TEXT("Known debug loglevels are: emerg, alert, crit, err, warn, notice, info, debug,") +BAREBOX_CMD_HELP_TEXT("vdebug") +BAREBOX_CMD_HELP_TEXT("") BAREBOX_CMD_HELP_TEXT("Options:") BAREBOX_CMD_HELP_OPT ("-c", "Delete messages after printing them") BAREBOX_CMD_HELP_OPT ("-d", "Show a time delta to the last message") BAREBOX_CMD_HELP_OPT ("-e <msg>", "Emit a log message") -BAREBOX_CMD_HELP_OPT ("-l <vdebug|debug|info|notice|warn|err|crit|alert|emerg>", "Restrict output to the given (comma-separated) list of levels") +BAREBOX_CMD_HELP_OPT ("-l <loglevel>", "Restrict output to the given (comma-separated) list of levels") +BAREBOX_CMD_HELP_OPT ("-n <loglevel>", "Set level at which printing of messages is done to the console") BAREBOX_CMD_HELP_OPT ("-r", "Print timestamp and log-level prefixes.") BAREBOX_CMD_HELP_OPT ("-t", "Show timestamp informations") BAREBOX_CMD_HELP_END diff --git a/commands/drvinfo.c b/commands/drvinfo.c index 9f8f971ee9..e13b04870e 100644 --- a/commands/drvinfo.c +++ b/commands/drvinfo.c @@ -5,15 +5,21 @@ #include <common.h> #include <command.h> #include <driver.h> +#include <complete.h> +#include <fnmatch.h> static int do_drvinfo(int argc, char *argv[]) { - struct driver_d *drv; - struct device_d *dev; + char *pattern = argv[1]; + struct driver *drv; + struct device *dev; printf("Driver\tDevice(s)\n"); printf("--------------------\n"); for_each_driver(drv) { + if (pattern && fnmatch(pattern, drv->name, 0)) + continue; + printf("%s\n",drv->name); for_each_device(dev) { if (dev->driver == drv) @@ -31,5 +37,7 @@ static int do_drvinfo(int argc, char *argv[]) BAREBOX_CMD_START(drvinfo) .cmd = do_drvinfo, BAREBOX_CMD_DESC("list compiled-in device drivers") + BAREBOX_CMD_OPTS("[DRIVER]") BAREBOX_CMD_GROUP(CMD_GRP_INFO) + BAREBOX_CMD_COMPLETE(driver_complete) BAREBOX_CMD_END diff --git a/commands/edit.c b/commands/edit.c index 12695d39e4..dea383aae7 100644 --- a/commands/edit.c +++ b/commands/edit.c @@ -185,7 +185,7 @@ static int edit_read_file(const char *path) if (!stat(path, &s)) { filebuffer = read_file(path, NULL); if (!filebuffer) { - printf("could not read %s: %s\n", path, errno_str()); + printf("could not read %s: %m\n", path); return -1; } @@ -249,7 +249,7 @@ static int save_file(const char *path) fd = open(path, O_WRONLY | O_TRUNC | O_CREAT); if (fd < 0) { - printf("could not open file for writing: %s\n", errno_str()); + printf("could not open file for writing: %m\n"); return fd; } diff --git a/commands/efi_handle_dump.c b/commands/efi_handle_dump.c new file mode 100644 index 0000000000..a9db5eb75b --- /dev/null +++ b/commands/efi_handle_dump.c @@ -0,0 +1,144 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * efi-device.c - barebox EFI payload support + * + * Copyright (c) 2014 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix + */ + +#include <common.h> +#include <command.h> +#include <efi.h> +#include <linux/uuid.h> +#include <efi/efi-mode.h> +#include <efi/efi-device.h> + +static void efi_devpath(struct efi_boot_services *bs, + efi_handle_t handle, + const efi_guid_t *guid, + const char *desc) +{ + efi_status_t efiret; + void *devpath; + char *dev_path_str; + + efiret = bs->open_protocol(handle, guid, &devpath, NULL, NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (EFI_ERROR(efiret)) + return; + + dev_path_str = device_path_to_str(devpath); + if (dev_path_str) { + printf(" %s: \n %s\n", desc, dev_path_str); + free(dev_path_str); + } +} + +static void efi_dump(struct efi_boot_services *bs, efi_handle_t *handles, unsigned long handle_count) +{ + int i, j; + unsigned long num_guids; + efi_guid_t **guids; + + if (!handles || !handle_count) + return; + + for (i = 0; i < handle_count; i++) { + printf("handle-%p\n", handles[i]); + + bs->protocols_per_handle(handles[i], &guids, &num_guids); + printf(" Protocols:\n"); + for (j = 0; j < num_guids; j++) + printf(" %d: %pUl: %s\n", j, guids[j], + efi_guid_string(guids[j])); + + efi_devpath(bs, handles[i], &efi_device_path_protocol_guid, + "Devpath"); + efi_devpath(bs, handles[i], &efi_loaded_image_device_path_guid, + "Image Devpath"); + } + printf("\n"); +} + +static int do_efi_protocol_dump(struct efi_boot_services *bs, int argc, char **argv) +{ + unsigned long handle_count = 0; + efi_handle_t *handles = NULL; + int ret; + efi_guid_t guid; + + /* Format 220e73b6-6bdb-4413-8405-b974b108619a */ + if (argc == 1) { + ret = guid_parse(argv[0], &guid); + } else if (argc == 11) { + u32 a; + u16 b, c; + u8 d0, d1, d2, d3, d4, d5, d6, d7; + /* Format : + * 220e73b6 6bdb 4413 84 05 b9 74 b1 08 61 9a + * or + * 0x220e73b6 0x6bdb 0x14413 0x84 0x05 0xb9 0x74 0xb1 0x08 0x61 0x9a + */ + ret = kstrtou32(argv[0], 16, &a); + ret = ret ?: kstrtou16(argv[1], 16, &b); + ret = ret ?: kstrtou16(argv[2], 16, &c); + ret = ret ?: kstrtou8(argv[3], 16, &d0); + ret = ret ?: kstrtou8(argv[4], 16, &d1); + ret = ret ?: kstrtou8(argv[5], 16, &d2); + ret = ret ?: kstrtou8(argv[6], 16, &d3); + ret = ret ?: kstrtou8(argv[7], 16, &d4); + ret = ret ?: kstrtou8(argv[8], 16, &d5); + ret = ret ?: kstrtou8(argv[9], 16, &d6); + ret = ret ?: kstrtou8(argv[10], 16, &d7); + if (!ret) + guid = EFI_GUID(a, b, c, d0, d1, d2, d3, d4, d5, d6, d7); + } else { + ret = -EINVAL; + } + + if (ret) + return ret; + + printf("Searching for:\n"); + printf(" %pUl: %s\n", &guid, efi_guid_string(&guid)); + + ret = __efi_locate_handle(bs, BY_PROTOCOL, &guid, NULL, &handle_count, &handles); + if (!ret) + efi_dump(bs, handles, handle_count); + + return 0; +} + +static int do_efi_handle_dump(int argc, char *argv[]) +{ + unsigned long handle_count = 0; + efi_handle_t *handles = NULL; + struct efi_boot_services *bs; + int ret; + + bs = efi_get_boot_services(); + if (!bs) { + printf("EFI not yet initialized\n"); + return COMMAND_ERROR; + } + + if (argc > 1) + return do_efi_protocol_dump(bs, --argc, ++argv); + + ret = __efi_locate_handle(bs, ALL_HANDLES, NULL, NULL, &handle_count, &handles); + if (!ret) + efi_dump(bs, handles, handle_count); + + return 0; +} + +BAREBOX_CMD_HELP_START(efi_handle_dump) +BAREBOX_CMD_HELP_TEXT("Dump all the efi handle with protocol and devpath\n") +BAREBOX_CMD_HELP_END + +BAREBOX_CMD_START(efi_handle_dump) + .cmd = do_efi_handle_dump, + BAREBOX_CMD_DESC("Usage: efi_handle_dump") + BAREBOX_CMD_OPTS("[a-b-c-d0d1-d3d4d5d6d7] or [a b c d0 d1 d2 d3 d4 d5 d6 d7]") + BAREBOX_CMD_GROUP(CMD_GRP_MISC) + BAREBOX_CMD_HELP(cmd_efi_handle_dump_help) +BAREBOX_CMD_END diff --git a/commands/ethlog.c b/commands/ethlog.c index 0cc93ba808..21d88bf1cb 100644 --- a/commands/ethlog.c +++ b/commands/ethlog.c @@ -29,11 +29,14 @@ static int do_ethlog(int argc, char *argv[]) { struct eth_device *edev; const char *edevname; - bool remove = false; - int opt; + bool remove = false, promisc = false; + int opt, ret; - while ((opt = getopt(argc, argv, "r")) > 0) { + while ((opt = getopt(argc, argv, "pr")) > 0) { switch (opt) { + case 'p': + promisc = true; + break; case 'r': remove = true; break; @@ -56,10 +59,19 @@ static int do_ethlog(int argc, char *argv[]) if (remove) { edev->tx_monitor = NULL; edev->rx_monitor = NULL; + if (promisc) + eth_set_promisc(edev, false); return 0; } + if (promisc) { + ret = eth_set_promisc(edev, true); + if (ret) + dev_warn(&edev->dev, "Failed to set promisc mode: %pe\n", + ERR_PTR(ret)); + } + edev->tx_monitor = ethlog_tx_monitor; edev->rx_monitor = ethlog_rx_monitor; @@ -69,12 +81,14 @@ static int do_ethlog(int argc, char *argv[]) BAREBOX_CMD_HELP_START(ethlog) BAREBOX_CMD_HELP_TEXT("Options:") BAREBOX_CMD_HELP_OPT("-r", "remove log handler from Ethernet interface") +BAREBOX_CMD_HELP_OPT("-p", "Enable promisc mode, or disable if -r is used") BAREBOX_CMD_HELP_END BAREBOX_CMD_START(ethlog) .cmd = do_ethlog, BAREBOX_CMD_DESC("ETHLOG - tool to get dump of Ethernet packets") - BAREBOX_CMD_OPTS("[-r] [device]") + BAREBOX_CMD_OPTS("[-rp] [device]") BAREBOX_CMD_GROUP(CMD_GRP_NET) BAREBOX_CMD_COMPLETE(eth_complete) + BAREBOX_CMD_HELP(cmd_ethlog_help) BAREBOX_CMD_END diff --git a/commands/filetype.c b/commands/filetype.c index 818c14fe79..7a556a980d 100644 --- a/commands/filetype.c +++ b/commands/filetype.c @@ -66,7 +66,11 @@ static int do_filetype(int argc, char *argv[]) if (S_ISDIR(s.st_mode)) return -EISDIR; - type = file_name_detect_type(filename); + ret = file_name_detect_type(filename, &type); + if (ret) { + printf("failed to detect type of %s: %s\n", filename, strerror(-ret)); + return COMMAND_ERROR; + } if (verbose) printf("%s: %s (%s)\n", filename, diff --git a/commands/findmnt.c b/commands/findmnt.c new file mode 100644 index 0000000000..da8f58835f --- /dev/null +++ b/commands/findmnt.c @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: © 2022 Ahmad Fatoum, Pengutronix + +#include <common.h> +#include <command.h> +#include <fs.h> +#include <errno.h> +#include <getopt.h> + +static void print_header(bool *header_printed) +{ + if (*header_printed) + return; + printf("%-20s%-25s%-10s%-20s\n", "TARGET", "SOURCE", "FSTYPE", "OPTIONS"); + *header_printed = true; +} + +static void report_findmnt(const struct fs_device *fsdev) +{ + const char *backingstore; + + backingstore = fsdev->backingstore ?: cdev_name(fsdev->cdev) ?: "none"; + + printf("%-20s%-25s%-10s%-20s\n", fsdev->path, backingstore, + fsdev->driver->drv.name, fsdev->options); +} + +static int do_findmnt(int argc, char *argv[]) +{ + bool header_printed = false; + struct fs_device *target = NULL; + char *device = NULL; + int opt, dirfd = AT_FDCWD; + + while ((opt = getopt(argc, argv, "T:")) > 0) { + switch(opt) { + case 'T': + target = get_fsdevice_by_path(dirfd, optarg); + if (!target) + return COMMAND_ERROR; + break; + default: + return COMMAND_ERROR_USAGE; + } + } + + argv += optind; + argc -= optind; + + if ((target && argc > 0) || (!target && argc > 1)) + return COMMAND_ERROR_USAGE; + + if (target) { + print_header(&header_printed); + report_findmnt(target); + return 0; + } + + if (argv[0]) { + device = canonicalize_path(dirfd, argv[0]); + if (!device) + return COMMAND_ERROR; + } + + for_each_fs_device(target) { + if (!device || streq_ptr(target->path, device) || + streq_ptr(target->backingstore, device)) { + print_header(&header_printed); + report_findmnt(target); + } else { + const char *backingstore; + struct cdev *cdev; + + cdev = cdev_by_name(devpath_to_name(device)); + if (!cdev) + continue; + + backingstore = target->backingstore; + backingstore += str_has_prefix(backingstore, "/dev/"); + + if (streq_ptr(backingstore, cdev->name)) { + print_header(&header_printed); + report_findmnt(target); + } + } + } + + free(device); + + return header_printed ? 0 : COMMAND_ERROR; +} + +BAREBOX_CMD_HELP_START(findmnt) +BAREBOX_CMD_HELP_TEXT("findmnt will list all mounted filesystems or search") +BAREBOX_CMD_HELP_TEXT("for a filesystem when given the mountpoint or the") +BAREBOX_CMD_HELP_TEXT("source device as an argument") +BAREBOX_CMD_HELP_TEXT("") +BAREBOX_CMD_HELP_TEXT("Options:") +BAREBOX_CMD_HELP_OPT ("-T", "mount target file path") +BAREBOX_CMD_HELP_END + +BAREBOX_CMD_START(findmnt) + .cmd = do_findmnt, + BAREBOX_CMD_DESC("find a file system") + BAREBOX_CMD_OPTS("[ DEVICE | -T FILE ]") + BAREBOX_CMD_GROUP(CMD_GRP_FILE) + BAREBOX_CMD_HELP(cmd_findmnt_help) +BAREBOX_CMD_END diff --git a/commands/flash.c b/commands/flash.c index 3d7c8fd577..5b7060aead 100644 --- a/commands/flash.c +++ b/commands/flash.c @@ -25,7 +25,7 @@ static int do_flerase(int argc, char *argv[]) filename = argv[1]; if (stat(filename, &s)) { - printf("stat %s: %s\n", filename, errno_str()); + printf("stat %s: %m\n", filename); return 1; } @@ -33,7 +33,7 @@ static int do_flerase(int argc, char *argv[]) fd = open(filename, O_WRONLY); if (fd < 0) { - printf("open %s: %s\n", filename, errno_str()); + printf("open %s: %m\n", filename); return 1; } @@ -89,7 +89,7 @@ static int do_protect(int argc, char *argv[]) prot = 0; if (stat(filename, &s)) { - printf("stat %s: %s\n", filename, errno_str()); + printf("stat %s: %m\n", filename); return 1; } @@ -97,7 +97,7 @@ static int do_protect(int argc, char *argv[]) fd = open(filename, O_WRONLY); if (fd < 0) { - printf("open %s: %s\n", filename, errno_str()); + printf("open %s: %m\n", filename); return 1; } diff --git a/commands/global.c b/commands/global.c index cf8e9a5b48..a8ff5ea18f 100644 --- a/commands/global.c +++ b/commands/global.c @@ -50,6 +50,7 @@ static int do_global(int argc, char *argv[]) BAREBOX_CMD_HELP_START(global) BAREBOX_CMD_HELP_TEXT("Add a new global variable named VAR, optionally set to VALUE.") +BAREBOX_CMD_HELP_TEXT("Without options, print all global and env (prefixed with *) variables.") BAREBOX_CMD_HELP_TEXT("") BAREBOX_CMD_HELP_TEXT("Options:") BAREBOX_CMD_HELP_OPT("-r", "Remove globalvars") @@ -58,7 +59,7 @@ BAREBOX_CMD_HELP_END BAREBOX_CMD_START(global) .cmd = do_global, BAREBOX_CMD_DESC("create or set global variables") - BAREBOX_CMD_OPTS("[-r] VAR[=VALUE] ...") + BAREBOX_CMD_OPTS("[-r] [VAR[=VALUE] ...]") BAREBOX_CMD_GROUP(CMD_GRP_ENV) BAREBOX_CMD_HELP(cmd_global_help) BAREBOX_CMD_COMPLETE(global_complete) diff --git a/commands/go.c b/commands/go.c index 0c0b4cb15e..3449a2181a 100644 --- a/commands/go.c +++ b/commands/go.c @@ -8,21 +8,44 @@ #include <complete.h> #include <fs.h> #include <fcntl.h> +#include <getopt.h> #include <linux/ctype.h> #include <errno.h> +#define INT_ARGS_MAX 4 + static int do_go(int argc, char *argv[]) { void *addr; int rcode = 1; int fd = -1; - int (*func)(int argc, char *argv[]); + void (*func)(ulong r0, ulong r1, ulong r2, ulong r3); + int opt; + ulong arg[INT_ARGS_MAX] = {}; + bool pass_argv = true; + + while ((opt = getopt(argc, argv, "+si")) > 0) { + switch (opt) { + case 's': + pass_argv = true; + break; + case 'i': + pass_argv = false; + break; + default: + return COMMAND_ERROR_USAGE; + } + } + + /* skip options */ + argv += optind; + argc -= optind; - if (argc < 2) + if (argc == 0 || (!pass_argv && argc - 1 > INT_ARGS_MAX)) return COMMAND_ERROR_USAGE; - if (!isdigit(*argv[1])) { - fd = open(argv[1], O_RDONLY); + if (!isdigit(*argv[0])) { + fd = open(argv[0], O_RDONLY); if (fd < 0) { perror("open"); goto out; @@ -34,7 +57,7 @@ static int do_go(int argc, char *argv[]) goto out; } } else - addr = (void *)simple_strtoul(argv[1], NULL, 16); + addr = (void *)simple_strtoul(argv[0], NULL, 16); printf("## Starting application at 0x%p ...\n", addr); @@ -42,9 +65,28 @@ static int do_go(int argc, char *argv[]) func = addr; + if (pass_argv) { + arg[0] = argc; + arg[1] = (ulong)argv; + } else { + int i; + + /* skip argv[0] */ + argc--; + argv++; + + for (i = 0; i < argc; i++) { + rcode = kstrtoul(argv[i], 0, &arg[i]); + if (rcode) { + printf("Can't parse \"%s\" as an integer value\n", argv[i]); + goto out; + } + } + } + shutdown_barebox(); - func(argc - 1, &argv[1]); + func(arg[0], arg[1], arg[2], arg[3]); /* * The application returned. Since we have shutdown barebox and @@ -64,12 +106,15 @@ BAREBOX_CMD_HELP_TEXT("Start application at ADDR passing ARG as arguments.") BAREBOX_CMD_HELP_TEXT("") BAREBOX_CMD_HELP_TEXT("If addr does not start with a digit it is interpreted as a filename") BAREBOX_CMD_HELP_TEXT("in which case the file is memmapped and executed") +BAREBOX_CMD_HELP_TEXT("Options:") +BAREBOX_CMD_HELP_OPT("-s", "pass all arguments as strings referenced by argc, argv arguments (default)") +BAREBOX_CMD_HELP_OPT("-i", "pass up to four integer arguments using default calling convention") BAREBOX_CMD_HELP_END BAREBOX_CMD_START(go) .cmd = do_go, BAREBOX_CMD_DESC("start application at address or file") - BAREBOX_CMD_OPTS("ADDR [ARG...]") + BAREBOX_CMD_OPTS("[-si] ADDR [ARG...]") BAREBOX_CMD_GROUP(CMD_GRP_BOOT) BAREBOX_CMD_HELP(cmd_go_help) BAREBOX_CMD_COMPLETE(command_var_complete) diff --git a/commands/gpio.c b/commands/gpio.c index 955b60e91b..caabb5adc0 100644 --- a/commands/gpio.c +++ b/commands/gpio.c @@ -4,27 +4,58 @@ #include <command.h> #include <errno.h> #include <gpio.h> +#include <getopt.h> static int get_gpio_and_value(int argc, char *argv[], int *gpio, int *value) { - const int count = value ? 3 : 2; + struct gpio_chip *chip = NULL; + struct device *dev; + int count = 1; int ret = 0; + int opt; + + while ((opt = getopt(argc, argv, "d:")) > 0) { + switch (opt) { + case 'd': + dev = find_device(optarg); + if (!dev) + return -ENODEV; + + chip = gpio_get_chip_by_dev(dev); + if (!chip) + return -EINVAL; + break; + default: + return COMMAND_ERROR_USAGE; + } + } + + if (value) + count++; - if (argc < count) + if (argc < optind + count) return COMMAND_ERROR_USAGE; - *gpio = gpio_find_by_name(argv[1]); + *gpio = gpio_find_by_name(argv[optind]); if (*gpio < 0) - *gpio = gpio_find_by_label(argv[1]); + *gpio = gpio_find_by_label(argv[optind]); if (*gpio < 0) { - ret = kstrtoint(argv[1], 0, gpio); + ret = kstrtoint(argv[optind], 0, gpio); if (ret < 0) return ret; + + if (chip) + *gpio += chip->base; + } else if (chip) { + if (gpio_get_chip(*gpio) != chip) { + printf("%s: not exporting pin %u\n", dev_name(chip->dev), *gpio); + return -EINVAL; + } } if (value) - ret = kstrtoint(argv[2], 0, value); + ret = kstrtoint(argv[optind + 1], 0, value); return ret; } @@ -47,7 +78,7 @@ static int do_gpio_get_value(int argc, char *argv[]) BAREBOX_CMD_START(gpio_get_value) .cmd = do_gpio_get_value, BAREBOX_CMD_DESC("return value of a GPIO pin") - BAREBOX_CMD_OPTS("GPIO") + BAREBOX_CMD_OPTS("[-d CONTROLLER] GPIO") BAREBOX_CMD_GROUP(CMD_GRP_HWMANIP) BAREBOX_CMD_END @@ -67,7 +98,7 @@ static int do_gpio_set_value(int argc, char *argv[]) BAREBOX_CMD_START(gpio_set_value) .cmd = do_gpio_set_value, BAREBOX_CMD_DESC("set a GPIO's output value") - BAREBOX_CMD_OPTS("GPIO VALUE") + BAREBOX_CMD_OPTS("[-d CONTROLLER] GPIO VALUE") BAREBOX_CMD_GROUP(CMD_GRP_HWMANIP) BAREBOX_CMD_END @@ -89,7 +120,7 @@ static int do_gpio_direction_input(int argc, char *argv[]) BAREBOX_CMD_START(gpio_direction_input) .cmd = do_gpio_direction_input, BAREBOX_CMD_DESC("set direction of a GPIO pin to input") - BAREBOX_CMD_OPTS("GPIO") + BAREBOX_CMD_OPTS("[-d CONTROLLER] GPIO") BAREBOX_CMD_GROUP(CMD_GRP_HWMANIP) BAREBOX_CMD_END @@ -111,6 +142,6 @@ static int do_gpio_direction_output(int argc, char *argv[]) BAREBOX_CMD_START(gpio_direction_output) .cmd = do_gpio_direction_output, BAREBOX_CMD_DESC("set direction of a GPIO pin to output") - BAREBOX_CMD_OPTS("GPIO VALUE") + BAREBOX_CMD_OPTS("[-d CONTROLLER] GPIO VALUE") BAREBOX_CMD_GROUP(CMD_GRP_HWMANIP) BAREBOX_CMD_END diff --git a/commands/hab.c b/commands/hab.c index 97a1701fa5..8ae943a4c8 100644 --- a/commands/hab.c +++ b/commands/hab.c @@ -58,7 +58,13 @@ static int do_hab(int argc, char *argv[]) printf("%02x", srk[i]); printf("\n"); - if (imx_hab_device_locked_down()) + ret = imx_hab_device_locked_down(); + if (ret < 0) { + printf("failed to determine lockdown mode: '%pe'\n", ERR_PTR(ret)); + return ret; + } + + if (ret) printf("secure mode\n"); else printf("devel mode\n"); diff --git a/commands/i2c.c b/commands/i2c.c index 997d49a949..3a708531ee 100644 --- a/commands/i2c.c +++ b/commands/i2c.c @@ -195,7 +195,7 @@ static int do_i2c_read(int argc, char *argv[]) struct i2c_adapter *adapter = NULL; struct i2c_client client; u8 *buf; - int count = -1, addr = -1, reg = -1, verbose = 0, ret, opt, bus = 0, wide = 0; + int count = 1, addr = -1, reg = -1, verbose = 0, ret, opt, bus = 0, wide = 0; while ((opt = getopt(argc, argv, "a:b:c:r:vw")) > 0) { switch (opt) { @@ -264,7 +264,7 @@ BAREBOX_CMD_HELP_OPT("-b BUS\t", "i2c bus number (default 0)") BAREBOX_CMD_HELP_OPT("-a ADDR\t", "i2c device address") BAREBOX_CMD_HELP_OPT("-r START", "start register (optional, master receive mode if none given)") BAREBOX_CMD_HELP_OPT("-w\t", "use word (16 bit) wide access") -BAREBOX_CMD_HELP_OPT("-c COUNT", "byte count") +BAREBOX_CMD_HELP_OPT("-c COUNT", "byte count (default 1)") BAREBOX_CMD_HELP_OPT("-v\t", "verbose") BAREBOX_CMD_HELP_END diff --git a/commands/iomemport.c b/commands/iomemport.c index d0cfc413c2..f2baa0e293 100644 --- a/commands/iomemport.c +++ b/commands/iomemport.c @@ -16,11 +16,14 @@ static void __print_resources(struct resource *res, int indent) for (i = 0; i < indent; i++) printf(" "); - printf("%pa - %pa (size %pa) %s\n", - &res->start, &res->end, &size, res->name); + printf("%pa - %pa (size %pa) %s%s\n", + &res->start, &res->end, &size, + res->flags & IORESOURCE_BUSY ? "[R] " : "", + res->name); - list_for_each_entry(r, &res->children, sibling) + list_for_each_entry(r, &res->children, sibling) { __print_resources(r, indent + 1); + } } static void print_resources(struct resource *res) diff --git a/commands/kallsyms.c b/commands/kallsyms.c new file mode 100644 index 0000000000..163cd99c10 --- /dev/null +++ b/commands/kallsyms.c @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: GPL-2.0-only + +/* + * kallsyms.c - translate address to symbols + */ + +#include <common.h> +#include <kallsyms.h> +#include <command.h> +#include <malloc.h> +#include <complete.h> +#include <getopt.h> +#include <string.h> + +static int do_kallsyms(int argc, char *argv[]) +{ + unsigned long addr; + + if (argc != 2) + return COMMAND_ERROR_USAGE; + + if (kstrtoul(argv[1], 16, &addr) == 0) { + char sym[KSYM_SYMBOL_LEN]; + + sprint_symbol(sym, addr); + + printf("%s\n", sym); + return 0; + } + + if ((addr = kallsyms_lookup_name(argv[1]))) { + printf("0x%08lx\n", addr); + return 0; + } + + return COMMAND_ERROR; +} + +BAREBOX_CMD_HELP_START(kallsyms) +BAREBOX_CMD_HELP_TEXT("Lookup address or symbol using kallsyms table") +BAREBOX_CMD_HELP_END + +BAREBOX_CMD_START(kallsyms) + .cmd = do_kallsyms, + BAREBOX_CMD_DESC("query kallsyms table") + BAREBOX_CMD_OPTS("[SYMBOL | ADDRESS]") + BAREBOX_CMD_GROUP(CMD_GRP_MISC) + BAREBOX_CMD_COMPLETE(empty_complete) + BAREBOX_CMD_HELP(cmd_kallsyms_help) +BAREBOX_CMD_END diff --git a/commands/keystore.c b/commands/keystore.c index 4922cf1beb..40bcb7105d 100644 --- a/commands/keystore.c +++ b/commands/keystore.c @@ -17,7 +17,7 @@ static int do_keystore(int argc, char *argv[]) const char *file = NULL; char *secret_str = NULL; void *secret; - size_t s_len; + size_t s_len = 0; while ((opt = getopt(argc, argv, "rs:f:")) > 0) { switch (opt) { diff --git a/commands/loadb.c b/commands/loadb.c index 7ab989f459..140d3743f6 100644 --- a/commands/loadb.c +++ b/commands/loadb.c @@ -646,7 +646,7 @@ static int do_load_serial_bin(int argc, char *argv[]) /* File should exist */ ofd = open_and_lseek(output_file, O_WRONLY | O_CREAT, offset); if (ofd < 0) { - perror(argv[0]); + printf("Could not open \"%s\": %m\n", output_file); return 3; } diff --git a/commands/loadenv.c b/commands/loadenv.c index 279ee52da5..ddbf66b764 100644 --- a/commands/loadenv.c +++ b/commands/loadenv.c @@ -18,7 +18,8 @@ static int do_loadenv(int argc, char *argv[]) { - char *filename = NULL, *dirname; + const char *filename = NULL; + char *dirname; unsigned flags = 0; int opt, ret; int scrub = 0; diff --git a/commands/loadxy.c b/commands/loadxy.c index 66daa117d9..e2d1a11a2c 100644 --- a/commands/loadxy.c +++ b/commands/loadxy.c @@ -165,7 +165,7 @@ static int do_loadx(int argc, char *argv[]) /* File should exist */ ofd = open_and_lseek(output_file, O_WRONLY | O_CREAT, offset); if (ofd < 0) { - perror(argv[0]); + printf("Could not open \"%s\": %m\n", output_file); return 3; } diff --git a/commands/ls.c b/commands/ls.c index 1192aed971..09a20e0a23 100644 --- a/commands/ls.c +++ b/commands/ls.c @@ -164,8 +164,7 @@ static int do_ls(int argc, char *argv[]) while (o < argc) { ret = stat(argv[o], &s); if (ret) { - printf("%s: %s: %s\n", argv[0], - argv[o], errno_str()); + printf("%s: %s: %m\n", argv[0], argv[o]); o++; exitcode = COMMAND_ERROR; continue; diff --git a/commands/md.c b/commands/md.c index 7a96634e27..f3758f571f 100644 --- a/commands/md.c +++ b/commands/md.c @@ -49,8 +49,10 @@ static int do_mem_md(int argc, char *argv[]) } fd = open_and_lseek(filename, mode | O_RDONLY, start); - if (fd < 0) + if (fd < 0) { + printf("Could not open \"%s\": %m\n", filename); return 1; + } map = memmap(fd, PROT_READ); if (map != MAP_FAILED) { diff --git a/commands/memset.c b/commands/memset.c index e4412533f1..1139691f2f 100644 --- a/commands/memset.c +++ b/commands/memset.c @@ -41,8 +41,10 @@ static int do_memset(int argc, char *argv[]) n = strtoull_suffix(argv[optind + 2], NULL, 0); fd = open_and_lseek(file, mode | O_WRONLY | O_CREAT, s); - if (fd < 0) + if (fd < 0) { + printf("Could not open \"%s\": %m\n", file); return 1; + } buf = xmalloc(RW_BUF_SIZE); memset(buf, c, RW_BUF_SIZE); diff --git a/commands/memtest.c b/commands/memtest.c index 864947fa94..9fa148b3aa 100644 --- a/commands/memtest.c +++ b/commands/memtest.c @@ -15,6 +15,7 @@ static int do_test_one_area(struct mem_test_resource *r, int bus_only, unsigned cache_flag) { + unsigned flags = MEMTEST_VERBOSE; int ret; printf("Testing memory space: %pa -> %pa:\n", @@ -22,14 +23,14 @@ static int do_test_one_area(struct mem_test_resource *r, int bus_only, remap_range((void *)r->r->start, resource_size(r->r), cache_flag); - ret = mem_test_bus_integrity(r->r->start, r->r->end); + ret = mem_test_bus_integrity(r->r->start, r->r->end, flags); if (ret < 0) return ret; if (bus_only) return 0; - ret = mem_test_moving_inversions(r->r->start, r->r->end); + ret = mem_test_moving_inversions(r->r->start, r->r->end, flags); if (ret < 0) return ret; printf("done.\n\n"); diff --git a/commands/menu.c b/commands/menu.c index 7a01aff280..e0fe09b508 100644 --- a/commands/menu.c +++ b/commands/menu.c @@ -406,64 +406,65 @@ end: return 1; } -static const __maybe_unused char cmd_menu_help[] = -"Manage Menu:\n" -" -m menu\n" -" -l list\n" -" -s show\n" +BAREBOX_CMD_HELP_START(menu) +BAREBOX_CMD_HELP_TEXT("Manage Menu:") +BAREBOX_CMD_HELP_OPT ("-m", "menu") +BAREBOX_CMD_HELP_OPT ("-l", "list") +BAREBOX_CMD_HELP_OPT ("-s", "show") +BAREBOX_CMD_HELP_TEXT("") #if defined(CONFIG_CMD_MENU_MANAGEMENT) -"Advanced menu management:\n" -" -e menu entry\n" -" -a add\n" -" -r remove\n" -" -S select\n" +BAREBOX_CMD_HELP_TEXT("Advanced menu management:") +BAREBOX_CMD_HELP_OPT ("-e", "menu entry") +BAREBOX_CMD_HELP_OPT ("-a", "add") +BAREBOX_CMD_HELP_OPT ("-r", "remove") +BAREBOX_CMD_HELP_OPT ("-S", "select") +BAREBOX_CMD_HELP_TEXT("") #endif -"\n" -"Show menu:\n" -" (-A auto select delay)\n" -" (-d auto select description)\n" -" menu -s -m MENU [-A delay] [-d auto_display]\n" -"\n" -"List menu:\n" -" menu -l\n" -"\n" +BAREBOX_CMD_HELP_TEXT("Show menu:") +BAREBOX_CMD_HELP_OPT ("-A", "auto select delay") +BAREBOX_CMD_HELP_OPT ("-d", "auto select description") +BAREBOX_CMD_HELP_TEXT("\tmenu -s -m MENU [-A delay] [-d auto_display]") +BAREBOX_CMD_HELP_TEXT("") +BAREBOX_CMD_HELP_TEXT("List menu:") +BAREBOX_CMD_HELP_TEXT("\tmenu -l\n") +BAREBOX_CMD_HELP_TEXT("") #if defined(CONFIG_CMD_MENU_MANAGEMENT) -"Add a menu:\n" -" menu -a -m NAME -d DESC\n" -"\n" -"Remove a menu:\n" -" menu -r -m NAME\n" -"\n" -"Add an entry:\n" -" (-R for do no exit the menu after executing the command)\n" -" (-b for box style 1 for selected)\n" -" (and optional -c for the command to run when we change the state)\n" -" menu -e -a -m MENU -c COMMAND [-R] [-b 0|1] -d DESC\n" - -"Add a submenu entry:\n" -" (-R is not needed)\n" -" (-b for box style 1 for selected)\n" -" (and -c is not needed)\n" -" menu -e -a -m MENU -u submenu -d [-b 0|1] DESC\n" -"\n" -"Remove an entry:\n" -" menu -e -r -m NAME -n ENTRY\n" -"\n" -"Select an entry:\n" -" menu -m <menu> -S -n ENTRY\n" -"\n" -"List menu:\n" -" menu -e -l [menu]\n" -"\n" -"Menu examples:\n" -" menu -a -m boot -d \"Boot Menu\"\n" -" menu -e -a -m boot -c boot -d \"Boot\"\n" -" menu -e -a -m boot -c reset -d \"Reset\"\n" +BAREBOX_CMD_HELP_TEXT("Add a menu:") +BAREBOX_CMD_HELP_TEXT("\tmenu -a -m NAME -d DESC") +BAREBOX_CMD_HELP_TEXT("") +BAREBOX_CMD_HELP_TEXT("Remove a menu:") +BAREBOX_CMD_HELP_TEXT("\tmenu -r -m NAME") +BAREBOX_CMD_HELP_TEXT("") +BAREBOX_CMD_HELP_TEXT("Add an entry:") +BAREBOX_CMD_HELP_TEXT("\t(-R for do no exit the menu after executing the command)") +BAREBOX_CMD_HELP_TEXT("\t(-b for box style 1 for selected)") +BAREBOX_CMD_HELP_TEXT("\t(and optional -c for the command to run when we change the state)") +BAREBOX_CMD_HELP_TEXT("\tmenu -e -a -m MENU -c COMMAND [-R] [-b 0|1] -d DESC") +BAREBOX_CMD_HELP_TEXT("") +BAREBOX_CMD_HELP_TEXT("Add a submenu entry:") +BAREBOX_CMD_HELP_TEXT("\t(-R is not needed)") +BAREBOX_CMD_HELP_TEXT("\t(-b for box style 1 for selected)") +BAREBOX_CMD_HELP_TEXT("\t(and -c is not needed)") +BAREBOX_CMD_HELP_TEXT("\tmenu -e -a -m MENU -u submenu -d [-b 0|1] DESC") +BAREBOX_CMD_HELP_TEXT("") +BAREBOX_CMD_HELP_TEXT("Remove an entry:") +BAREBOX_CMD_HELP_TEXT("\tmenu -e -r -m NAME -n ENTRY") +BAREBOX_CMD_HELP_TEXT("") +BAREBOX_CMD_HELP_TEXT("Select an entry:") +BAREBOX_CMD_HELP_TEXT("\tmenu -m <menu> -S -n ENTRY") +BAREBOX_CMD_HELP_TEXT("") +BAREBOX_CMD_HELP_TEXT("List menu:") +BAREBOX_CMD_HELP_TEXT("\tmenu -e -l [menu]") +BAREBOX_CMD_HELP_TEXT("") +BAREBOX_CMD_HELP_TEXT("Menu examples:") +BAREBOX_CMD_HELP_TEXT("\tmenu -a -m boot -d \"Boot Menu\"") +BAREBOX_CMD_HELP_TEXT("\tmenu -e -a -m boot -c boot -d \"Boot\"") +BAREBOX_CMD_HELP_TEXT("\tmenu -e -a -m boot -c reset -d \"Reset\"") #else -"Menu example:\n" +BAREBOX_CMD_HELP_TEXT("Menu example:") #endif -" menu -s -m boot\n" -; +BAREBOX_CMD_HELP_TEXT("\tmenu -s -m boot") +BAREBOX_CMD_HELP_END BAREBOX_CMD_START(menu) .cmd = do_menu, diff --git a/commands/miitool.c b/commands/miitool.c index 47494f5089..24e383736a 100644 --- a/commands/miitool.c +++ b/commands/miitool.c @@ -217,7 +217,7 @@ static int show_basic_mii(struct mii_bus *mii, struct phy_device *phydev, return 0; } -static void mdiobus_show(struct device_d *dev, const char *phydevname, +static void mdiobus_show(struct device *dev, const char *phydevname, int verbose) { struct mii_bus *mii = to_mii_bus(dev); diff --git a/commands/mkdir.c b/commands/mkdir.c index e7153b8732..01fc0b083b 100644 --- a/commands/mkdir.c +++ b/commands/mkdir.c @@ -37,7 +37,7 @@ static int do_mkdir(int argc, char *argv[]) ret = mkdir(argv[optind], 0); } if (ret) { - printf("could not create %s: %s\n", argv[optind], errno_str()); + printf("could not create %s: %m\n", argv[optind]); return 1; } optind++; diff --git a/commands/mm.c b/commands/mm.c index 9ce8839644..8755a0f2c9 100644 --- a/commands/mm.c +++ b/commands/mm.c @@ -16,7 +16,7 @@ static int do_mem_mm(int argc, char *argv[]) { - int ret = 0; + int ret; int fd; char *filename = "/dev/mem"; int mode = O_RWSIZE_4; @@ -40,8 +40,10 @@ static int do_mem_mm(int argc, char *argv[]) mask = simple_strtoull(argv[optind++], NULL, 0); fd = open_and_lseek(filename, mode | O_RDWR | O_CREAT, adr); - if (fd < 0) + if (fd < 0) { + printf("Could not open \"%s\": %m\n", filename); return 1; + } switch (mode) { case O_RWSIZE_1: @@ -65,9 +67,9 @@ static int do_mem_mm(int argc, char *argv[]) goto out_write; break; case O_RWSIZE_4: + ret = pread(fd, &val32, 4, adr); if (ret < 0) goto out_read; - ret = pread(fd, &val32, 4, adr); val32 &= ~mask; val32 |= (value & mask); ret = pwrite(fd, &val32, 4, adr); @@ -75,9 +77,9 @@ static int do_mem_mm(int argc, char *argv[]) goto out_write; break; case O_RWSIZE_8: + ret = pread(fd, &val64, 8, adr); if (ret < 0) goto out_read; - ret = pread(fd, &val64, 8, adr); val64 &= ~mask; val64 |= (value & mask); ret = pwrite(fd, &val64, 8, adr); diff --git a/commands/mmc.c b/commands/mmc.c index 1e62b71850..041a721d36 100644 --- a/commands/mmc.c +++ b/commands/mmc.c @@ -5,6 +5,7 @@ #include <stdio.h> #include <string.h> #include <getopt.h> +#include <dma.h> static int mmc_enh_area_setmax(struct mci *mci, u8 *ext_csd) { @@ -65,23 +66,6 @@ static int mmc_partitioning_complete(struct mci *mci) return ret; } -static u8 *mci_get_ext_csd(struct mci *mci) -{ - u8 *ext_csd; - int ret; - - ext_csd = xmalloc(512); - - ret = mci_send_ext_csd(mci, ext_csd); - if (ret) { - printf("Failure to read EXT_CSD register\n"); - free(ext_csd); - return ERR_PTR(-EIO); - } - - return ext_csd; -} - /* enh_area [-c] /dev/mmcX */ static int do_mmc_enh_area(int argc, char *argv[]) { @@ -95,6 +79,7 @@ static int do_mmc_enh_area(int argc, char *argv[]) while ((opt = getopt(argc, argv, "c")) > 0) { switch (opt) { case 'c': + printf("Use -c to complete the partitioning is deprecated, use separate partition_complete command instead\n"); set_completed = 1; break; } @@ -131,7 +116,7 @@ static int do_mmc_enh_area(int argc, char *argv[]) if (ret) goto error; - free(ext_csd); + dma_free(ext_csd); if (set_completed) { ret = mmc_partitioning_complete(mci); @@ -143,10 +128,99 @@ static int do_mmc_enh_area(int argc, char *argv[]) return COMMAND_SUCCESS; error: - free(ext_csd); + dma_free(ext_csd); return COMMAND_ERROR; } +static int do_mmc_write_reliability(int argc, char *argv[]) +{ + const char *devpath; + struct mci *mci; + u8 *ext_csd; + + if (argc - optind != 1) { + printf("Usage: mmc write_reliability /dev/mmcX\n"); + return COMMAND_ERROR_USAGE; + } + + devpath = argv[optind]; + + mci = mci_get_device_by_devpath(devpath); + if (!mci) { + printf("Failure to open %s as mci device\n", devpath); + return COMMAND_ERROR; + } + + ext_csd = mci_get_ext_csd(mci); + if (IS_ERR(ext_csd)) + return COMMAND_ERROR; + + if (ext_csd[EXT_CSD_PARTITION_SETTING_COMPLETED]) { + printf("Partitioning already finalized\n"); + goto error; + } + + if (!(ext_csd[EXT_CSD_WR_REL_PARAM] & EXT_CSD_EN_REL_WR)) { + printf("Device doesn't support the enhanced definition of reliable write\n"); + goto error; + } + + if (!(ext_csd[EXT_CSD_WR_REL_PARAM] & EXT_CSD_HS_CTRL_REL)) { + printf("Device doesn't support WR_REL_SET writes\n"); + goto error; + } + + /* + * Host has one opportunity to write all of the bits. Separate writes to + * individual bits are not permitted so set all bits for now. + */ + if ((ext_csd[EXT_CSD_WR_REL_SET] & 0x1f) != 0x1f) { + int ret; + + ret = mci_switch(mci, EXT_CSD_WR_REL_SET, 0x1f); + if (ret) { + printf("Failure to write to EXT_CSD_WR_REL_SET\n"); + goto error; + } + } + + dma_free(ext_csd); + + return COMMAND_SUCCESS; + +error: + dma_free(ext_csd); + return COMMAND_ERROR; +} + +static int do_mmc_partition_complete(int argc, char *argv[]) +{ + const char *devpath; + struct mci *mci; + int ret; + + if (argc - optind != 1) { + printf("Usage: mmc partition_complete /dev/mmcX\n"); + return COMMAND_ERROR_USAGE; + } + + devpath = argv[optind]; + + mci = mci_get_device_by_devpath(devpath); + if (!mci) { + printf("Failure to open %s as mci device\n", devpath); + return COMMAND_ERROR_USAGE; + } + + ret = mmc_partitioning_complete(mci); + if (ret) + return COMMAND_ERROR; + + printf("Now power cycle the device to let it reconfigure itself.\n"); + + return COMMAND_SUCCESS; +} + static struct { const char *cmd; int (*func)(int argc, char *argv[]); @@ -154,6 +228,12 @@ static struct { { .cmd = "enh_area", .func = do_mmc_enh_area, + }, { + .cmd = "write_reliability", + .func = do_mmc_write_reliability, + }, { + .cmd = "partition_complete", + .func = do_mmc_partition_complete, } }; @@ -188,12 +268,16 @@ BAREBOX_CMD_HELP_TEXT("") BAREBOX_CMD_HELP_TEXT("The subcommand enh_area creates an enhanced area of") BAREBOX_CMD_HELP_TEXT("maximal size.") BAREBOX_CMD_HELP_TEXT("Note, with -c this is an irreversible action.") -BAREBOX_CMD_HELP_OPT("-c", "complete partitioning") +BAREBOX_CMD_HELP_OPT("-c", "complete partitioning (deprecated)") +BAREBOX_CMD_HELP_TEXT("") +BAREBOX_CMD_HELP_TEXT("The subcommand write_reliability enable write reliability") +BAREBOX_CMD_HELP_TEXT("") +BAREBOX_CMD_HELP_TEXT("The subcommand partition_complete set PARTITION_SETTING_COMPLETED (irreversible action)") BAREBOX_CMD_HELP_END BAREBOX_CMD_START(mmc) .cmd = do_mmc, - BAREBOX_CMD_OPTS("enh_area [-c] /dev/mmcX") + BAREBOX_CMD_OPTS("partition_complete|write_reliability|enh_area [-c] /dev/mmcX") BAREBOX_CMD_GROUP(CMD_GRP_HWMANIP) BAREBOX_CMD_HELP(cmd_mmc_help) BAREBOX_CMD_END diff --git a/commands/mmc_extcsd.c b/commands/mmc_extcsd.c index 7ae068348d..f67c48404a 100644 --- a/commands/mmc_extcsd.c +++ b/commands/mmc_extcsd.c @@ -1427,7 +1427,7 @@ static int print_field(u8 *reg, int index) case EXT_CSD_MAX_ENH_SIZE_MULT: tmp = get_field_val(EXT_CSD_HC_WP_GRP_SIZE, 0, 0xFF); - tmp = tmp + get_field_val(EXT_CSD_HC_ERASE_GRP_SIZE, 0, 0xFF); + tmp = tmp * get_field_val(EXT_CSD_HC_ERASE_GRP_SIZE, 0, 0xFF); tmp64 *= tmp; tmp64 *= SZ_512K; printf("\tMax Enhanced Area: %llu B\n", tmp64); diff --git a/commands/mount.c b/commands/mount.c index ff1d8bc5e5..fddd770dc9 100644 --- a/commands/mount.c +++ b/commands/mount.c @@ -13,7 +13,7 @@ static int do_mount(int argc, char *argv[]) { int opt, verbose = 0; - struct driver_d *drv; + struct driver *drv; const char *type = NULL; const char *mountpoint, *devstr; const char *fsoptions = NULL; @@ -36,7 +36,7 @@ static int do_mount(int argc, char *argv[]) } if (argc == optind) { - struct fs_device_d *fsdev; + struct fs_device *fsdev; for_each_fs_device(fsdev) { printf("%s on %s type %s\n", @@ -48,7 +48,7 @@ static int do_mount(int argc, char *argv[]) if (verbose) { printf("\nSupported filesystems:\n\n"); bus_for_each_driver(&fs_bus, drv) { - struct fs_driver_d * fsdrv = drv_to_fs_driver(drv); + struct fs_driver * fsdrv = drv_to_fs_driver(drv); printf("%s\n", fsdrv->drv.name); } } diff --git a/commands/mw.c b/commands/mw.c index 5dcef7e2fc..915f549216 100644 --- a/commands/mw.c +++ b/commands/mw.c @@ -39,8 +39,10 @@ static int do_mem_mw(int argc, char *argv[]) adr = strtoull_suffix(argv[optind++], NULL, 0); fd = open_and_lseek(filename, mode | O_WRONLY | O_CREAT, adr); - if (fd < 0) + if (fd < 0) { + printf("Could not open \"%s\": %m\n", filename); return 1; + } while (optind < argc) { u8 val8; diff --git a/commands/nand.c b/commands/nand.c index 67e43eba30..d07444aee0 100644 --- a/commands/nand.c +++ b/commands/nand.c @@ -165,7 +165,7 @@ BAREBOX_CMD_HELP_END BAREBOX_CMD_START(nand) .cmd = do_nand, BAREBOX_CMD_DESC("NAND flash handling") - BAREBOX_CMD_OPTS("[-adb] NANDDEV") + BAREBOX_CMD_OPTS("[-adbgi] NANDDEV") BAREBOX_CMD_GROUP(CMD_GRP_HWMANIP) BAREBOX_CMD_HELP(cmd_nand_help) BAREBOX_CMD_END diff --git a/commands/of_compatible.c b/commands/of_compatible.c new file mode 100644 index 0000000000..d8704d50bb --- /dev/null +++ b/commands/of_compatible.c @@ -0,0 +1,121 @@ +// SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: © 2023 Ahmad Fatoum <a.fatoum@pengutronix.de> + +#include <common.h> +#include <libfile.h> +#include <fdt.h> +#include <of.h> +#include <command.h> +#include <complete.h> +#include <errno.h> +#include <getopt.h> + +static int do_of_compatible(int argc, char *argv[]) +{ + int opt; + int ret = 0; + bool fix = false, kernel_compat = false; + struct device_node *root = NULL, *node, *of_free = NULL; + char **compats, **compat, *dtbfile = NULL; + const char *nodename = "/"; + + while ((opt = getopt(argc, argv, "f:n:Fk")) > 0) { + switch (opt) { + case 'f': + dtbfile = optarg; + break; + case 'n': + nodename = optarg; + break; + case 'F': + fix = true; + break; + case 'k': + kernel_compat = true; + break; + default: + return COMMAND_ERROR_USAGE; + } + } + + if (argc - optind < 1) + return COMMAND_ERROR_USAGE; + + compats = &argv[optind]; + + if (dtbfile) { + root = of_read_file(dtbfile); + if (IS_ERR(root)) + return PTR_ERR(root); + + of_free = root; + } else { + root = of_get_root_node(); + + /* copy internal device tree to apply fixups onto it */ + if (fix) + root = of_free = of_dup(root); + } + + if (fix) + of_fix_tree(root); + + node = of_find_node_by_path_or_alias(root, nodename); + if (!node) { + printf("Cannot find nodepath %s\n", nodename); + ret = -ENOENT; + goto out; + } + + ret = COMMAND_ERROR; + + if (kernel_compat) { + const char *compat_override; + + if (node->parent) { + printf("-k only valid for root node\n"); + ret = COMMAND_ERROR_USAGE; + goto out; + } + + compat_override = barebox_get_of_machine_compatible() ?: ""; + for (compat = compats; *compat; compat++) { + if (strcmp(*compat, compat_override) == 0) { + ret = COMMAND_SUCCESS; + goto out; + } + } + } + + for (compat = compats; *compat; compat++) { + int score; + + score = of_device_is_compatible(node, *compat); + if (score > 0) { + ret = COMMAND_SUCCESS; + break; + } + } + +out: + of_delete_node(of_free); + + return ret; +} + +BAREBOX_CMD_HELP_START(of_compatible) +BAREBOX_CMD_HELP_TEXT("Options:") +BAREBOX_CMD_HELP_OPT ("-f dtb", "work on dtb instead of internal devicetree") +BAREBOX_CMD_HELP_OPT ("-F", "apply fixups on devicetree before compare") +BAREBOX_CMD_HELP_OPT ("-n node", "node path or alias to compare its compatible (default is /)") +BAREBOX_CMD_HELP_OPT ("-k", "compare $global.of.kernel.add_machine_compatible as well") +BAREBOX_CMD_HELP_END + +BAREBOX_CMD_START(of_compatible) + .cmd = do_of_compatible, + BAREBOX_CMD_DESC("Check DT node's compatible") + BAREBOX_CMD_OPTS("[-fFnk] [COMPATS..]") + BAREBOX_CMD_GROUP(CMD_GRP_MISC) + BAREBOX_CMD_COMPLETE(empty_complete) + BAREBOX_CMD_HELP(cmd_of_compatible_help) +BAREBOX_CMD_END diff --git a/commands/of_diff.c b/commands/of_diff.c index 6a78263200..623b033c73 100644 --- a/commands/of_diff.c +++ b/commands/of_diff.c @@ -16,72 +16,57 @@ static struct device_node *get_tree(const char *filename, struct device_node *root) { struct device_node *node; - void *fdt; - size_t size; - int ret; if (!strcmp(filename, "-")) { - node = of_get_root_node(); - if (!node) - return ERR_PTR(-ENOENT); - - return of_dup(node); + node = of_dup(root) ?: ERR_PTR(-ENOENT); + if (IS_ERR(node)) + printf("Cannot duplicate live tree: %pe\n", node); + } else if (!strcmp(filename, "+")) { + return NULL; + } else { + node = of_read_file(filename); } - if (!strcmp(filename, "+")) { - node = of_get_root_node(); - if (!node) - return ERR_PTR(-ENOENT); + return node; +} - node = of_dup(root); +static struct device_node *get_tree_fixed(const struct device_node *root) +{ + struct device_node *node; + node = of_dup(root); + if (!IS_ERR(node)) of_fix_tree(node); - return node; - } - - ret = read_file_2(filename, &size, &fdt, FILESIZE_MAX); - if (ret) - return ERR_PTR(ret); - - node = of_unflatten_dtb(fdt, size); - - free(fdt); - return node; } static int do_of_diff(int argc, char *argv[]) { - int ret = 0; + int ret = COMMAND_ERROR; struct device_node *a, *b, *root; - if (argc < 3) + if (argc != 3) return COMMAND_ERROR_USAGE; root = of_get_root_node(); a = get_tree(argv[1], root); b = get_tree(argv[2], root); - if (IS_ERR(a)) { - printf("Cannot read %s: %pe\n", argv[1], a); - ret = COMMAND_ERROR; - a = NULL; - goto out; - } + if (!a && !b) + return COMMAND_ERROR_USAGE; - if (IS_ERR(b)) { - printf("Cannot read %s: %pe\n", argv[2], b); - ret = COMMAND_ERROR; - b = NULL; - goto out; - } + if (!a) + a = get_tree_fixed(b); + if (!b) + b = get_tree_fixed(a); + + if (!IS_ERR(a) && !IS_ERR(b)) + ret = of_diff(a, b, 0) ? COMMAND_ERROR : COMMAND_SUCCESS; - ret = of_diff(a, b, 0) ? COMMAND_ERROR : COMMAND_SUCCESS; -out: - if (a && a != root) + if (!IS_ERR(a) && a != root) of_delete_node(a); - if (b && b != root) + if (!IS_ERR(b) && b != root) of_delete_node(b); return ret; @@ -91,7 +76,7 @@ BAREBOX_CMD_HELP_START(of_diff) BAREBOX_CMD_HELP_TEXT("This command prints a diff between two given device trees.") BAREBOX_CMD_HELP_TEXT("The device trees are given as dtb files or:") BAREBOX_CMD_HELP_TEXT("'-' to compare against the barebox live tree, or") -BAREBOX_CMD_HELP_TEXT("'+' to compare against the fixed barebox live tree") +BAREBOX_CMD_HELP_TEXT("'+' to compare against the other device tree after fixups") BAREBOX_CMD_HELP_END BAREBOX_CMD_START(of_diff) diff --git a/commands/of_display_timings.c b/commands/of_display_timings.c index aab57b17d6..232074fce7 100644 --- a/commands/of_display_timings.c +++ b/commands/of_display_timings.c @@ -67,29 +67,9 @@ static int do_of_display_timings(int argc, char *argv[]) /* Check if external dtb given */ if (dtbfile) { - void *fdt; - size_t size; - - fdt = read_file(dtbfile, &size); - if (!fdt) { - pr_err("unable to read %s: %s\n", dtbfile, - strerror(errno)); - return -errno; - } - - if (file_detect_type(fdt, size) != filetype_oftree) { - pr_err("%s is not a oftree file.\n", dtbfile); - free(fdt); - return -EINVAL; - } - - root = of_unflatten_dtb(fdt, size); - - free(fdt); - + root = of_read_file(dtbfile); if (IS_ERR(root)) return PTR_ERR(root); - } else { root = of_get_root_node(); } @@ -100,7 +80,7 @@ static int do_of_display_timings(int argc, char *argv[]) for_each_node_by_name_address_from(display, root, node) { for_each_child_of_node(display, timings) { - printf("%s\n", timings->full_name); + printf("%pOF\n", timings); found = 1; } } @@ -119,7 +99,7 @@ static int do_of_display_timings(int argc, char *argv[]) if (!timings) continue; - printf("%s\n", timings->full_name); + printf("%pOF\n", timings); found = 1; } diff --git a/commands/of_dump.c b/commands/of_dump.c index c2ca8485cd..2508d4ce11 100644 --- a/commands/of_dump.c +++ b/commands/of_dump.c @@ -21,7 +21,7 @@ static void of_print_nodenames(struct device_node *node) { struct device_node *n; - printf("%s\n", node->full_name); + printf("%pOF\n", node); list_for_each_entry(n, &node->children, parent_list) { if (ctrlc()) @@ -37,7 +37,6 @@ static int do_of_dump(int argc, char *argv[]) int fix = 0; struct device_node *root = NULL, *node, *of_free = NULL; char *dtbfile = NULL; - size_t size; const char *nodename; unsigned maxpropsize = ~0; int names_only = 0, properties_only = 0; @@ -72,49 +71,21 @@ static int do_of_dump(int argc, char *argv[]) nodename = argv[optind]; if (dtbfile) { - void *fdt; - - fdt = read_file(dtbfile, &size); - if (!fdt) { - printf("unable to read %s: %s\n", dtbfile, strerror(errno)); - return -errno; - } - - root = of_unflatten_dtb(fdt, size); - - free(fdt); - - if (IS_ERR(root)) { - ret = PTR_ERR(root); - goto out; - } + root = of_read_file(dtbfile); + if (IS_ERR(root)) + return PTR_ERR(root); of_free = root; } else { root = of_get_root_node(); - if (fix) { - /* create a copy of internal devicetree */ - void *fdt; - fdt = of_flatten_dtb(root); - root = of_unflatten_dtb(fdt, fdt_totalsize(fdt)); - - free(fdt); - - if (IS_ERR(root)) { - ret = PTR_ERR(root); - goto out; - } - - of_free = root; - } + /* copy internal device tree to apply fixups onto it */ + if (fix) + root = of_free = of_dup(root); } - if (fix) { - ret = of_fix_tree(root); - if (ret) - goto out; - } + if (fix) + of_fix_tree(root); node = of_find_node_by_path_or_alias(root, nodename); if (!node) { @@ -131,8 +102,7 @@ static int do_of_dump(int argc, char *argv[]) of_print_nodes(node, 0, maxpropsize); out: - if (of_free) - of_delete_node(of_free); + of_delete_node(of_free); return ret; } diff --git a/commands/of_fixup.c b/commands/of_fixup.c new file mode 100644 index 0000000000..d667afb5b1 --- /dev/null +++ b/commands/of_fixup.c @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0-only + +/* + * of_fixup.c - List and remove OF fixups + */ + +#include <common.h> +#include <kallsyms.h> +#include <of.h> +#include <command.h> +#include <malloc.h> +#include <complete.h> +#include <getopt.h> +#include <string.h> + +static int do_of_fixup(int argc, char *argv[]) +{ + struct of_fixup *of_fixup; + int opt, enable = -1; + bool did_fixup = false; + + while ((opt = getopt(argc, argv, "ed")) > 0) { + switch (opt) { + case 'e': + enable = 1; + break; + case 'd': + enable = 0; + break; + default: + return COMMAND_ERROR_USAGE; + } + } + + argv += optind; + argc -= optind; + + if ((enable < 0 && argc > 0) || (enable >= 0 && argc == 0)) + return COMMAND_ERROR_USAGE; + + list_for_each_entry(of_fixup, &of_fixup_list, list) { + int i; + ulong addr = (ulong)of_fixup->fixup; + char sym[KSYM_SYMBOL_LEN]; + const char *name; + + name = kallsyms_lookup(addr, NULL, NULL, NULL, sym); + if (!name) { + sprintf(sym, "<0x%lx>", addr); + name = sym; + } + + if (enable == -1) { + printf("%s(0x%p)%s\n", name, of_fixup->context, + of_fixup->disabled ? " [DISABLED]" : ""); + continue; + } + + for (i = 0; i < argc; i++) { + if (strcmp(name, argv[i]) != 0) + continue; + + of_fixup->disabled = !enable; + did_fixup = true; + } + } + + if (argc && !did_fixup) { + printf("none of the specified fixups found\n"); + return -EINVAL; + } + + return 0; +} + +BAREBOX_CMD_HELP_START(of_fixup) +BAREBOX_CMD_HELP_TEXT("Disable or re-enable an already registered fixup for the device tree.") +BAREBOX_CMD_HELP_TEXT("Call without arguments to list all fixups") +BAREBOX_CMD_HELP_TEXT("") +BAREBOX_CMD_HELP_TEXT("Options:") +BAREBOX_CMD_HELP_OPT("-d", "disable fixup") +BAREBOX_CMD_HELP_OPT("-e", "re-enable fixup") +BAREBOX_CMD_HELP_OPT("fixups", "List of fixups to enable or disable") +BAREBOX_CMD_HELP_END + +BAREBOX_CMD_START(of_fixup) + .cmd = do_of_fixup, + BAREBOX_CMD_DESC("list and enable/disable fixups") + BAREBOX_CMD_OPTS("[-de] [fixups...]") + BAREBOX_CMD_GROUP(CMD_GRP_MISC) + BAREBOX_CMD_COMPLETE(empty_complete) + BAREBOX_CMD_HELP(cmd_of_fixup_help) +BAREBOX_CMD_END diff --git a/commands/of_overlay.c b/commands/of_overlay.c index b3660b4bf1..2013c4b278 100644 --- a/commands/of_overlay.c +++ b/commands/of_overlay.c @@ -10,29 +10,46 @@ #include <getopt.h> #include <libfile.h> #include <of.h> +#include <linux/clk.h> static int do_of_overlay(int argc, char *argv[]) { int ret; - struct fdt_header *fdt; struct device_node *overlay; - size_t size; + bool live_tree = false; + int opt; - if (argc != 2) + while ((opt = getopt(argc, argv, "l")) > 0) { + switch (opt) { + case 'l': + live_tree = true; + break; + } + } + + if (argc != optind + 1) return COMMAND_ERROR_USAGE; - fdt = read_file(argv[optind], &size); - if (!fdt) { - printf("cannot read %s\n", argv[optind]); + if (live_tree && !IS_ENABLED(CONFIG_OF_OVERLAY_LIVE)) { + printf("Support for live tree overlays is disabled. Enable CONFIG_OF_OVERLAY_LIVE\n"); return 1; } - overlay = of_unflatten_dtb(fdt, size); - free(fdt); + overlay = of_read_file(argv[optind]); if (IS_ERR(overlay)) return PTR_ERR(overlay); - ret = of_register_overlay(overlay); + if (live_tree) { + ret = of_overlay_apply_tree(of_get_root_node(), overlay); + if (ret) + goto err; + + of_clk_init(); + of_probe(); + } else { + ret = of_register_overlay(overlay); + } + if (ret) { printf("cannot apply oftree overlay: %s\n", strerror(-ret)); goto err; @@ -45,9 +62,22 @@ err: return ret; } +BAREBOX_CMD_HELP_START(of_overlay) +BAREBOX_CMD_HELP_TEXT("Register a device tree overlay file (dtbo) with barebox.") +BAREBOX_CMD_HELP_TEXT("By default the overlay is registered as a fixup and the") +BAREBOX_CMD_HELP_TEXT("overlay will then be applied to the Linux device tree.") +BAREBOX_CMD_HELP_TEXT("With -l given the overlay is applied to the barebox live") +BAREBOX_CMD_HELP_TEXT("tree instead. This involves probing new devices added in") +BAREBOX_CMD_HELP_TEXT("the overlay file.") +BAREBOX_CMD_HELP_TEXT("") +BAREBOX_CMD_HELP_TEXT("Options:") +BAREBOX_CMD_HELP_OPT("-l", "apply to barebox live tree") +BAREBOX_CMD_HELP_END + BAREBOX_CMD_START(of_overlay) .cmd = do_of_overlay, - BAREBOX_CMD_DESC("register device tree overlay as fixup") - BAREBOX_CMD_OPTS("FILE") + BAREBOX_CMD_DESC("register device tree overlay") + BAREBOX_CMD_OPTS("[-l] FILE") BAREBOX_CMD_GROUP(CMD_GRP_MISC) + BAREBOX_CMD_HELP(cmd_of_overlay_help) BAREBOX_CMD_END diff --git a/commands/of_property.c b/commands/of_property.c index 063e97775c..0c914c55c6 100644 --- a/commands/of_property.c +++ b/commands/of_property.c @@ -305,7 +305,6 @@ static int do_of_property(int argc, char *argv[]) char *path, *propname; char *dtbfile = NULL; int ret = 0; - size_t size; struct fdt_header *fdt = NULL; struct device_node *root = NULL; @@ -340,15 +339,9 @@ static int do_of_property(int argc, char *argv[]) return COMMAND_ERROR_USAGE; if (dtbfile) { - fdt = read_file(dtbfile, &size); - if (!fdt) { - printf("unable to read %s: %m\n", dtbfile); - return -errno; - } - - root = of_unflatten_dtb(fdt, size); - - free(fdt); + root = of_read_file(dtbfile); + if (IS_ERR(root)) + return PTR_ERR(root); } if (set) { @@ -401,8 +394,7 @@ static int do_of_property(int argc, char *argv[]) out: - if (root) - of_delete_node(root); + of_delete_node(root); return ret; } diff --git a/commands/oftree.c b/commands/oftree.c index 7d4b08c9d3..76227a10b0 100644 --- a/commands/oftree.c +++ b/commands/oftree.c @@ -31,7 +31,6 @@ static int do_oftree(int argc, char *argv[]) { struct fdt_header *fdt = NULL; - size_t size; int opt; int probe = 0; char *load = NULL; @@ -76,16 +75,7 @@ static int do_oftree(int argc, char *argv[]) } if (load) { - fdt = read_file(load, &size); - if (!fdt) { - printf("unable to read %s\n", load); - return 1; - } - - root = of_unflatten_dtb(fdt, size); - - free(fdt); - + root = of_read_file(load); if (IS_ERR(root)) return PTR_ERR(root); diff --git a/commands/parted.c b/commands/parted.c new file mode 100644 index 0000000000..6af18cdc57 --- /dev/null +++ b/commands/parted.c @@ -0,0 +1,374 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include <common.h> +#include <command.h> +#include <block.h> +#include <getopt.h> +#include <fcntl.h> +#include <disks.h> +#include <linux/sizes.h> +#include <partitions.h> +#include <linux/math64.h> + +static struct partition_desc *gpdesc; +static bool table_needs_write; +static const char *gunit_str = "KiB"; +static uint64_t gunit = 1024; + +struct unit { + const char *str; + uint64_t size; +}; + +static struct unit units[] = { + { .str = "B", .size = 1 }, + { .str = "s", .size = 512 }, + { .str = "KiB", .size = SZ_1K }, + { .str = "MiB", .size = SZ_1M }, + { .str = "GiB", .size = SZ_1G }, + { .str = "TiB", .size = SZ_1T }, + { .str = "KB", .size = 1000ULL }, + { .str = "MB", .size = 1000ULL * 1000 }, + { .str = "GB", .size = 1000ULL * 1000 * 1000 }, + { .str = "TB", .size = 1000ULL * 1000 * 1000 * 1000 }, + { .str = "k", .size = SZ_1K }, + { .str = "K", .size = SZ_1K }, + { .str = "M", .size = SZ_1M }, + { .str = "G", .size = SZ_1G }, +}; + +static int parted_strtoull(const char *str, uint64_t *val, uint64_t *mult) +{ + char *end; + int i; + + *val = simple_strtoull(str, &end, 0); + + if (!*end) { + *mult = 0; + return 0; + } + + for (i = 0; i < ARRAY_SIZE(units); i++) { + if (!strcmp(end, units[i].str)) { + *mult = units[i].size; + return 0; + } + } + + printf("Error: Cannot read \"%s\" as number\n", str); + + return -EINVAL; +} + +static struct partition_desc *pdesc_get(struct block_device *blk) +{ + if (gpdesc) + return gpdesc; + + gpdesc = partition_table_read(blk); + if (!gpdesc) { + printf("Cannot read partition table\n"); + return NULL; + } + + return gpdesc; +} + +static int do_unit(struct block_device *blk, int argc, char *argv[]) +{ + int i; + + if (argc < 2) { + printf("Error: missing unit\n"); + return -EINVAL; + } + + for (i = 0; i < ARRAY_SIZE(units); i++) { + if (!strcmp(units[i].str, argv[1])) { + gunit_str = units[i].str; + gunit = units[i].size; + return 2; + } + } + + printf("invalid unit: %s\n", argv[1]); + + return -EINVAL; +} + +static int do_print(struct block_device *blk, int argc, char *argv[]) +{ + struct partition_desc *pdesc; + struct partition *part; + + pdesc = pdesc_get(blk); + if (!pdesc) { + printf("Error: Cannot get partition table from %s\n", blk->cdev.name); + return -EINVAL; + } + + printf("Disk /dev/%s: %s\n", blk->cdev.name, + size_human_readable(blk->num_blocks << SECTOR_SHIFT)); + printf("Partition Table: %s\n", pdesc->parser->name); + + printf("Number Start End Size Name\n"); + + list_for_each_entry(part, &pdesc->partitions, list) { + uint64_t start = part->first_sec << SECTOR_SHIFT; + uint64_t size = part->size << SECTOR_SHIFT; + uint64_t end = start + size - SECTOR_SIZE; + + printf(" %3d %10llu%-3s %10llu%-3s %10llu%-3s %-36s\n", + part->num, + div64_u64(start, gunit), gunit_str, + div64_u64(end, gunit), gunit_str, + div64_u64(size, gunit), gunit_str, + part->name); + } + + return 1; +} + +static int do_mkpart(struct block_device *blk, int argc, char *argv[]) +{ + struct partition_desc *pdesc; + uint64_t start, end; + const char *name, *fs_type; + int ret; + uint64_t mult; + + if (argc < 5) { + printf("Error: Missing required arguments\n"); + return -EINVAL; + } + + name = argv[1]; + fs_type = argv[2]; + + ret = parted_strtoull(argv[3], &start, &mult); + if (ret) + return ret; + + ret = parted_strtoull(argv[4], &end, &mult); + if (ret) + return ret; + + if (!mult) + mult = gunit; + + start *= mult; + end *= mult; + + /* If not on sector boundaries move start up and end down */ + start = ALIGN(start, SECTOR_SIZE); + end = ALIGN_DOWN(end, SECTOR_SIZE); + + /* convert to LBA */ + start >>= SECTOR_SHIFT; + end >>= SECTOR_SHIFT; + + /* + * When unit is >= KB then substract one sector for user convenience. + * It allows to start the next partition where the previous ends + */ + if (mult >= 1000) + end -= 1; + + pdesc = pdesc_get(blk); + if (!pdesc) + return -EINVAL; + + ret = partition_create(pdesc, name, fs_type, start, end); + + if (!ret) + table_needs_write = true; + + return ret < 0 ? ret : 5; +} + +static int do_rmpart(struct block_device *blk, int argc, char *argv[]) +{ + struct partition_desc *pdesc; + unsigned long num; + int ret; + + if (argc < 2) { + printf("Error: Expecting a partition number.\n"); + return -EINVAL; + } + + ret = kstrtoul(argv[1], 0, &num); + if (ret) + return ret; + + pdesc = pdesc_get(blk); + if (!pdesc) + return -EINVAL; + + ret = partition_remove(pdesc, num); + if (ret) + return ret; + + table_needs_write = true; + + return 2; +} + +static int do_mklabel(struct block_device *blk, int argc, char *argv[]) +{ + struct partition_desc *pdesc; + + if (argc < 2) { + printf("Error: Expecting a disk label type.\n"); + return -EINVAL; + } + + pdesc = partition_table_new(blk, argv[1]); + if (IS_ERR(pdesc)) { + printf("Error: Cannot create partition table: %pe\n", pdesc); + return PTR_ERR(pdesc); + } + + table_needs_write = true; + + if (gpdesc) + partition_table_free(gpdesc); + gpdesc = pdesc; + + return 2; +} + +static int do_refresh(struct block_device *blk, int argc, char *argv[]) +{ + struct partition_desc *pdesc; + + pdesc = pdesc_get(blk); + if (!pdesc) + return -EINVAL; + + table_needs_write = true; + + return 1; +} + +struct parted_command { + const char *name; + int (*command)(struct block_device *blk, int argc, char *argv[]); +}; + +struct parted_command parted_commands[] = { + { + .name = "mkpart", + .command = do_mkpart, + }, { + .name = "print", + .command = do_print, + }, { + .name = "rm", + .command = do_rmpart, + }, { + .name = "mklabel", + .command = do_mklabel, + }, { + .name = "unit", + .command = do_unit, + }, { + .name = "refresh", + .command = do_refresh, + }, +}; + +static int parted_run_command(struct block_device *blk, int argc, char *argv[]) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(parted_commands); i++) { + struct parted_command *cmd = &parted_commands[i]; + + if (!strcmp(argv[0], cmd->name)) + return cmd->command(blk, argc, argv); + } + + printf("No such command: %s\n", argv[0]); + + return COMMAND_ERROR; +} + +static int do_parted(int argc, char *argv[]) +{ + struct cdev *cdev; + struct block_device *blk; + int ret = 0; + + table_needs_write = false; + gpdesc = NULL; + + if (argc < 3) + return COMMAND_ERROR_USAGE; + + cdev = cdev_open_by_name(argv[1], O_RDWR); + if (!cdev) { + printf("Cannot open %s\n", argv[1]); + return COMMAND_ERROR; + } + + blk = cdev_get_block_device(cdev); + if (!blk) { + ret = -EINVAL; + goto err; + } + + argc -= 2; + argv += 2; + + while (argc) { + debug("---> run command %s\n", argv[0]); + ret = parted_run_command(blk, argc, argv); + if (ret < 0) + break; + + argc -= ret; + argv += ret; + + ret = 0; + } + + if (!ret && gpdesc && table_needs_write) + ret = partition_table_write(gpdesc); + +err: + if (gpdesc) + partition_table_free(gpdesc); + + cdev_close(cdev); + + return ret; +} + +BAREBOX_CMD_HELP_START(parted) +BAREBOX_CMD_HELP_TEXT("parted is a partition manipulation program with a behaviour similar to") +BAREBOX_CMD_HELP_TEXT("GNU Parted") +BAREBOX_CMD_HELP_TEXT("") +BAREBOX_CMD_HELP_TEXT("commands:") +BAREBOX_CMD_HELP_OPT ("print", "print partitions") +BAREBOX_CMD_HELP_OPT ("mklabel <type>", "create a new partition table") +BAREBOX_CMD_HELP_OPT ("rm <num>", "remove a partition") +BAREBOX_CMD_HELP_OPT ("mkpart <name> <fstype> <start> <end>", "create a new partition") +BAREBOX_CMD_HELP_OPT ("unit <unit>", "change display/input units") +BAREBOX_CMD_HELP_OPT ("refresh", "refresh a partition table") +BAREBOX_CMD_HELP_TEXT("") +BAREBOX_CMD_HELP_TEXT("<unit> can be one of \"s\" (sectors), \"B\" (bytes), \"kB\", \"MB\", \"GB\", \"TB\",") +BAREBOX_CMD_HELP_TEXT("\"KiB\", \"MiB\", \"GiB\" or \"TiB\"") +BAREBOX_CMD_HELP_TEXT("<type> must be \"gpt\"") +BAREBOX_CMD_HELP_TEXT("<fstype> can be one of \"ext2\", \"ext3\", \"ext4\", \"fat16\", \"fat32\" or \"bbenv\"") +BAREBOX_CMD_HELP_TEXT("<name> for MBR partition tables can be one of \"primary\", \"extended\" or") +BAREBOX_CMD_HELP_TEXT("\"logical\". For GPT this is a name string.") +BAREBOX_CMD_HELP_END + +BAREBOX_CMD_START(parted) + .cmd = do_parted, + BAREBOX_CMD_DESC("edit partition tables") + BAREBOX_CMD_OPTS("<device> [command [options...]...]") + BAREBOX_CMD_GROUP(CMD_GRP_FILE) + BAREBOX_CMD_HELP(cmd_parted_help) +BAREBOX_CMD_END diff --git a/commands/partition.c b/commands/partition.c index 44ee0359bf..14f400ccb4 100644 --- a/commands/partition.c +++ b/commands/partition.c @@ -16,7 +16,6 @@ #include <complete.h> #include <driver.h> #include <malloc.h> -#include <partition.h> #include <errno.h> #include <xfuncs.h> #include <fs.h> diff --git a/commands/pm_domain.c b/commands/pm_domain.c new file mode 100644 index 0000000000..ec8b769df1 --- /dev/null +++ b/commands/pm_domain.c @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include <common.h> +#include <command.h> +#include <pm_domain.h> + +static int do_pm_domain(int argc, char *argv[]) +{ + pm_genpd_print(); + + return 0; +} + +BAREBOX_CMD_START(pm_domain) + .cmd = do_pm_domain, + BAREBOX_CMD_DESC("list power domains") + BAREBOX_CMD_GROUP(CMD_GRP_INFO) +BAREBOX_CMD_END diff --git a/commands/pwm.c b/commands/pwm.c new file mode 100644 index 0000000000..5d41fa8ff4 --- /dev/null +++ b/commands/pwm.c @@ -0,0 +1,212 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-FileCopyrightText: © 2023 Marc Reilly <marc@cpdesign.com.au> + +/* pwm - pwm commands */ + +#include <common.h> +#include <command.h> +#include <errno.h> +#include <malloc.h> +#include <getopt.h> +#include <pwm.h> + +#define HZ_TO_NANOSECONDS(x) (1000000000UL/(x)) +#define HZ_FROM_NANOSECONDS(x) (1000000000UL/(x)) + +static bool is_equal_state(struct pwm_state *state1, struct pwm_state *state2) +{ + return (state1->period_ns == state2->period_ns) + && (state1->duty_ns == state2->duty_ns) + && (state1->polarity == state2->polarity) + && (state1->p_enable == state2->p_enable); +} + +static int do_pwm_cmd(int argc, char *argv[]) +{ + struct pwm_device *pwm = NULL; + struct pwm_state state, orig_state; + int error = 0; + char *devname = NULL; + int duty = -1, period = -1; + int freq = -1, width = -1; + bool invert_polarity = false, stop = false; + bool use_default_width = false; + bool verbose = false; + int opt; + + while ((opt = getopt(argc, argv, "ld:D:P:f:w:F:isv")) > 0) { + switch (opt) { + case 'l': + pwm_print(); + return 0; + case 'd': + devname = optarg; + break; + case 'D': + duty = simple_strtol(optarg, NULL, 0); + break; + case 'P': + period = simple_strtol(optarg, NULL, 0); + break; + case 'F': + /* convenience option for changing frequency without + * having to specify duty width */ + use_default_width = true; + /* fallthrough */ + case 'f': + freq = simple_strtol(optarg, NULL, 0); + break; + case 'w': + width = simple_strtol(optarg, NULL, 0); + break; + case 'i': + invert_polarity = true; + break; + case 's': + stop = true; + break; + case 'v': + verbose = true; + break; + default: + return COMMAND_ERROR_USAGE; + } + } + + if (!devname) { + printf(" need to specify a device\n"); + return COMMAND_ERROR; + } + + if ((freq == 0) || (period == 0)) { + printf(" period or freqency needs to be non-zero\n"); + return COMMAND_ERROR; + } + + if (freq >= 0 && period >= 0) { + printf(" specify period or frequency, not both\n"); + return COMMAND_ERROR; + } + + if (duty >= 0 && width >= 0) { + printf(" specify duty or width, not both\n"); + return COMMAND_ERROR; + } + + if (width > 100) { + printf(" width (%% duty cycle) can't be more than 100%%\n"); + return COMMAND_ERROR; + } + + pwm = pwm_request(devname); + if (!pwm) { + printf(" pwm device %s not found\n", devname); + return -ENODEV; + } + + pwm_get_state(pwm, &state); + + /* argc will be at least 3 with a valid devname */ + if (verbose || (argc <= 3)) { + printf("pwm params for '%s':\n", devname); + printf(" period : %u (ns)\n", state.period_ns); + printf(" duty : %u (ns)\n", state.duty_ns); + printf(" enabled : %d\n", state.p_enable); + printf(" polarity : %s\n", state.polarity == 0 ? "Normal" : "Inverted"); + if (state.period_ns) + printf(" freq : %lu (Hz)\n", HZ_FROM_NANOSECONDS(state.period_ns)); + else + printf(" freq : -\n"); + + pwm_free(pwm); + return 0; + } + + if ((state.period_ns == 0) && (freq < 0) && (period < 0)) { + printf(" need to know some timing info: freq or period\n"); + pwm_free(pwm); + return COMMAND_ERROR; + } + + orig_state = state; + + if (invert_polarity) + state.polarity = invert_polarity; + + /* period */ + if (freq > 0) { + state.p_enable = true; + state.period_ns = HZ_TO_NANOSECONDS(freq); + if (use_default_width && (width < 0)) { + width = 50; + } + } else if (period > 0) { + state.p_enable = true; + state.period_ns = period; + } + + /* duty */ + if (width >= 0) { + pwm_set_relative_duty_cycle(&state, width, 100); + } else if (duty >= 0) { + state.duty_ns = duty; + } + + if (state.duty_ns > state.period_ns) { + printf(" duty_ns must not be greater than period_ns\n"); + } + + /* only set the state if its changed */ + if (!is_equal_state(&orig_state, & state)) + error = pwm_apply_state(pwm, &state); + + if (error < 0) + printf(" error while applying state: %d\n", error); + + /* stop handled as an additional step on purpose, allows turning off + * output (eg if duty => 0) and stopping in one command + */ + if (stop > 0) { + state.p_enable = false; + error = pwm_apply_state(pwm, &state); + if (error < 0) + printf(" error while stopping: %d\n", error); + } + + pwm_free(pwm); + + return error; +} + +BAREBOX_CMD_HELP_START(pwm) +BAREBOX_CMD_HELP_TEXT("Sets pwm device parameters, or shows current value.") +BAREBOX_CMD_HELP_TEXT(" Specify the pwm device by device name.") +BAREBOX_CMD_HELP_TEXT(" If no other parameters are given, or if args has '-v',") +BAREBOX_CMD_HELP_TEXT(" then show the current values only.") +BAREBOX_CMD_HELP_TEXT(" Timings can either be specified via period + duty (on) duration,") +BAREBOX_CMD_HELP_TEXT(" or via frequency. Duty can be given either as a percentage or time.") +BAREBOX_CMD_HELP_TEXT(" If a parameter is not specified, the current value will be used") +BAREBOX_CMD_HELP_TEXT(" where possible.") +BAREBOX_CMD_HELP_TEXT(" To set an output to inactive state, set the duty to 0.") +BAREBOX_CMD_HELP_TEXT(" (although note this will not by itself stop the pwm running.)") +BAREBOX_CMD_HELP_TEXT(" Stopping the pwm device does not necessarily set the output to inactive,") +BAREBOX_CMD_HELP_TEXT(" but stop is handled last, so can be done in addition to other changes.") +BAREBOX_CMD_HELP_TEXT("Options:") +BAREBOX_CMD_HELP_OPT("-l\t", "list registered PWMs") +BAREBOX_CMD_HELP_OPT("-d <name>", "device name (eg 'pwm0')") +BAREBOX_CMD_HELP_OPT("-D <duty_ns>", "duty cycle (ns)") +BAREBOX_CMD_HELP_OPT("-P <period_ns>", "period (ns)") +BAREBOX_CMD_HELP_OPT("-f <freq_hz>", "frequency (Hz)") +BAREBOX_CMD_HELP_OPT("-w <duty_%>", "duty cycle (%) - the on 'width' of each cycle") +BAREBOX_CMD_HELP_OPT("-i\t", "line inverted polarity") +BAREBOX_CMD_HELP_OPT("-s\t", "stop (disable) the pwm device") +BAREBOX_CMD_HELP_OPT("-v\t", "print current values") +BAREBOX_CMD_HELP_END + +BAREBOX_CMD_START(pwm) + .cmd = do_pwm_cmd, + BAREBOX_CMD_DESC("pwm") + BAREBOX_CMD_OPTS("[-ldDPfwisv]") + BAREBOX_CMD_GROUP(CMD_GRP_HWMANIP) + BAREBOX_CMD_HELP(cmd_pwm_help) +BAREBOX_CMD_END diff --git a/commands/readlink.c b/commands/readlink.c index 81ad25c733..55f8249028 100644 --- a/commands/readlink.c +++ b/commands/readlink.c @@ -31,7 +31,7 @@ static int do_readlink(int argc, char *argv[]) return COMMAND_ERROR_USAGE; if (canonicalize) { - char *buf = canonicalize_path(argv[optind]); + char *buf = canonicalize_path(AT_FDCWD, argv[optind]); struct stat s; if (!buf) diff --git a/commands/regulator.c b/commands/regulator.c index 3e2595f8bf..3e38b61646 100644 --- a/commands/regulator.c +++ b/commands/regulator.c @@ -6,16 +6,53 @@ #include <common.h> #include <command.h> #include <regulator.h> +#include <getopt.h> static int do_regulator(int argc, char *argv[]) { - regulators_print(); + struct regulator *chosen; + unsigned flags = 0; + int opt, ret; + while ((opt = getopt(argc, argv, "e:d:D")) > 0) { + switch (opt) { + case 'e': + case 'd': + chosen = regulator_get_name(optarg); + if (IS_ERR_OR_NULL(chosen)) { + printf("regulator not found\n"); + return COMMAND_ERROR; + } + + ret = opt == 'e' ? regulator_enable(chosen) + : regulator_disable(chosen); + regulator_put(chosen); + return ret; + case 'D': + flags |= REGULATOR_PRINT_DEVS; + break; + default: + return COMMAND_ERROR_USAGE; + } + } + + regulators_print(flags); return 0; } +BAREBOX_CMD_HELP_START(regulator) + BAREBOX_CMD_HELP_TEXT("List and control regulators.") + BAREBOX_CMD_HELP_TEXT("Without options, displays regulator info") + BAREBOX_CMD_HELP_TEXT("Options:") + BAREBOX_CMD_HELP_OPT("-e REGULATOR\t", "enable REGULATOR") + BAREBOX_CMD_HELP_OPT("-d REGULATOR\t", "disable REGULATOR") + BAREBOX_CMD_HELP_OPT("-D\t", "list provider devices of regulators") +BAREBOX_CMD_HELP_END + BAREBOX_CMD_START(regulator) .cmd = do_regulator, - BAREBOX_CMD_DESC("list regulators") - BAREBOX_CMD_GROUP(CMD_GRP_INFO) + BAREBOX_CMD_DESC("list and control regulators") + BAREBOX_CMD_OPTS("[-edD] [REGULATOR]") + BAREBOX_CMD_GROUP(CMD_GRP_HWMANIP) + BAREBOX_CMD_HELP(cmd_regulator_help) BAREBOX_CMD_END diff --git a/commands/reset.c b/commands/reset.c index fe54e2f9b4..88e677afab 100644 --- a/commands/reset.c +++ b/commands/reset.c @@ -12,12 +12,12 @@ static int cmd_reset(int argc, char *argv[]) { struct restart_handler *rst; - int opt, shutdown_flag; + int opt, shutdown_flag, flags = 0; const char *name = NULL; shutdown_flag = 1; - while ((opt = getopt(argc, argv, "flr:")) > 0) { + while ((opt = getopt(argc, argv, "flwr:")) > 0) { switch (opt) { case 'f': shutdown_flag = 0; @@ -25,6 +25,9 @@ static int cmd_reset(int argc, char *argv[]) case 'l': restart_handlers_print(); return 0; + case 'w': + flags |= RESTART_FLAG_WARM_BOOTROM; + break; case 'r': name = optarg; break; @@ -33,9 +36,9 @@ static int cmd_reset(int argc, char *argv[]) } } - rst = restart_handler_get_by_name(name); - if (!rst && name) { - printf("reset '%s' does not exist\n", name); + rst = restart_handler_get_by_name(name, flags); + if (!rst && (name || flags)) { + printf("No matching restart handler found\n"); return COMMAND_ERROR; } @@ -57,13 +60,14 @@ BAREBOX_CMD_HELP_START(reset) BAREBOX_CMD_HELP_TEXT("Options:") BAREBOX_CMD_HELP_OPT("-f", "force RESET, don't call shutdown") BAREBOX_CMD_HELP_OPT("-l", "list reset handlers") +BAREBOX_CMD_HELP_OPT("-w", "only consider warm BootROM reboot-mode-preserving resets") BAREBOX_CMD_HELP_OPT("-r RESET", "use reset handler named RESET") BAREBOX_CMD_HELP_END BAREBOX_CMD_START(reset) .cmd = cmd_reset, BAREBOX_CMD_DESC("perform RESET of the CPU") - BAREBOX_CMD_OPTS("[-flr]") + BAREBOX_CMD_OPTS("[-flrw]") BAREBOX_CMD_GROUP(CMD_GRP_BOOT) BAREBOX_CMD_HELP(cmd_reset_help) BAREBOX_CMD_COMPLETE(empty_complete) diff --git a/commands/rm.c b/commands/rm.c index ba52b185cb..c35cf2d2d4 100644 --- a/commands/rm.c +++ b/commands/rm.c @@ -12,13 +12,16 @@ static int do_rm(int argc, char *argv[]) { - int i, opt, recursive = 0; + int i, opt, recursive = 0, force = 0; - while ((opt = getopt(argc, argv, "r")) > 0) { + while ((opt = getopt(argc, argv, "rf")) > 0) { switch (opt) { case 'r': recursive = 1; break; + case 'f': + force = 1; + break; default: return COMMAND_ERROR_USAGE; } @@ -37,8 +40,10 @@ static int do_rm(int argc, char *argv[]) else ret = unlink(argv[i]); if (ret) { - printf("could not remove %s: %s\n", argv[i], errno_str()); - return 1; + if (!force || ret != -ENOENT) + printf("could not remove %s: %m\n", argv[i]); + if (!force) + return 1; } i++; } @@ -49,12 +54,13 @@ static int do_rm(int argc, char *argv[]) BAREBOX_CMD_HELP_START(rm) BAREBOX_CMD_HELP_TEXT("Options:") BAREBOX_CMD_HELP_OPT ("-r", "remove directories and their contents recursively") +BAREBOX_CMD_HELP_OPT ("-f", "ignore nonexistent files") BAREBOX_CMD_HELP_END BAREBOX_CMD_START(rm) .cmd = do_rm, BAREBOX_CMD_DESC("remove files") - BAREBOX_CMD_OPTS("[-r] FILES...") + BAREBOX_CMD_OPTS("[-rf] FILES...") BAREBOX_CMD_GROUP(CMD_GRP_FILE) BAREBOX_CMD_HELP(cmd_rm_help) BAREBOX_CMD_END diff --git a/commands/rmdir.c b/commands/rmdir.c index 9b2938a556..44793ca56e 100644 --- a/commands/rmdir.c +++ b/commands/rmdir.c @@ -14,7 +14,7 @@ static int do_rmdir(int argc, char *argv[]) while (i < argc) { if (rmdir(argv[i])) { - printf("could not remove %s: %s\n", argv[i], errno_str()); + printf("could not remove %s: %m\n", argv[i]); return 1; } i++; diff --git a/commands/selftest.c b/commands/selftest.c index a10f1467fe..bb62575aa7 100644 --- a/commands/selftest.c +++ b/commands/selftest.c @@ -24,7 +24,7 @@ static int run_selftest(const char *match, bool list) if (match && strcmp(test->name, match)) continue; - err |= test->func(); + err |= selftest_run(test); matches++; } diff --git a/commands/stacksmash.c b/commands/stacksmash.c new file mode 100644 index 0000000000..e200fa5a1c --- /dev/null +++ b/commands/stacksmash.c @@ -0,0 +1,58 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <common.h> +#include <command.h> +#include <complete.h> +#include <linux/compiler.h> +#include <string.h> + +static noinline void stack_overflow_frame(void) +{ + volatile int length = 512; + char a[128] = {}; + + /* + * In order to avoid having the compiler optimize away the stack smashing + * we need to do a little something here. + */ + OPTIMIZER_HIDE_VAR(length); + + memset(a, 0xa5, length); + + printf("We have smashed our stack as this should not exceed 128: sizeof(a) = %zu\n", + strlen(a)); +} + +static noinline void stack_overflow_region(u64 i) +{ + volatile char a[1024] = {}; + + if (ctrlc()) + return; + + RELOC_HIDE(&a, 0); + + stack_overflow_region(0); + + printf("%*ph", 1024, a); +} + +static int do_stacksmash(int argc, char *argv[]) +{ + if (argc != 2) + return COMMAND_ERROR_USAGE; + + if (!strcmp(argv[1], "frame")) + stack_overflow_frame(); + else if (!strcmp(argv[1], "region")) + stack_overflow_region(0); + + panic("Stack smashing of %s not caught\n", argv[1]); +} +BAREBOX_CMD_START(stacksmash) + .cmd = do_stacksmash, + BAREBOX_CMD_DESC("Run stack smashing tests") + BAREBOX_CMD_OPTS("[frame | region]") + BAREBOX_CMD_GROUP(CMD_GRP_MISC) + BAREBOX_CMD_COMPLETE(empty_complete) +BAREBOX_CMD_END diff --git a/commands/stat.c b/commands/stat.c new file mode 100644 index 0000000000..10662005cd --- /dev/null +++ b/commands/stat.c @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: © 2022 Ahmad Fatoum, Pengutronix + +#include <common.h> +#include <command.h> +#include <fs.h> +#include <linux/stat.h> +#include <errno.h> +#include <malloc.h> +#include <getopt.h> +#include <stringlist.h> + +static int do_stat(int argc, char *argv[]) +{ + int (*statfn)(int dirfd, const char *, struct stat *) = lstatat; + int ret, opt, dirfd = AT_FDCWD, extra_flags = 0, exitcode = 0; + char **filename; + struct stat st; + + while((opt = getopt(argc, argv, "Lc:C:")) > 0) { + switch(opt) { + case 'L': + statfn = statat; + break; + case 'C': + extra_flags |= O_CHROOT; + fallthrough; + case 'c': + dirfd = open(optarg, O_PATH | extra_flags); + if (dirfd < 0) + return dirfd; + break; + default: + return COMMAND_ERROR_USAGE; + } + } + + if (optind == argc) + return COMMAND_ERROR_USAGE; + + for (filename = &argv[optind]; *filename; filename++) { + ret = statfn(dirfd, *filename, &st); + + if (ret) { + printf("%s: %s: %m\n", argv[0], *filename); + exitcode = COMMAND_ERROR; + continue; + } + + stat_print(dirfd, *filename, &st); + } + + close(dirfd); + + return exitcode; +} + +BAREBOX_CMD_HELP_START(stat) +BAREBOX_CMD_HELP_TEXT("Display status information about the specified files") +BAREBOX_CMD_HELP_TEXT("or directories.") +BAREBOX_CMD_HELP_TEXT("") +BAREBOX_CMD_HELP_TEXT("Options:") +BAREBOX_CMD_HELP_OPT ("-L", "follow links") +BAREBOX_CMD_HELP_OPT ("-c DIR", "lookup file relative to directory DIR") +BAREBOX_CMD_HELP_OPT ("-C DIR", "change root to DIR before file lookup") +BAREBOX_CMD_HELP_END + +BAREBOX_CMD_START(stat) + .cmd = do_stat, + BAREBOX_CMD_DESC("display file status") + BAREBOX_CMD_OPTS("[-LcC] [FILEDIR...]") + BAREBOX_CMD_GROUP(CMD_GRP_FILE) + BAREBOX_CMD_HELP(cmd_stat_help) +BAREBOX_CMD_END diff --git a/commands/test.c b/commands/test.c index c845cec017..13005b97de 100644 --- a/commands/test.c +++ b/commands/test.c @@ -9,11 +9,13 @@ */ #include <common.h> #include <command.h> +#include <fnmatch.h> #include <fs.h> #include <linux/stat.h> typedef enum { OPT_EQUAL, + OPT_EQUAL_BASH, OPT_NOT_EQUAL, OPT_ARITH_EQUAL, OPT_ARITH_NOT_EQUAL, @@ -36,6 +38,7 @@ typedef enum { static char *test_options[] = { [OPT_EQUAL] = "=", + [OPT_EQUAL_BASH] = "==", [OPT_NOT_EQUAL] = "!=", [OPT_ARITH_EQUAL] = "-eq", [OPT_ARITH_NOT_EQUAL] = "-ne", @@ -67,19 +70,81 @@ static int parse_opt(const char *opt) return -1; } +static int string_comp(const char *left_op, const char *right_op, bool bash_test) +{ + if (bash_test) + return fnmatch(right_op, left_op, 0); + + return strcmp(left_op, right_op); +} + +static int parse_number(const char *str, long *num, bool signedcmp) +{ + int ret; + + ret = signedcmp ? kstrtol(str, 0, num) : kstrtoul(str, 0, num); + if (ret) + printf("test: %s: integer expression expected\n", str); + + return ret; +} + +#define __do_arith_cmp(x, op, y, signedcmp) \ + ((signedcmp) ? (long)(x) op (long)(y) : (x) op (y)) + +static int arith_comp(const char *a_str, const char *b_str, int op) +{ + ulong a, b; + bool signedcmp = a_str[0] == '-' || b_str[0] == '-'; + int ret; + + ret = parse_number(a_str, &a, signedcmp); + if (ret) + return ret; + + ret = parse_number(b_str, &b, signedcmp); + if (ret) + return ret; + + switch (op) { + case OPT_ARITH_EQUAL: + return __do_arith_cmp(a, ==, b, signedcmp); + case OPT_ARITH_NOT_EQUAL: + return __do_arith_cmp(a, !=, b, signedcmp); + case OPT_ARITH_GREATER_EQUAL: + return __do_arith_cmp(a, >=, b, signedcmp); + case OPT_ARITH_GREATER_THAN: + return __do_arith_cmp(a, >, b, signedcmp); + case OPT_ARITH_LESS_EQUAL: + return __do_arith_cmp(a, <=, b, signedcmp); + case OPT_ARITH_LESS_THAN: + return __do_arith_cmp(a, <, b, signedcmp); + } + + return -EINVAL; +} + static int do_test(int argc, char *argv[]) { char **ap; int left, adv, expr, last_expr, neg, last_cmp, opt, zero; - ulong a, b; struct stat statbuf; + bool bash_test = false; if (*argv[0] == '[') { - if (*argv[argc - 1] != ']') { - printf("[: missing `]'\n"); - return 1; - } argc--; + if (!strncmp(argv[0], "[[", 2)) { + if (strncmp(argv[argc], "]]", 2) != 0) { + printf("[[: missing `]]'\n"); + return 1; + } + bash_test = true; + } else { + if (*argv[argc] != ']') { + printf("[: missing `]'\n"); + return 1; + } + } } /* args? */ @@ -179,32 +244,24 @@ static int do_test(int argc, char *argv[]) if (left < 3) break; - a = simple_strtol(ap[0], NULL, 0); - b = simple_strtol(ap[2], NULL, 0); - switch (parse_opt(ap[1])) { + opt = parse_opt(ap[1]); + switch (opt) { case OPT_EQUAL: - expr = strcmp(ap[0], ap[2]) == 0; + case OPT_EQUAL_BASH: + expr = string_comp(ap[0], ap[2], bash_test) == 0; break; case OPT_NOT_EQUAL: - expr = strcmp(ap[0], ap[2]) != 0; + expr = string_comp(ap[0], ap[2], bash_test) != 0; break; case OPT_ARITH_EQUAL: - expr = a == b; - break; case OPT_ARITH_NOT_EQUAL: - expr = a != b; - break; case OPT_ARITH_LESS_THAN: - expr = a < b; - break; case OPT_ARITH_LESS_EQUAL: - expr = a <= b; - break; case OPT_ARITH_GREATER_THAN: - expr = a > b; - break; case OPT_ARITH_GREATER_EQUAL: - expr = a >= b; + expr = arith_comp(ap[0], ap[2], opt); + if (expr < 0) + return 1; break; default: expr = 1; @@ -233,7 +290,7 @@ out: return expr; } -static const char * const test_aliases[] = { "[", NULL}; +static const char * const test_aliases[] = { "[", "[[", NULL}; BAREBOX_CMD_HELP_START(test) BAREBOX_CMD_HELP_TEXT("Options:") diff --git a/commands/tftp.c b/commands/tftp.c index 48ff00c621..6ac822c9e8 100644 --- a/commands/tftp.c +++ b/commands/tftp.c @@ -21,15 +21,24 @@ static int do_tftpb(int argc, char *argv[]) char *source, *dest, *freep; int opt; int tftp_push = 0; + int port = -1; int ret; IPaddr_t ip; char ip4_str[sizeof("255.255.255.255")]; + char mount_opts[sizeof("port=12345")]; - while ((opt = getopt(argc, argv, "p")) > 0) { + while ((opt = getopt(argc, argv, "pP:")) > 0) { switch(opt) { case 'p': tftp_push = 1; break; + case 'P': + port = simple_strtoul(optarg, NULL, 0); + if (port <= 0 || port > 0xffff) { + pr_err("invalid port '%s'\n", optarg); + return COMMAND_ERROR_USAGE; + } + break; default: return COMMAND_ERROR_USAGE; } @@ -59,7 +68,13 @@ static int do_tftpb(int argc, char *argv[]) ip = net_get_serverip(); sprintf(ip4_str, "%pI4", &ip); - ret = mount(ip4_str, "tftp", TFTP_MOUNT_PATH, NULL); + + if (port >= 0) + sprintf(mount_opts, "port=%u", port); + else + mount_opts[0] = '\0'; + + ret = mount(ip4_str, "tftp", TFTP_MOUNT_PATH, mount_opts); if (ret) goto err_rmdir; @@ -84,12 +99,13 @@ BAREBOX_CMD_HELP_TEXT("server address is taken from the environment (ethX.server BAREBOX_CMD_HELP_TEXT("") BAREBOX_CMD_HELP_TEXT("Options:") BAREBOX_CMD_HELP_OPT ("-p", "push to TFTP server") +BAREBOX_CMD_HELP_OPT ("-P PORT", "tftp server port number") BAREBOX_CMD_HELP_END BAREBOX_CMD_START(tftp) .cmd = do_tftpb, BAREBOX_CMD_DESC("load (or save) a file using TFTP") - BAREBOX_CMD_OPTS("[-p] SOURCE [DEST]") + BAREBOX_CMD_OPTS("[-p] [-P <port>] SOURCE [DEST]") BAREBOX_CMD_GROUP(CMD_GRP_NET) BAREBOX_CMD_HELP(cmd_tftp_help) BAREBOX_CMD_END diff --git a/commands/time.c b/commands/time.c index 5b8933ea65..a3f2704071 100644 --- a/commands/time.c +++ b/commands/time.c @@ -5,33 +5,32 @@ #include <clock.h> #include <linux/math64.h> #include <malloc.h> +#include <getopt.h> static int do_time(int argc, char *argv[]) { - int i; + int opt; unsigned char *buf; u64 start, end, diff64; bool nanoseconds = false; - int len = 1; /* '\0' */ - if (argc < 2) - return COMMAND_ERROR_USAGE; - - for (i = 1; i < argc; i++) - len += strlen(argv[i]) + 1; + while ((opt = getopt(argc, argv, "+n")) > 0) { + switch (opt) { + case 'n': + nanoseconds = true; + break; + default: + return COMMAND_ERROR_USAGE; + } + } - buf = xzalloc(len); + argv += optind; + argc -= optind; - i = 1; - if (!strcmp(argv[i], "-n")) { - nanoseconds = true; - i++; - } + if (argc < 1) + return COMMAND_ERROR_USAGE; - for (; i < argc; i++) { - strcat(buf, argv[i]); - strcat(buf, " "); - } + buf = strjoin(" ", argv, argc); start = get_time_ns(); diff --git a/commands/trigger.c b/commands/trigger.c index c1402b66f0..d2802080b9 100644 --- a/commands/trigger.c +++ b/commands/trigger.c @@ -16,7 +16,7 @@ static int do_trigger(int argc, char *argv[]) { - struct led *led = NULL; + struct led *led; int opt, ret = 0; int cmd = LED_COMMAND_SHOW_INFO; enum led_trigger trigger; @@ -35,9 +35,6 @@ static int do_trigger(int argc, char *argv[]) } } - if (optind < argc) - led = led_by_name_or_number(argv[optind]); - switch (cmd) { case LED_COMMAND_SHOW_INFO: led_triggers_show_info(); diff --git a/commands/tutorial.c b/commands/tutorial.c index 4441777643..afe5b66f0b 100644 --- a/commands/tutorial.c +++ b/commands/tutorial.c @@ -84,7 +84,6 @@ out: static int do_tutorial_next(int argc, char *argv[]) { int opt, i; - char *step = NULL; char *oldcwd; ssize_t ret = 0; bool is_prev = *argv[0] == 'p'; @@ -121,14 +120,12 @@ static int do_tutorial_next(int argc, char *argv[]) next_step = next_step > 0 ? next_step - 1 : 0; if (optind == argc) { - step = steps.gl_pathv[next_step]; - ret = print_tutorial_step(step); + ret = print_tutorial_step(steps.gl_pathv[next_step]); if (ret == 0 && !is_prev) next_step = (next_step + 1) % steps.gl_pathc; } else { for (i = optind; i < argc; i++) { - step = strdup(argv[i]); - ret = print_tutorial_step(step); + ret = print_tutorial_step(argv[i]); if (ret) break; } diff --git a/commands/ubsan.c b/commands/ubsan.c index 620b4774c3..4a9716139c 100644 --- a/commands/ubsan.c +++ b/commands/ubsan.c @@ -102,6 +102,8 @@ static void test_ubsan_object_size_mismatch(void) volatile long long *ptr, val2; ptr = (long long *)&val; + OPTIMIZER_HIDE_VAR(ptr); + val2 = *ptr; } diff --git a/commands/uimage.c b/commands/uimage.c index 588519e3f3..72b827b5b2 100644 --- a/commands/uimage.c +++ b/commands/uimage.c @@ -13,7 +13,7 @@ static int uimage_fd; -static int uimage_flush(void *buf, unsigned int len) +static long uimage_flush(void *buf, unsigned long len) { return write_full(uimage_fd, buf, len); } diff --git a/commands/uptime.c b/commands/uptime.c new file mode 100644 index 0000000000..d67538631c --- /dev/null +++ b/commands/uptime.c @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include <common.h> +#include <command.h> +#include <clock.h> +#include <getopt.h> +#include <linux/math64.h> + +#define NSEC_PER_MINUTE (NSEC_PER_SEC * 60LL) +#define NSEC_PER_HOUR (NSEC_PER_MINUTE * 60LL) +#define NSEC_PER_DAY (NSEC_PER_HOUR * 24LL) +#define NSEC_PER_WEEK (NSEC_PER_DAY * 7LL) + +static bool print_with_unit(u64 val, const char *unit, bool comma) +{ + if (!val) + return comma; + + printf("%s%llu %s%s", comma ? ", " : "", val, unit, val > 1 ? "s" : ""); + return true; +} + +static int do_uptime(int argc, char *argv[]) +{ + u64 timestamp, weeks, days, hours, minutes; + bool comma = false; + int opt; + + timestamp = get_time_ns(); + + while((opt = getopt(argc, argv, "n")) > 0) { + switch(opt) { + case 'n': + printf("up %lluns\n", timestamp); + return 0; + default: + return COMMAND_ERROR_USAGE; + } + } + + if (optind != argc) + return COMMAND_ERROR_USAGE; + + printf("up "); + + weeks = div64_u64_rem(timestamp, NSEC_PER_WEEK, ×tamp); + days = div64_u64_rem(timestamp, NSEC_PER_DAY, ×tamp); + hours = div64_u64_rem(timestamp, NSEC_PER_HOUR, ×tamp); + minutes = div64_u64_rem(timestamp, NSEC_PER_MINUTE, ×tamp); + + comma = print_with_unit(weeks, "week", false); + comma = print_with_unit(days, "day", comma); + comma = print_with_unit(hours, "hour", comma); + comma = print_with_unit(minutes, "minute", comma); + + if (!comma) { + u64 seconds = div64_u64_rem(timestamp, NSEC_PER_SEC, ×tamp); + print_with_unit(seconds, "second", false); + } + + printf("\n"); + + return 0; +} + +BAREBOX_CMD_HELP_START(uptime) +BAREBOX_CMD_HELP_TEXT("This command formats the number of elapsed nanoseconds") +BAREBOX_CMD_HELP_TEXT("as measured with the current clocksource") +BAREBOX_CMD_HELP_TEXT("Note: Timekeeping is co-operative. If long running code does") +BAREBOX_CMD_HELP_TEXT("not use delay/is_timeout/get_time_ns/getchar functions") +BAREBOX_CMD_HELP_TEXT("timer may overrun resulting in incorrect results") +BAREBOX_CMD_HELP_TEXT("Options:") +BAREBOX_CMD_HELP_OPT ("-n", "output elapsed time in nanoseconds") +BAREBOX_CMD_HELP_END + +BAREBOX_CMD_START(uptime) + .cmd = do_uptime, + BAREBOX_CMD_DESC("Tell how long barebox has been running") + BAREBOX_CMD_OPTS("[-n]") + BAREBOX_CMD_GROUP(CMD_GRP_MISC) + BAREBOX_CMD_HELP(cmd_uptime_help) +BAREBOX_CMD_END diff --git a/commands/usb.c b/commands/usb.c index ca8d3e0d52..0588ba6968 100644 --- a/commands/usb.c +++ b/commands/usb.c @@ -6,7 +6,7 @@ #include <common.h> #include <command.h> #include <complete.h> -#include <usb/usb.h> +#include <linux/usb/usb.h> #include <getopt.h> /* shows the device tree recursively */ diff --git a/commands/usbgadget.c b/commands/usbgadget.c index 290f33eff3..e69660fde5 100644 --- a/commands/usbgadget.c +++ b/commands/usbgadget.c @@ -12,9 +12,9 @@ #include <getopt.h> #include <fs.h> #include <xfuncs.h> -#include <usb/usbserial.h> -#include <usb/dfu.h> -#include <usb/gadget-multi.h> +#include <linux/usb/usbserial.h> +#include <linux/usb/dfu.h> +#include <linux/usb/gadget-multi.h> static int do_usbgadget(int argc, char *argv[]) { @@ -61,7 +61,8 @@ BAREBOX_CMD_HELP_TEXT("Options:") BAREBOX_CMD_HELP_OPT ("-a\t", "Create CDC ACM function") BAREBOX_CMD_HELP_OPT ("-A <desc>", "Create Android Fastboot function. If 'desc' is not provided, " "try to use 'global.fastboot.partitions' variable.") -BAREBOX_CMD_HELP_OPT ("-b\t", "include registered barebox update handlers (fastboot specific)") +BAREBOX_CMD_HELP_OPT ("-b\t", "include registered barebox update handlers (fastboot specific," + "exported as 'bbu-<update_handler_name>' partitions)") BAREBOX_CMD_HELP_OPT ("-D <desc>", "Create DFU function. If 'desc' is not provided, " "try to use 'global.usbgadget.dfu_function' variable.") BAREBOX_CMD_HELP_OPT ("-S <desc>", "Create USB Mass Storage function. If 'desc' is not provided," diff --git a/commands/usbserial.c b/commands/usbserial.c index 567018c233..17a4afec42 100644 --- a/commands/usbserial.c +++ b/commands/usbserial.c @@ -11,7 +11,7 @@ #include <getopt.h> #include <fs.h> #include <xfuncs.h> -#include <usb/usbserial.h> +#include <linux/usb/usbserial.h> static int do_usbserial(int argc, char *argv[]) { diff --git a/commands/version.c b/commands/version.c index 764c208767..0ad8e587de 100644 --- a/commands/version.c +++ b/commands/version.c @@ -7,7 +7,7 @@ static int do_version(int argc, char *argv[]) { - printf ("\n%s\n", version_string); + printf ("\n%s\n\n", version_string); return 0; } |