diff options
Diffstat (limited to 'commands')
104 files changed, 3557 insertions, 903 deletions
diff --git a/commands/Kconfig b/commands/Kconfig index 520ad4b1de..8d0816c4d0 100644 --- a/commands/Kconfig +++ b/commands/Kconfig @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-only + config REGINFO bool @@ -21,6 +23,13 @@ menu "Commands" menu "Information" +config CMD_TUTORIAL + bool "barebox tutorial (next command)" + default SANDBOX + help + Help navigate a barebox tutorial available + in /env/data/tutorial/ + config CMD_AT91CLK bool "at91clk" default y @@ -44,6 +53,21 @@ config CMD_ARM_CPUINFO D-cache: 8192 bytes (linelen = 8) Control register: M C W P D L I V RR DT IT U XP +config CMD_RISCV_CPUINFO + bool "cpuinfo command" + default y + depends on RISCV + 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 @@ -59,6 +83,31 @@ config CMD_DEVINFO If called with a device path being the argument, devinfo shows more default information about this device and its parameters. +config CMD_DEVLOOKUP + tristate + prompt "devlookup" + help + Look up device behind device file and its parameters + + devlookup [-v VAR] /dev/DEVICE [parameter] + + Detects the device behind a device file and outputs it, + unless a second argument is given. In that case the device + parameter with that name is looked up. Specifying -v VARIABLE + will write output to VARIABLE instead of printing it. + +config CMD_DEVUNBIND + tristate + prompt "devunbind" + help + Debugging aid to unbind device(s) from driver at runtime + + devunbind [-fl] DEVICES.. + + Options: + -f unbind driver and force removal of device and children + -l list remove callbacks in shutdown order + config CMD_DMESG tristate prompt "dmesg" @@ -74,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 @@ -152,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 @@ -199,6 +257,21 @@ 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 + prompt "nvmem command" + help + the nvmem command lists the currently registered nvmem devices. + config CMD_LSPCI bool depends on PCI @@ -253,6 +326,15 @@ config CMD_POLLER is_timeout() or one of the various delay functions. The poller command prints informations about registered pollers. +config CMD_BTHREAD + tristate + prompt "bthread" + depends on BTHREAD + help + barebox threads are cooperatively-scheduled (green) threads that are running in + the background whenever code executes is_timeout() or one of the various delay + functions. The bthread command prints informations about registered bthreads. + config CMD_SLICE tristate prompt "slice" @@ -261,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 @@ -310,6 +401,7 @@ config CMD_BOOT BOOTSRC can be: - a filename under /env/boot/ - a full path to a boot script + - a full path to a bootspec entry - a device name - a partition name under /dev/ - a full path to a directory which @@ -371,38 +463,21 @@ config CMD_BOOTZ Usage: bootz FILE -config CMD_LINUX16 - tristate - depends on X86 && !X86_EFI - default y if X86 - prompt "linux16" - help - Usage: linux16 [-v VESAMODE] FILE - - Load kernel from FILE and boot on x86 in real-mode. - - Only kernel images in bzImage format are supported by now. - - For the video mode refer the Linux kernel documentation - 'Documentation/fb/vesafb.txt' for correct VESA mode numbers. Use 'ask' - instead of a number to make Linux prompt for options. - - Options: - -v VESAMODE set VESAMODE - - config CMD_GO tristate prompt "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 @@ -588,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 @@ -901,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 @@ -950,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 @@ -1130,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 @@ -1248,6 +1378,14 @@ config CMD_IP_ROUTE_GET be shown on the command line or alternatively a variable is set to the result. +config CMD_ETHLOG + tristate + prompt "ethlog" + help + log ethernet traffic. + + Usage: ethlog [-r] [DEVICENAME] + # end Network commands endmenu @@ -1295,9 +1433,10 @@ config CMD_ECHO_E config CMD_EDIT tristate + depends on CONSOLE_FULL || CONSOLE_SIMPLE prompt "edit" help - A small fill-screen editor. + A small full-screen editor. Usage: edit FILE @@ -1621,6 +1760,7 @@ config CMD_MEMSET config CMD_MEMTEST tristate + select MEMTEST prompt "memtest" help The memtest command can test the registered barebox memory. @@ -1841,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 @@ -1864,18 +2016,19 @@ 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 depends on NAND depends on PARTITION - depends on NAND_ECC_HW || NAND_ECC_SOFT prompt "nandtest" help NAND flash memory test @@ -1946,6 +2099,21 @@ config CMD_SPI -w BIT bits per word (default 8) -v verbose +config CMD_MIPI_DBI + bool + depends on DRIVER_VIDEO_MIPI_DBI && SPI + select PRINTF_HEXSTR + prompt "mipi_dbi command" + help + write/read from MIPI DBI SPI device + + Usage: mipi_dbi [-wld] [REG] [DATA...] + + Options: + -l list all MIPI DBI devices + -d DEVICE select specific device (default is first registered) + -w issue write command + config CMD_LED_TRIGGER bool depends on LED_TRIGGERS @@ -2056,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 @@ -2086,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 @@ -2153,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 @@ -2206,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 @@ -2237,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 034c0e6383..30e1f8403e 100644 --- a/commands/Makefile +++ b/commands/Makefile @@ -1,9 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0-only + obj-$(CONFIG_STDDEV) += stddev.o obj-$(CONFIG_CMD_DIGEST) += digest.o obj-$(CONFIG_COMPILE_HASH) += hashsum.o obj-$(CONFIG_CMD_BOOTM) += bootm.o obj-$(CONFIG_CMD_UIMAGE) += uimage.o -obj-$(CONFIG_CMD_LINUX16) += linux16.o obj-$(CONFIG_CMD_LOADB) += loadb.o obj-$(CONFIG_CMD_LOADY) += loadxy.o obj-$(CONFIG_CMD_LOADS) += loads.o @@ -15,6 +16,7 @@ obj-$(CONFIG_CMD_MEMCMP) += memcmp.o obj-$(CONFIG_CMD_MEMCPY) += memcpy.o obj-$(CONFIG_CMD_MEMSET) += memset.o obj-$(CONFIG_CMD_EDIT) += edit.o +obj-$(CONFIG_CMD_ETHLOG) += ethlog.o obj-$(CONFIG_CMD_EXEC) += exec.o obj-$(CONFIG_CMD_SLEEP) += sleep.o obj-$(CONFIG_CMD_SMC) += smc.o @@ -24,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 @@ -33,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 @@ -48,6 +52,7 @@ obj-$(CONFIG_CMD_SAVEENV) += saveenv.o obj-$(CONFIG_CMD_LOADENV) += loadenv.o obj-$(CONFIG_CMD_NAND) += nand.o obj-$(CONFIG_CMD_NANDTEST) += nandtest.o +obj-$(CONFIG_CMD_NVMEM) += nvmem.o obj-$(CONFIG_CMD_MEMTEST) += memtest.o obj-$(CONFIG_CMD_MEMTESTER) += memtester/ obj-$(CONFIG_CMD_TRUE) += true.o @@ -65,6 +70,8 @@ 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 obj-$(CONFIG_CMD_MENU) += menu.o @@ -75,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 @@ -97,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 @@ -105,11 +116,14 @@ obj-$(CONFIG_CMD_MIITOOL) += miitool.o obj-$(CONFIG_CMD_DETECT) += detect.o obj-$(CONFIG_CMD_BOOT) += boot.o obj-$(CONFIG_CMD_DEVINFO) += devinfo.o +obj-$(CONFIG_CMD_DEVUNBIND) += devunbind.o +obj-$(CONFIG_CMD_DEVLOOKUP) += devlookup.o obj-$(CONFIG_CMD_DRVINFO) += drvinfo.o 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 @@ -129,6 +143,12 @@ obj-$(CONFIG_CMD_MMC_EXTCSD) += mmc_extcsd.o obj-$(CONFIG_CMD_NAND_BITFLIP) += nand-bitflip.o obj-$(CONFIG_CMD_SEED) += seed.o obj-$(CONFIG_CMD_IP_ROUTE_GET) += ip-route-get.o +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 18f4e36ec7..e4699520e8 100644 --- a/commands/boot.c +++ b/commands/boot.c @@ -28,13 +28,14 @@ static int do_boot(int argc, char *argv[]) char *freep = NULL; int opt, ret = 0, do_list = 0, do_menu = 0; int dryrun = 0, verbose = 0, timeout = -1; + unsigned default_menu_entry = 0; struct bootentries *entries; struct bootentry *entry; void *handle; const char *name; char *(*next)(void *); - while ((opt = getopt(argc, argv, "vldmt:w:")) > 0) { + while ((opt = getopt(argc, argv, "vldmM:t:w:")) > 0) { switch (opt) { case 'v': verbose++; @@ -43,8 +44,18 @@ 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 */ + if (*optarg == '\0') { + default_menu_entry = 1; + } else { + ret = kstrtouint(optarg, 0, &default_menu_entry); + if (ret) + return ret; + } + fallthrough; case 'm': do_menu = 1; break; @@ -104,7 +115,7 @@ static int do_boot(int argc, char *argv[]) if (do_list) bootsources_list(entries); else if (do_menu) - bootsources_menu(entries, timeout); + bootsources_menu(entries, default_menu_entry, timeout); ret = 0; out: @@ -122,6 +133,7 @@ BAREBOX_CMD_HELP_TEXT("") BAREBOX_CMD_HELP_TEXT("BOOTSRC can be:") BAREBOX_CMD_HELP_TEXT("- a filename under /env/boot/") BAREBOX_CMD_HELP_TEXT("- a full path to a boot script") +BAREBOX_CMD_HELP_TEXT("- a full path to a bootspec entry") BAREBOX_CMD_HELP_TEXT("- a device name") BAREBOX_CMD_HELP_TEXT("- a partition name under /dev/") BAREBOX_CMD_HELP_TEXT("- a full path to a directory which") @@ -133,9 +145,10 @@ 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") BAREBOX_CMD_HELP_OPT ("-w SECS","Start watchdog with timeout SECS before booting") BAREBOX_CMD_HELP_OPT ("-t SECS","specify timeout in SECS") BAREBOX_CMD_HELP_END @@ -143,7 +156,7 @@ BAREBOX_CMD_HELP_END BAREBOX_CMD_START(boot) .cmd = do_boot, BAREBOX_CMD_DESC("boot from script, device, ...") - BAREBOX_CMD_OPTS("[-vdlmwt] [BOOTSRC...]") + BAREBOX_CMD_OPTS("[-vdlmMwt] [BOOTSRC...]") BAREBOX_CMD_GROUP(CMD_GRP_BOOT) BAREBOX_CMD_HELP(cmd_boot_help) BAREBOX_CMD_END diff --git a/commands/bootm.c b/commands/bootm.c index f54a4827eb..95d267135c 100644 --- a/commands/bootm.c +++ b/commands/bootm.c @@ -17,7 +17,6 @@ #include <fs.h> #include <errno.h> #include <bootm.h> -#include <of.h> #include <rtc.h> #include <init.h> #include <of.h> diff --git a/commands/bthread.c b/commands/bthread.c new file mode 100644 index 0000000000..aaade46e92 --- /dev/null +++ b/commands/bthread.c @@ -0,0 +1,234 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2021 Ahmad Fatoum, Pengutronix + */ + +#include <bthread.h> +#include <errno.h> +#include <malloc.h> +#include <stdio.h> +#include <command.h> +#include <getopt.h> +#include <clock.h> +#include <slice.h> + +static int bthread_time(void) +{ + uint64_t start = get_time_ns(); + int i = 0; + + slice_release(&command_slice); + + /* + * How many background tasks can we have in one second? + * + * A low number here may point to problems with bthreads taking too + * much time. + */ + while (!is_timeout(start, SECOND)) + i++; + + slice_acquire(&command_slice); + + return i; +} + +static void bthread_infinite(void *data) +{ + while (!bthread_should_stop()) + ; +} + +static int bthread_isolated_time(void) +{ + uint64_t start = get_time_ns(); + struct bthread *bthread; + int i = 0; + + bthread = bthread_run(bthread_infinite, NULL, "infinite"); + if (!bthread) + return -ENOMEM; + + /* main thread is the first in the run queue. Newly created bthread + * is the last. So if main_thread explicitly schedules new bthread, + * it will schedule back to main_thread afterwards and we won't + * execute any other threads in-between. + */ + + while (!is_timeout_non_interruptible(start, SECOND)) { + bthread_schedule(bthread); + i += 2; + } + + __bthread_stop(bthread); + + return i; +} + +struct arg { + unsigned long in; + long out; +}; + +static void bthread_printer(void *_arg) +{ + struct arg *arg = _arg; + volatile u64 start; + volatile unsigned long i = 0; + start = get_time_ns(); + + while (!bthread_should_stop()) { + if (!is_timeout_non_interruptible(start, 225 * MSECOND)) + continue; + + if (arg->in == i++) + printf("%s yield #%lu\n", bthread_name(current), i); + start = get_time_ns(); + } + + arg->out = i; +} + +static int yields; + +static void bthread_spawner(void *_spawner_arg) +{ + struct arg *arg, *spawner_arg = _spawner_arg; + struct bthread *bthread[4]; + volatile u64 start; + volatile unsigned long i = 0; + int ret = 0; + + start = get_time_ns(); + + for (i = 0; i < ARRAY_SIZE(bthread); i++) { + arg = malloc(sizeof(*arg)); + arg->in = i; + bthread[i] = bthread_run(bthread_printer, arg, + "%s-bthread%u", bthread_name(current), i+1); + if (!bthread[i]) { + ret = -ENOMEM; + goto cleanup; + } + } + + while (!bthread_should_stop()) + ; + +cleanup: + while (i--) { + arg = bthread_data(bthread[i]); + __bthread_stop(bthread[i]); + + if (!ret && (arg->out != 4 || yields < arg->out)) + ret = -EIO; + free(arg); + } + + spawner_arg->out = ret; +} + +struct spawn { + struct bthread *bthread; + struct list_head list; +}; + +static int do_bthread(int argc, char *argv[]) +{ + static int dummynr; + static LIST_HEAD(dummies); + LIST_HEAD(spawners); + struct spawn *spawner, *tmp; + int ret = 0; + int opt, i = 0; + bool time = false; + struct arg *arg; + + while ((opt = getopt(argc, argv, "aritcv")) > 0) { + switch (opt) { + case 'a': + spawner = xzalloc(sizeof(*spawner)); + spawner->bthread = bthread_run(bthread_infinite, NULL, + "dummy%u", dummynr++); + if (!spawner->bthread) { + free(spawner); + ret = -ENOMEM; + goto cleanup; + } + + list_add(&spawner->list, &dummies); + break; + case 'r': + if (dummynr == 0) + return -EINVAL; + spawner = list_first_entry(&dummies, struct spawn, list); + bthread_cancel(spawner->bthread); + list_del(&spawner->list); + free(spawner); + dummynr--; + break; + case 'i': + bthread_info(); + break; + case 'c': + yields = bthread_isolated_time(); + printf("%d bthread context switches possible in 1s\n", yields); + break; + case 'v': + spawner = xzalloc(sizeof(*spawner)); + arg = malloc(sizeof(*arg)); + spawner->bthread = bthread_run(bthread_spawner, arg, + "spawner%u", ++i); + if (!spawner->bthread) { + free(spawner); + ret = -ENOMEM; + goto cleanup; + } + + /* We create intermediate spawning threads to test thread + * creation and scheduling from non-main thread. + */ + list_add(&spawner->list, &spawners); + + /* fallthrough */ + case 't': + time = true; + } + } + + if (time) { + yields = bthread_time(); + printf("%d bthread yield calls in 1s\n", yields); + } + +cleanup: + list_for_each_entry_safe(spawner, tmp, &spawners, list) { + arg = bthread_data(spawner->bthread); + __bthread_stop(spawner->bthread); + if (!ret && arg->out) + ret = arg->out; + free(arg); + free(spawner); + } + + return ret; +} + +BAREBOX_CMD_HELP_START(bthread) + BAREBOX_CMD_HELP_TEXT("print info about registered barebox threads") + BAREBOX_CMD_HELP_TEXT("") + BAREBOX_CMD_HELP_TEXT("Options:") + BAREBOX_CMD_HELP_OPT ("-i", "Print information about registered bthreads") + BAREBOX_CMD_HELP_OPT ("-t", "measure how many bthreads we currently run in 1s") + BAREBOX_CMD_HELP_OPT ("-c", "count maximum context switches in 1s") + BAREBOX_CMD_HELP_OPT ("-a", "add a dummy bthread") + BAREBOX_CMD_HELP_OPT ("-r", "remove a dummy bthread") + BAREBOX_CMD_HELP_OPT ("-v", "verify correct bthread operation") +BAREBOX_CMD_HELP_END + +BAREBOX_CMD_START(bthread) + .cmd = do_bthread, + BAREBOX_CMD_DESC("print info about registered bthreads") + BAREBOX_CMD_GROUP(CMD_GRP_MISC) + BAREBOX_CMD_HELP(cmd_bthread_help) +BAREBOX_CMD_END 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 649a0a7cb2..606519091e 100644 --- a/commands/clk.c +++ b/commands/clk.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only + #include <common.h> #include <command.h> #include <getopt.h> @@ -54,23 +56,18 @@ BAREBOX_CMD_END static int do_clk_set_rate(int argc, char *argv[]) { - struct clk *clk; unsigned long rate; if (argc != 3) return COMMAND_ERROR_USAGE; - clk = clk_lookup(argv[1]); - if (IS_ERR(clk)) - return PTR_ERR(clk); - rate = simple_strtoul(argv[2], NULL, 0); - return clk_set_rate(clk, rate); + return clk_name_set_rate(argv[1], rate); } 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) @@ -82,6 +79,38 @@ BAREBOX_CMD_START(clk_set_rate) BAREBOX_CMD_COMPLETE(clk_name_complete) BAREBOX_CMD_END +static int do_clk_round_rate(int argc, char *argv[]) +{ + struct clk *clk; + unsigned long rate; + + if (argc != 3) + return COMMAND_ERROR_USAGE; + + clk = clk_lookup(argv[1]); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + rate = simple_strtoul(argv[2], NULL, 0); + + printf("%ld\n", clk_round_rate(clk, rate)); + + return 0; +} + +BAREBOX_CMD_HELP_START(clk_round_rate) +BAREBOX_CMD_HELP_TEXT("Show clock CLK actual rate if set to HZ") +BAREBOX_CMD_HELP_END + +BAREBOX_CMD_START(clk_round_rate) + .cmd = do_clk_round_rate, + BAREBOX_CMD_DESC("show a resulting clocks rate") + BAREBOX_CMD_OPTS("CLK HZ") + BAREBOX_CMD_GROUP(CMD_GRP_HWMANIP) + BAREBOX_CMD_HELP(cmd_clk_round_rate_help) + BAREBOX_CMD_COMPLETE(clk_name_complete) +BAREBOX_CMD_END + static int do_clk_get_rate(int argc, char *argv[]) { int opt; @@ -110,13 +139,9 @@ static int do_clk_get_rate(int argc, char *argv[]) rate = clk_get_rate(clk); - if (variable_name) { - char *t; - - t = basprintf("%lu", rate); - setenv(variable_name, t); - free(t); - } else + if (variable_name) + pr_setenv(variable_name, "%lu", rate); + else printf("%lu\n", rate); return COMMAND_SUCCESS; @@ -182,19 +207,10 @@ BAREBOX_CMD_END static int do_clk_set_parent(int argc, char *argv[]) { - struct clk *clk, *parent; - if (argc != 3) return COMMAND_ERROR_USAGE; - clk = clk_lookup(argv[1]); - if (IS_ERR(clk)) - return PTR_ERR(clk); - parent = clk_lookup(argv[2]); - if (IS_ERR(parent)) - return PTR_ERR(parent); - - return clk_set_parent(clk, parent); + return clk_name_set_parent(argv[1], argv[2]); } BAREBOX_CMD_START(clk_set_parent) diff --git a/commands/crc.c b/commands/crc.c index 80ecf7fe29..23ffd4360b 100644 --- a/commands/crc.c +++ b/commands/crc.c @@ -83,17 +83,11 @@ static int do_crc(int argc, char *argv[]) printf("CRC32 for %s 0x%08lx ... 0x%08lx ==> 0x%08lx", filename, (ulong)start, (ulong)start + total - 1, crc); - if (crcvarname) { - char *crcstr = basprintf("0x%lx", crc); - setenv(crcvarname, crcstr); - kfree(crcstr); - } + if (crcvarname) + pr_setenv(crcvarname, "0x%lx", crc); - if (sizevarname) { - char *sizestr = basprintf("0x%lx", total); - setenv(sizevarname, sizestr); - kfree(sizestr); - } + if (sizevarname) + pr_setenv(sizevarname, "0x%lx", total); #ifdef CONFIG_CMD_CRC_CMP if (vfilename) { 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 2e2e48e42c..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; @@ -85,7 +85,7 @@ static int do_devinfo(int argc, char *argv[]) if (dev->info) dev->info(dev); - if (dev->parent) + if (dev->parent && (!dev->bus || dev->bus->dev != dev->parent)) printf("Parent: %s\n", dev_name(dev->parent)); first = true; @@ -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); + 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/devlookup.c b/commands/devlookup.c new file mode 100644 index 0000000000..ffd6afbaba --- /dev/null +++ b/commands/devlookup.c @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include <common.h> +#include <command.h> +#include <fs.h> +#include <getopt.h> +#include <malloc.h> +#include <linux/stat.h> +#include <linux/ctype.h> +#include <environment.h> + +static int report(const char *variable, const char *val) +{ + if (!val) + return -(errno ?: EINVAL); + + if (variable) + return setenv(variable, val); + + printf("%s\n", val); + return 0; +} + +static int do_devlookup(int argc, char *argv[]) +{ + const char *variable = NULL, *devicefile, *paramname; + struct cdev *cdev; + int opt; + + while ((opt = getopt(argc, argv, "v:")) > 0) { + switch(opt) { + case 'v': + variable = optarg; + break; + } + } + + if (argc - optind == 0 || argc - optind > 2) + return COMMAND_ERROR_USAGE; + + devicefile = argv[optind]; + paramname = argv[optind + 1]; + + devicefile = devpath_to_name(devicefile); + + cdev = cdev_by_name(devicefile); + if (!cdev) { + printf("devlookup: cdev %s not found\n", devicefile); + return -ENOENT; + } + + if (!cdev->dev) { + printf("devlookup: cdev %s not associated with a device\n", devicefile); + return -ENODEV; + } + + if (paramname) + return report(variable, dev_get_param(cdev->dev, paramname)); + + return report(variable, dev_name(cdev->dev)); +} + +BAREBOX_CMD_HELP_START(devlookup) +BAREBOX_CMD_HELP_TEXT("Detects the device behind a device file and outputs it,") +BAREBOX_CMD_HELP_TEXT("unless a second argument is given. In that case the device") +BAREBOX_CMD_HELP_TEXT("parameter with that name is looked up. Specifying -v VARIABLE") +BAREBOX_CMD_HELP_TEXT("will write output to VARIABLE instead of printing it") +BAREBOX_CMD_HELP_END + +BAREBOX_CMD_START(devlookup) + .cmd = do_devlookup, + BAREBOX_CMD_DESC("look up device behind device file and its parameters") + BAREBOX_CMD_OPTS("[-v VAR] /dev/DEVICE [parameter]") + BAREBOX_CMD_GROUP(CMD_GRP_SCRIPT) + BAREBOX_CMD_HELP(cmd_devlookup_help) +BAREBOX_CMD_END + diff --git a/commands/devunbind.c b/commands/devunbind.c new file mode 100644 index 0000000000..d30193b285 --- /dev/null +++ b/commands/devunbind.c @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: © 2021 Ahmad Fatoum <a.fatoum@pengutronix.de>, Pengutronix + +#include <command.h> +#include <common.h> +#include <complete.h> +#include <driver.h> +#include <getopt.h> + +static int do_devunbind(int argc, char *argv[]) +{ + bool unregister = false; + struct device *dev; + int ret = COMMAND_SUCCESS, i, opt; + + while ((opt = getopt(argc, argv, "fl")) > 0) { + switch (opt) { + case 'f': + unregister = true; + break; + case 'l': + list_for_each_entry(dev, &active_device_list, active) { + void *rm_dev; + + BUG_ON(!dev->driver); + + 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; + default: + return COMMAND_ERROR_USAGE; + } + } + + if (!argv[optind]) + return COMMAND_ERROR_USAGE; + + for (i = optind; i < argc; i++) { + dev = get_device_by_name(argv[i]); + if (!dev) { + printf("skipping missing %s\n", argv[i]); + ret = -ENODEV; + continue; + } + + if (unregister) { + unregister_device(dev); + continue; + } + + if (!device_remove(dev)) { + printf("no remove callback registered for %s\n", argv[i]); + ret = COMMAND_ERROR; + continue; + } + + dev->driver = NULL; + list_del(&dev->active); + } + + return ret; +} + +BAREBOX_CMD_HELP_START(devunbind) +BAREBOX_CMD_HELP_TEXT("Debugging aid to unbind device from driver at runtime") +BAREBOX_CMD_HELP_TEXT("") +BAREBOX_CMD_HELP_TEXT("Options:") +BAREBOX_CMD_HELP_OPT ("-f", "unbind driver and force removal of device and children") +BAREBOX_CMD_HELP_OPT ("-l", "list remove callbacks in shutdown order") +BAREBOX_CMD_HELP_END + +BAREBOX_CMD_START(devunbind) + .cmd = do_devunbind, + BAREBOX_CMD_DESC("unbind device(s) from driver") + BAREBOX_CMD_OPTS("[-fl] DEVICES..") + BAREBOX_CMD_GROUP(CMD_GRP_INFO) + BAREBOX_CMD_HELP(cmd_devunbind_help) + BAREBOX_CMD_COMPLETE(device_complete) +BAREBOX_CMD_END diff --git a/commands/dfu.c b/commands/dfu.c index 3132a7479d..2116747f68 100644 --- a/commands/dfu.c +++ b/commands/dfu.c @@ -10,7 +10,8 @@ #include <getopt.h> #include <fs.h> #include <xfuncs.h> -#include <usb/dfu.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) @@ -20,28 +21,28 @@ */ static int do_dfu(int argc, char *argv[]) { - struct f_dfu_opts opts; - char *argstr; - struct usb_dfu_dev *dfu_alts = NULL; + struct usbgadget_funcs funcs = {}; int ret; if (argc != optind + 1) return COMMAND_ERROR_USAGE; - argstr = argv[optind]; + funcs.flags |= USBGADGET_DFU; + funcs.dfu_opts = argv[optind]; + ret = usbgadget_register(&funcs); + if (ret) + return ret; - opts.files = file_list_parse(argstr); - if (IS_ERR(opts.files)) { - ret = PTR_ERR(opts.files); - goto out; + command_slice_release(); + while (!usb_dfu_detached()) { + if (ctrlc()) { + ret = -EINTR; + break; + } } + command_slice_acquire(); - ret = usb_dfu_register(&opts); - - file_list_free(opts.files); -out: - - free(dfu_alts); + usb_multi_unregister(); return ret; } 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/echo.c b/commands/echo.c index 99575b4c0c..572b852ea3 100644 --- a/commands/echo.c +++ b/commands/echo.c @@ -10,6 +10,40 @@ #include <errno.h> #include <libbb.h> +static void echo_dputc(int fd, char c, bool wide) +{ + wchar_t wc; + int n; + + if (!wide || fd == 1 || fd == 2) { + dputc(fd, c); + return; + } + + n = mbtowc(&wc, &c, 1); + if (n < 0) + return; + + write(fd, &wc, sizeof(wchar_t)); +} + +static void echo_dputs(int fd, const char *s, bool wide) +{ + wchar_t *ws; + + if (!wide || fd == 1 || fd == 2) { + dputs(fd, s); + return; + } + + ws = strdup_char_to_wchar(s); + if (!ws) + return; + + write(fd, ws, wcslen(ws) * sizeof(wchar_t)); + free(ws); +} + static int do_echo(int argc, char *argv[]) { int i, optind = 1; @@ -18,6 +52,10 @@ static int do_echo(int argc, char *argv[]) int oflags = O_WRONLY | O_CREAT; char str[CONFIG_CBSIZE]; int process_escape = 0; + bool wide = false; + + if (IS_ENABLED(CONFIG_PRINTF_WCHAR) && *argv[0] == 'w') + wide = true; /* We can't use getopt() here because we want to * echo all things we don't understand. @@ -66,18 +104,22 @@ exit_parse: } for (i = optind; i < argc; i++) { + const char *out; + if (i > optind) - dputc(fd, ' '); + echo_dputc(fd, ' ', wide); if (process_escape) { process_escape_sequence(argv[i], str, CONFIG_CBSIZE); - dputs(fd, str); + out = str; } else { - dputs(fd, argv[i]); + out = argv[i]; } + + echo_dputs(fd, out, wide); } if (newline) - dputc(fd, '\n'); + echo_dputc(fd, '\n', wide); if (file) close(fd); @@ -99,8 +141,13 @@ BAREBOX_CMD_HELP_OPT ("-a FILE", "append to FILE instead of using stdout") BAREBOX_CMD_HELP_OPT ("-o FILE", "overwrite FILE instead of using stdout") BAREBOX_CMD_HELP_END +static __maybe_unused const char * const echo_aliases[] = { "wecho", NULL}; + BAREBOX_CMD_START(echo) .cmd = do_echo, +#ifdef CONFIG_PRINTF_WCHAR + .aliases = echo_aliases, +#endif BAREBOX_CMD_DESC("echo args to console") BAREBOX_CMD_OPTS("[-neao] STRING") BAREBOX_CMD_GROUP(CMD_GRP_CONSOLE) diff --git a/commands/edit.c b/commands/edit.c index 3ab4beaa4f..dea383aae7 100644 --- a/commands/edit.c +++ b/commands/edit.c @@ -12,6 +12,7 @@ #include <errno.h> #include <xfuncs.h> #include <linux/stat.h> +#include <console.h> #define TABSPACE 8 @@ -184,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; } @@ -248,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; } @@ -347,19 +348,57 @@ static void merge_line(struct line *line) static void getwinsize(void) { - int i = 0, r; - char buf[100]; + int n; char *endp; + struct console_device *cdev; + const char esc[] = ESC "7" ESC "[r" ESC "[999;999H" ESC "[6n"; + char buf[64]; - printf(ESC "7" ESC "[r" ESC "[999;999H" ESC "[6n"); + screenwidth = screenheight = 256; - while ((r = getchar()) != 'R') { - buf[i] = r; - i++; - } + for_each_console(cdev) { + int width, height; + uint64_t start; + + if (!(cdev->f_active & CONSOLE_STDIN)) + continue; + if (!(cdev->f_active & CONSOLE_STDOUT)) + continue; + + memset(buf, 0, sizeof(buf)); + + cdev->puts(cdev, esc, sizeof(esc)); + + n = 0; + + start = get_time_ns(); + + while (1) { + if (is_timeout(start, 100 * MSECOND)) + break; + + if (!cdev->tstc(cdev)) + continue; + + buf[n] = cdev->getc(cdev); + + if (buf[n] == 'R') + break; + + n++; + } + + if (buf[0] != 27) + continue; + if (buf[1] != '[') + continue; - screenheight = simple_strtoul(buf + 2, &endp, 10); - screenwidth = simple_strtoul(endp + 1, NULL, 10); + height = simple_strtoul(buf + 2, &endp, 10); + width = simple_strtoul(endp + 1, NULL, 10); + + screenwidth = min(screenwidth, width); + screenheight = min(screenheight, height); + } pos(0, 0); } @@ -483,6 +522,25 @@ static int read_modal_key(bool is_modal) return -EAGAIN; } +static bool is_efi_console_active(void) +{ + struct console_device *cdev; + + if (!IS_ENABLED(CONFIG_DRIVER_SERIAL_EFI_STDIO)) + return false; + + for_each_console(cdev) { + if (!(cdev->f_active & CONSOLE_STDIN)) + continue; + if (!(cdev->f_active & CONSOLE_STDOUT)) + continue; + if (!strcmp(dev_name(cdev->dev), "efi-stdio")) + return true; + } + + return false; +} + static int do_edit(int argc, char *argv[]) { bool is_vi = false; @@ -495,17 +553,12 @@ static int do_edit(int argc, char *argv[]) if (argc != 2) return COMMAND_ERROR_USAGE; - screenwidth = 80; + buffer = NULL; + if(edit_read_file(argv[1])) + return 1; - /* - * The EFI simple text output protocol wraps to the next line and scrolls - * down when we write to the right bottom screen position. Reduce the number - * of rows by one to work around this. - */ - if (IS_ENABLED(CONFIG_EFI_BOOTUP)) - screenheight = 24; - else - screenheight = 25; + screenwidth = 80; + screenheight = 25; /* check if we are not called as "edit" */ if (*argv[0] != 'e') { @@ -517,9 +570,21 @@ static int do_edit(int argc, char *argv[]) is_vi = true; } - buffer = NULL; - if(edit_read_file(argv[1])) - return 1; + if (is_efi_console_active()) { + /* + * The EFI simple text output protocol wraps to the next line and + * scrolls down when we write to the right bottom screen position. + * Reduce the number of rows by one to work around this. + */ + screenheight--; + + /* + * Our console driver for the EFI simple text output protocol does + * not implement the "\e[1S" sequence we use for scrolling the + * screen. + */ + smartscroll = 0; + } cursx = 0; cursy = 0; @@ -545,7 +610,9 @@ static int do_edit(int argc, char *argv[]) argv[1]); } - printf("\x1b[2;%dr", screenheight); + if (smartscroll) + printf("\x1b[2;%dr", screenheight); + pos(0, 0); screenheight--; /* status line */ 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 new file mode 100644 index 0000000000..21d88bf1cb --- /dev/null +++ b/commands/ethlog.c @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: (c) 2022 Pengutronix, +// Oleksij Rempel <o.rempel@pengutronix.de> + +#include <common.h> +#include <command.h> +#include <complete.h> +#include <environment.h> +#include <getopt.h> +#include <net.h> + +static void ethlog_rx_monitor(struct eth_device *edev, void *packet, + int length) +{ + dev_print_hex_dump(&edev->dev, KERN_DEBUG, "rx data <: ", + DUMP_PREFIX_OFFSET, 16, 1, packet, length, true); + printk("\n"); +} + +static void ethlog_tx_monitor(struct eth_device *edev, void *packet, + int length) +{ + dev_print_hex_dump(&edev->dev, KERN_DEBUG, "tx data >: ", + DUMP_PREFIX_OFFSET, 16, 1, packet, length, true); + printk("\n"); +} + +static int do_ethlog(int argc, char *argv[]) +{ + struct eth_device *edev; + const char *edevname; + bool remove = false, promisc = false; + int opt, ret; + + while ((opt = getopt(argc, argv, "pr")) > 0) { + switch (opt) { + case 'p': + promisc = true; + break; + case 'r': + remove = true; + break; + default: + return COMMAND_ERROR_USAGE; + } + } + + if (optind == argc) + edevname = "eth0"; + else + edevname = argv[optind]; + + edev = eth_get_byname(edevname); + if (!edev) { + printf("No such network device: %s\n", edevname); + return 1; + } + + 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; + + return 0; +} + +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("[-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/fbtest.c b/commands/fbtest.c index 30d96f6af4..be1540d3d1 100644 --- a/commands/fbtest.c +++ b/commands/fbtest.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only + #include <common.h> #include <command.h> #include <errno.h> 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/hashsum.c b/commands/hashsum.c index bfacee0b92..308faa172a 100644 --- a/commands/hashsum.c +++ b/commands/hashsum.c @@ -74,7 +74,7 @@ BAREBOX_CMD_START(md5sum) BAREBOX_CMD_HELP(cmd_md5sum_help) BAREBOX_CMD_END -#endif /* CMD_CMD_MD5SUM */ +#endif /* CONFIG_CMD_MD5SUM */ #ifdef CONFIG_CMD_SHA1SUM @@ -95,7 +95,7 @@ BAREBOX_CMD_START(sha1sum) BAREBOX_CMD_HELP(cmd_sha1sum_help) BAREBOX_CMD_END -#endif /* CMD_CMD_SHA1SUM */ +#endif /* CONFIG_CMD_SHA1SUM */ #ifdef CONFIG_CMD_SHA224SUM @@ -116,7 +116,7 @@ BAREBOX_CMD_START(sha224sum) BAREBOX_CMD_HELP(cmd_sha224sum_help) BAREBOX_CMD_END -#endif /* CMD_CMD_SHA224SUM */ +#endif /* CONFIG_CMD_SHA224SUM */ #ifdef CONFIG_CMD_SHA256SUM @@ -137,7 +137,7 @@ BAREBOX_CMD_START(sha256sum) BAREBOX_CMD_HELP(cmd_sha256sum_help) BAREBOX_CMD_END -#endif /* CMD_CMD_SHA256SUM */ +#endif /* CONFIG_CMD_SHA256SUM */ #ifdef CONFIG_CMD_SHA384SUM @@ -158,7 +158,7 @@ BAREBOX_CMD_START(sha384sum) BAREBOX_CMD_HELP(cmd_sha384sum_help) BAREBOX_CMD_END -#endif /* CMD_CMD_SHA384SUM */ +#endif /* CONFIG_CMD_SHA384SUM */ #ifdef CONFIG_CMD_SHA512SUM @@ -179,4 +179,4 @@ BAREBOX_CMD_START(sha512sum) BAREBOX_CMD_HELP(cmd_sha512sum_help) BAREBOX_CMD_END -#endif /* CMD_CMD_SHA512SUM */ +#endif /* CONFIG_CMD_SHA512SUM */ diff --git a/commands/hwclock.c b/commands/hwclock.c index 1b5c2cd100..c594e070ac 100644 --- a/commands/hwclock.c +++ b/commands/hwclock.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only + #include <common.h> #include <command.h> #include <getopt.h> @@ -9,14 +11,6 @@ #include <string.h> #include <environment.h> -static char *strchrnul(const char *s, int c) -{ - while (*s != '\0' && *s != c) - s++; - - return (char *)s; -} - static int sscanf_two_digits(char *s, int *res) { char buf[3]; @@ -159,11 +153,9 @@ static int do_hwclock(int argc, char *argv[]) if (env_name) { unsigned long time; - char t[12]; rtc_tm_to_time(&tm, &time); - snprintf(t, 12, "%lu", time); - setenv(env_name, t); + pr_setenv(env_name, "%lu", time); } else { printf("%s\n", time_str(&tm)); } diff --git a/commands/hwmon.c b/commands/hwmon.c index ace4503c0b..04c3e728c6 100644 --- a/commands/hwmon.c +++ b/commands/hwmon.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only + #include <common.h> #include <command.h> #include <getopt.h> 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/insmod.c b/commands/insmod.c index 735dde0222..8f962b62d3 100644 --- a/commands/insmod.c +++ b/commands/insmod.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only + #include <common.h> #include <command.h> #include <module.h> diff --git a/commands/internal.h b/commands/internal.h index 21d1408c91..63c10af28e 100644 --- a/commands/internal.h +++ b/commands/internal.h @@ -1,2 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + int __do_digest(struct digest *d, unsigned char *sig, int argc, char *argv[]); 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 4f6a7ef190..40bcb7105d 100644 --- a/commands/keystore.c +++ b/commands/keystore.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only + #include <common.h> #include <command.h> #include <getopt.h> @@ -15,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/linux16.c b/commands/linux16.c deleted file mode 100644 index 73e402d877..0000000000 --- a/commands/linux16.c +++ /dev/null @@ -1,331 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// SPDX-FileCopyrightText: © 2009 Juergen Beisert, Pengutronix - -/* - * In parts from the GRUB2 project: - * - * GRUB -- GRand Unified Bootloader - * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2007,2008 Free Software Foundation, Inc. - */ - -#include <common.h> -#include <command.h> -#include <environment.h> -#include <fs.h> -#include <errno.h> -#include <libfile.h> -#include <getopt.h> -#include <malloc.h> -#include <boot.h> -#include <asm/syslib.h> - -/** FIXME */ -#define LINUX_MAGIC_SIGNATURE 0x53726448 /* "HdrS" */ - -/** FIXME */ -#define LINUX_FLAG_BIG_KERNEL 0x1 - -/** FIXME */ -#define LINUX_BOOT_LOADER_TYPE 0x72 - -/** FIXME */ -#define LINUX_DEFAULT_SETUP_SECTS 4 - -/** FIXME */ -#define LINUX_MAX_SETUP_SECTS 64 - -/** FIXME */ -#define LINUX_OLD_REAL_MODE_SEGMT 0x9000 - -/** FIXME */ -#define LINUX_OLD_REAL_MODE_ADDR (LINUX_OLD_REAL_MODE_SEGMT << 4) - -/** FIXME */ -#define LINUX_HEAP_END_OFFSET (LINUX_OLD_REAL_MODE_SEGMT - 0x200) - -/** FIXME */ -#define LINUX_FLAG_CAN_USE_HEAP 0x80 - -/** Define kernel command lines's start offset in the setup segment */ -#define LINUX_CL_OFFSET 0x9000 - -/** Define kernel command lines's end offset */ -#define LINUX_CL_END_OFFSET 0x90FF - -/** FIXME */ -#define LINUX_CL_MAGIC 0xA33F - -/** FIXME */ -#define LINUX_SETUP_MOVE_SIZE 0x9100 - -/** Sector size */ -#define DISK_SECTOR_BITS 9 -#define DISK_SECTOR_SIZE 0x200 - -/** Where to load a bzImage */ -#define LINUX_BZIMAGE_ADDR 0x100000 - -struct linux_kernel_header { - /* first sector of the image */ - uint8_t code1[0x0020]; - uint16_t cl_magic; /**< Magic number 0xA33F */ - uint16_t cl_offset; /**< The offset of command line */ - uint8_t code2[0x01F1 - 0x0020 - 2 - 2]; - uint8_t setup_sects; /**< The size of the setup in sectors */ - uint16_t root_flags; /**< If the root is mounted readonly */ - uint16_t syssize; /**< obsolete */ - uint16_t swap_dev; /**< obsolete */ - uint16_t ram_size; /**< obsolete */ - uint16_t vid_mode; /**< Video mode control */ - uint16_t root_dev; /**< Default root device number */ - uint16_t boot_flag; /**< 0xAA55 magic number */ - - /* second sector of the image */ - uint16_t jump; /**< Jump instruction (this is code!) */ - uint32_t header; /**< Magic signature "HdrS" */ - uint16_t version; /**< Boot protocol version supported */ - uint32_t realmode_swtch; /**< Boot loader hook */ - uint16_t start_sys; /**< The load-low segment (obsolete) */ - uint16_t kernel_version; /**< Points to kernel version string */ - uint8_t type_of_loader; /**< Boot loader identifier */ -#define LINUX_LOADER_ID_LILO 0x0 -#define LINUX_LOADER_ID_LOADLIN 0x1 -#define LINUX_LOADER_ID_BOOTSECT 0x2 -#define LINUX_LOADER_ID_SYSLINUX 0x3 -#define LINUX_LOADER_ID_ETHERBOOT 0x4 -#define LINUX_LOADER_ID_ELILO 0x5 -#define LINUX_LOADER_ID_GRUB 0x7 -#define LINUX_LOADER_ID_UBOOT 0x8 -#define LINUX_LOADER_ID_XEN 0x9 -#define LINUX_LOADER_ID_GUJIN 0xa -#define LINUX_LOADER_ID_QEMU 0xb - uint8_t loadflags; /**< Boot protocol option flags */ - uint16_t setup_move_size; /**< Move to high memory size */ - uint32_t code32_start; /**< Boot loader hook */ - uint32_t ramdisk_image; /**< initrd load address */ - uint32_t ramdisk_size; /**< initrd size */ - uint32_t bootsect_kludge; /**< obsolete */ - uint16_t heap_end_ptr; /**< Free memory after setup end */ - uint8_t ext_loader_ver; /**< boot loader's extension of the version number */ - uint8_t ext_loader_type; /**< boot loader's extension of its type */ - char *cmd_line_ptr; /**< Points to the kernel command line */ - uint32_t initrd_addr_max; /**< Highest address for initrd */ -#if 0 - /* for the records only. These members are defined in - * more recent Linux kernels - */ - uint32_t kernel_alignment; /**< Alignment unit required by the kernel */ - uint8_t relocatable_kernel; /** */ - uint8_t min_alignment; /** */ - uint32_t cmdline_size; /** */ - uint32_t hardware_subarch; /** */ - uint64_t hardware_subarch_data; /** */ - uint32_t payload_offset; /** */ - uint32_t payload_length; /** */ - uint64_t setup_data; /** */ - uint64_t pref_address; /** */ - uint32_t init_size; /** */ -#endif -} __attribute__ ((packed)); - -/* This is -1. Keep this value in sync with the kernel */ -#define NORMAL_VGA 0xffff /* 80x25 mode */ -#define ASK_VGA 0xfffd /* ask for it at bootup */ - -/** - * Load an x86 Linux kernel bzImage and start it - * @param argc parameter count - * @param argv list of parameter - * - * Loads an x86 bzImage, checks for its integrity, stores the two parts - * (setup = 'real mode code' and kernel = 'protected mode code') to their - * default locations, switches back to real mode and runs the setup code. - */ -static int do_linux16(int argc, char *argv[]) -{ - struct linux_kernel_header *lh = NULL; - int rc, opt; - unsigned setup_sects; - unsigned real_mode_size; - int vid_mode = NORMAL_VGA; - size_t image_size; - const char *cmdline = linux_bootargs_get(); - const char *kernel_file; - - while((opt = getopt(argc, argv, "v:")) > 0) { - switch(opt) { - case 'v': - vid_mode = simple_strtoul(optarg, NULL, 0); - if (vid_mode == 0) { - if (!strcmp(optarg, "ask")) - vid_mode = ASK_VGA; - else { - printf("Unknown video mode: %s\n", optarg); - return 1; - } - } - break; - default: - return COMMAND_ERROR_USAGE; - } - } - - if (optind == argc) { - printf("No kernel filename given\n"); - return 1; - } - kernel_file = argv[optind]; - - lh = read_file(kernel_file, &image_size); - if (lh == NULL) { - printf("Cannot read file '%s'\n", argv[1]); - return 1; - } - - if (lh->boot_flag != 0xaa55) { - printf("File '%s' has invalid magic number\n", argv[1]); - rc = 1; - goto on_error; - } - - if (lh->setup_sects > LINUX_MAX_SETUP_SECTS) { - printf("File '%s' contains too many setup sectors\n", argv[1]); - rc = 1; - goto on_error; - } - - setup_sects = lh->setup_sects; - - printf("Found a %d.%d image header\n", lh->version >> 8, lh->version & 0xFF); - - if (lh->header == LINUX_MAGIC_SIGNATURE && lh->version >= 0x0200) { - /* kernel is recent enough */ - ; - if (!(lh->loadflags & LINUX_FLAG_BIG_KERNEL)) { - printf("Cannot load a classic zImage. Use a bzImage instead\n"); - goto on_error; - } - lh->type_of_loader = LINUX_BOOT_LOADER_TYPE; /* TODO */ - - if (lh->version >= 0x0201) { - lh->heap_end_ptr = LINUX_HEAP_END_OFFSET; - lh->loadflags |= LINUX_FLAG_CAN_USE_HEAP; - } - - if (lh->version >= 0x0202) - lh->cmd_line_ptr = (void*)(LINUX_OLD_REAL_MODE_ADDR + LINUX_CL_OFFSET); /* FIXME */ - else { - lh->cl_magic = LINUX_CL_MAGIC; - lh->cl_offset = LINUX_CL_OFFSET; - lh->setup_move_size = LINUX_SETUP_MOVE_SIZE; - } - } else { - printf("Kernel too old to handle\n"); - rc = 1; - goto on_error; - } - - if (strlen(cmdline) >= (LINUX_CL_END_OFFSET - LINUX_CL_OFFSET)) { - printf("Kernel command line exceeds the available space\n"); - rc = 1; - goto on_error; - } - - /* - * The kernel does not check for the "vga=<val>" kernel command line - * parameter anymore. It expects this kind of information in the - * boot parameters instead. - */ - if (vid_mode != NORMAL_VGA) - lh->vid_mode = vid_mode; - - /* If SETUP_SECTS is not set, set it to the default. */ - if (setup_sects == 0) { - printf("Fixing setup sector count\n"); - setup_sects = LINUX_DEFAULT_SETUP_SECTS; - } - - if (setup_sects >= 15) { - void *src = lh; - if (lh->kernel_version != 0) - printf("Kernel version: '%s'\n", - (char *)src + lh->kernel_version + DISK_SECTOR_SIZE); - } - - /* - * Size of the real mode part to handle in a separate way - */ - real_mode_size = (setup_sects << DISK_SECTOR_BITS) + DISK_SECTOR_SIZE; - - /* - * real mode space hole extended memory - * |---------------------------------------------->|----------->|------------------------------> - * 0 0xa0000 0x100000 - * <-1-|----------2-----------><-3- | - * 0x7e00 0x90000 - * <-4--|-5--> |---------6-------------> - * - * 1) real mode stack - * 2) barebox code - * 3) flat mode stack - * 4) realmode stack when starting a Linux kernel - * 5) Kernel's real mode setup code - * 6) compressed kernel image - */ - /* - * Parts of the image we know: - * - real mode part - * - kernel payload - */ - /* - * NOTE: This part is dangerous, as it copies some image content to - * various locations in the main memory. This could overwrite important - * data of the running barebox (hopefully not) - */ - /* copy the real mode part of the image to the 9th segment */ - memcpy((void*)LINUX_OLD_REAL_MODE_ADDR, lh, LINUX_SETUP_MOVE_SIZE); - - /* TODO add 'BOOT_IMAGE=<file>' and 'auto' if no user intervention was done (in front of all other params) */ - /* copy also the command line into this area */ - memcpy((void*)(LINUX_OLD_REAL_MODE_ADDR + LINUX_CL_OFFSET), cmdline, strlen(cmdline) + 1); - printf("Using kernel command line: '%s'\n", cmdline); - - /* copy the compressed image part to its final address the setup code expects it - * Note: The protected mode part starts at offset (setup_sects + 1) * 512 - */ - memcpy((void*)LINUX_BZIMAGE_ADDR, ((void*)lh) + real_mode_size, image_size - real_mode_size); - - /* - * switch back to real mode now and start the real mode part of the - * image at address "(LINUX_OLD_REAL_MODE_ADDR >> 4) + 0x20:0x0000" - * which means "0x9020:0x000" -> 0x90200 - */ - bios_start_linux(LINUX_OLD_REAL_MODE_SEGMT); /* does not return */ - -on_error: - if (lh != NULL) - free(lh); - - return rc; -} - -BAREBOX_CMD_HELP_START(linux16) -BAREBOX_CMD_HELP_TEXT("Load kernel from FILE and boot on x86 in real-mode.") -BAREBOX_CMD_HELP_TEXT("") -BAREBOX_CMD_HELP_TEXT("Only kernel images in bzImage format are supported by now.") -BAREBOX_CMD_HELP_TEXT("") -BAREBOX_CMD_HELP_TEXT("For the video mode refer the Linux kernel documentation") -BAREBOX_CMD_HELP_TEXT("'Documentation/fb/vesafb.txt' for correct VESA mode numbers. Use 'ask'") -BAREBOX_CMD_HELP_TEXT("instead of a number to make Linux for options..") -BAREBOX_CMD_HELP_TEXT("") -BAREBOX_CMD_HELP_TEXT("Options:") -BAREBOX_CMD_HELP_OPT ("-v VESAMODE", "set VESAMODE") -BAREBOX_CMD_HELP_END - -BAREBOX_CMD_START(linux16) - .cmd = do_linux16, - BAREBOX_CMD_DESC("boot a linux kernel on x86 via real-mode code") - BAREBOX_CMD_OPTS("[-v VESAMODE] FILE") - BAREBOX_CMD_GROUP(CMD_GRP_BOOT) - BAREBOX_CMD_HELP(cmd_linux16_help) -BAREBOX_CMD_END diff --git a/commands/loadb.c b/commands/loadb.c index 17d3af84b5..140d3743f6 100644 --- a/commands/loadb.c +++ b/commands/loadb.c @@ -542,7 +542,6 @@ packet_error: static ulong load_serial_bin(void) { int size, i; - char buf[32]; /* Try to allocate the buffer we shall write to files */ write_buffer = malloc(MAX_WRITE_BUFFER); @@ -576,8 +575,7 @@ static ulong load_serial_bin(void) write_idx = 0; } printf("## Total Size = 0x%08x = %d Bytes\n", size, size); - sprintf(buf, "%X", size); - setenv("filesize", buf); + pr_setenv("filesize", "%X", size); err_quit: free(write_buffer); @@ -648,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/loads.c b/commands/loads.c index 8260673c51..7c5df31251 100644 --- a/commands/loads.c +++ b/commands/loads.c @@ -65,7 +65,6 @@ static ulong load_serial(ulong offset) int type; /* return code for record type */ ulong addr; /* load address from S-Record */ ulong size; /* number of bytes transferred */ - char buf[32]; ulong store_addr; ulong start_addr = ~0; ulong end_addr = 0; @@ -100,8 +99,7 @@ static ulong load_serial(ulong offset) "## Total Size = 0x%08lX = %ld Bytes\n", start_addr, end_addr, size, size ); - sprintf(buf, "%lX", size); - setenv("filesize", buf); + pr_setenv("filesize", "%lX", size); return addr; case SREC_START: break; 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 bedf2e1c42..09a20e0a23 100644 --- a/commands/ls.c +++ b/commands/ls.c @@ -63,10 +63,10 @@ int ls(const char *path, ulong flags) if (stat(path, &s)) return -errno; - if (flags & LS_SHOWARG && s.st_mode & S_IFDIR) + if (flags & LS_SHOWARG && S_ISDIR(s.st_mode)) printf("%s:\n", path); - if (!(s.st_mode & S_IFDIR)) { + if (!S_ISDIR(s.st_mode)) { ls_one(path, path); return 0; } @@ -112,7 +112,7 @@ int ls(const char *path, ulong flags) continue; } - if (s.st_mode & S_IFDIR) + if (S_ISDIR(s.st_mode)) ls(tmp, flags); } @@ -164,14 +164,13 @@ 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; } - if (!(s.st_mode & S_IFDIR)) { + if (!S_ISDIR(s.st_mode)) { if (flags & LS_COLUMN) string_list_add_sorted(&sl, argv[o]); else @@ -197,7 +196,7 @@ static int do_ls(int argc, char *argv[]) continue; } - if (s.st_mode & S_IFDIR) { + if (S_ISDIR(s.st_mode)) { ret = ls(argv[o], flags); if (ret) { perror("ls"); diff --git a/commands/lsmod.c b/commands/lsmod.c index 711c1c66dc..3d7ce40430 100644 --- a/commands/lsmod.c +++ b/commands/lsmod.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only + #include <common.h> #include <command.h> #include <complete.h> diff --git a/commands/magicvar.c b/commands/magicvar.c index 8740784ed2..01acc741ac 100644 --- a/commands/magicvar.c +++ b/commands/magicvar.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only + #include <common.h> #include <command.h> #include <getopt.h> diff --git a/commands/md.c b/commands/md.c index ef6a1e1bc0..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) { @@ -59,7 +61,7 @@ static int do_mem_md(int argc, char *argv[]) goto out; } - buf = xmalloc(RW_BUF_SIZE); + buf = xzalloc(RW_BUF_SIZE + 7); do { now = min(size, (loff_t)RW_BUF_SIZE); @@ -88,7 +90,7 @@ out: BAREBOX_CMD_HELP_START(md) -BAREBOX_CMD_HELP_TEXT("Display (hex dump) a memory region.") +BAREBOX_CMD_HELP_TEXT("Display (hex dump) a memory REGION.") BAREBOX_CMD_HELP_TEXT("") BAREBOX_CMD_HELP_TEXT("Options:") BAREBOX_CMD_HELP_OPT ("-b", "byte access") @@ -108,7 +110,7 @@ BAREBOX_CMD_HELP_END BAREBOX_CMD_START(md) .cmd = do_mem_md, BAREBOX_CMD_DESC("memory display") - BAREBOX_CMD_OPTS("[-bwlsx] REGION") + BAREBOX_CMD_OPTS("[-bwlqx] [-s FILE] REGION") BAREBOX_CMD_GROUP(CMD_GRP_MEM) BAREBOX_CMD_HELP(cmd_md_help) BAREBOX_CMD_END diff --git a/commands/memcmp.c b/commands/memcmp.c index 2b3783d66a..8122b99f17 100644 --- a/commands/memcmp.c +++ b/commands/memcmp.c @@ -97,7 +97,7 @@ BAREBOX_CMD_HELP_END BAREBOX_CMD_START(memcmp) .cmd = do_memcmp, BAREBOX_CMD_DESC("memory compare") - BAREBOX_CMD_OPTS("[-bwlsd] ADDR1 ADDR2 COUNT") + BAREBOX_CMD_OPTS("[-bwlq] [-s FILE] [-d FILE] ADDR1 ADDR2 COUNT") BAREBOX_CMD_GROUP(CMD_GRP_MEM) BAREBOX_CMD_HELP(cmd_memcmp_help) BAREBOX_CMD_END diff --git a/commands/memcpy.c b/commands/memcpy.c index 2477bba359..1b480f27f0 100644 --- a/commands/memcpy.c +++ b/commands/memcpy.c @@ -72,7 +72,9 @@ out: } BAREBOX_CMD_HELP_START(memcpy) -BAREBOX_CMD_HELP_TEXT("Copy memory at SRC of COUNT bytes to DEST") +BAREBOX_CMD_HELP_TEXT("Copy memory of COUNT bytes from offsets SRC to DEST.") +BAREBOX_CMD_HELP_TEXT("If source is a file, COUNT can be left unspecified") +BAREBOX_CMD_HELP_TEXT("in which case the whole file is copied.") BAREBOX_CMD_HELP_TEXT("") BAREBOX_CMD_HELP_TEXT("Options:") BAREBOX_CMD_HELP_OPT ("-b", "byte access") @@ -86,7 +88,7 @@ BAREBOX_CMD_HELP_END BAREBOX_CMD_START(memcpy) .cmd = do_memcpy, BAREBOX_CMD_DESC("memory copy") - BAREBOX_CMD_OPTS("[-bwlsd] SRC DEST COUNT") + BAREBOX_CMD_OPTS("[-bwlq] [-s FILE] [-d FILE] SRC DEST COUNT") BAREBOX_CMD_GROUP(CMD_GRP_MEM) BAREBOX_CMD_HELP(cmd_memcpy_help) BAREBOX_CMD_END diff --git a/commands/memset.c b/commands/memset.c index 716cba26de..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); @@ -84,7 +86,7 @@ BAREBOX_CMD_HELP_END BAREBOX_CMD_START(memset) .cmd = do_memset, BAREBOX_CMD_DESC("memory fill") - BAREBOX_CMD_OPTS("[-bwld] ADDR DATA COUNT") + BAREBOX_CMD_OPTS("[-bwlq [-d FILE] ADDR DATA COUNT") BAREBOX_CMD_GROUP(CMD_GRP_MEM) BAREBOX_CMD_HELP(cmd_memset_help) BAREBOX_CMD_END 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/memtester/Makefile b/commands/memtester/Makefile index 17a2429276..b410813af7 100644 --- a/commands/memtester/Makefile +++ b/commands/memtester/Makefile @@ -1 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0-only + obj-y += tests.o memtester.o diff --git a/commands/memtester/memtester.c b/commands/memtester/memtester.c index 130dc97c83..f4adbfc855 100644 --- a/commands/memtester/memtester.c +++ b/commands/memtester/memtester.c @@ -113,7 +113,7 @@ static int do_memtester(int argc, char **argv) { strerror(errno)); return COMMAND_ERROR_USAGE; } else { - if (!S_ISCHR(statbuf.st_mode)) { + if (!S_ISCHR(statbuf.st_mode) && !S_ISBLK(statbuf.st_mode)) { printf("can not mmap non-char device %s\n", optarg); return COMMAND_ERROR_USAGE; 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/mipi_dbi.c b/commands/mipi_dbi.c new file mode 100644 index 0000000000..b9b665b721 --- /dev/null +++ b/commands/mipi_dbi.c @@ -0,0 +1,104 @@ +// SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: © 2022 Ahmad Fatoum + +#include <common.h> +#include <command.h> +#include <getopt.h> +#include <video/mipi_dbi.h> +#include <video/mipi_display.h> + +static int mipi_dbi_command_show(struct mipi_dbi *dbi, int cmd) +{ + u8 val[4]; + int ret; + size_t len; + + if (!mipi_dbi_command_is_read(dbi, cmd)) + return -EACCES; + + len = mipi_dbi_command_read_len(cmd); + + printf("%02x: ", cmd); + ret = mipi_dbi_command_buf(dbi, cmd, val, len); + if (ret) { + printf("XX\n"); + return ret; + } + printf("%*phN\n", (int)len, val); + + return 0; +} + +static int do_mipi_dbi(int argc, char *argv[]) +{ + struct mipi_dbi *dbi; + int opt, ret, i; + bool write = false; + u8 cmd, val[4]; + + dbi = list_first_entry_or_null(&mipi_dbi_list, struct mipi_dbi, list); + + while ((opt = getopt(argc, argv, "wld:")) > 0) { + struct mipi_dbi *tmp; + + switch (opt) { + case 'w': + write = true; + break; + case 'l': + list_for_each_entry(tmp, &mipi_dbi_list, list) + printf("%s\n", mipi_dbi_name(tmp)); + return 0; + case 'd': + dbi = NULL; + list_for_each_entry(tmp, &mipi_dbi_list, list) { + if (!strcmp(optarg, mipi_dbi_name(tmp))) { + dbi = tmp; + break; + } + } + break; + default: + return COMMAND_ERROR_USAGE; + } + } + + if (!dbi) + return -ENODEV; + + if (optind == argc) { + for (cmd = 0; cmd < 255; cmd++) + mipi_dbi_command_show(dbi, cmd); + return 0; + } + + ret = kstrtou8(argv[optind++], 16, &cmd); + if (ret < 0) + return ret; + + if (optind == argc && !write) + return mipi_dbi_command_show(dbi, cmd); + + for (i = optind; i < argc; i++) { + ret = kstrtou8(argv[optind + i], 16, &val[i]); + if (ret < 0) + return ret; + } + + return mipi_dbi_command_buf(dbi, cmd, val, argc - optind); +} + +BAREBOX_CMD_HELP_START(mipi_dbi) +BAREBOX_CMD_HELP_TEXT("Options:") +BAREBOX_CMD_HELP_OPT ("-l\t", "list all MIPI DBI devices") +BAREBOX_CMD_HELP_OPT ("-d DEVICE", "select specific device (default is first registered)") +BAREBOX_CMD_HELP_OPT ("-w", "issue write command") +BAREBOX_CMD_HELP_END + +BAREBOX_CMD_START(mipi_dbi) + .cmd = do_mipi_dbi, + BAREBOX_CMD_DESC("write/read from MIPI DBI SPI device") + BAREBOX_CMD_OPTS("[-wld] [REG] [DATA...]") + BAREBOX_CMD_GROUP(CMD_GRP_HWMANIP) + BAREBOX_CMD_HELP(cmd_mipi_dbi_help) +BAREBOX_CMD_END 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 f6d66320fb..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); @@ -116,7 +118,7 @@ BAREBOX_CMD_HELP_END BAREBOX_CMD_START(mm) .cmd = do_mem_mm, BAREBOX_CMD_DESC("memory modify with mask") - BAREBOX_CMD_OPTS("[-bwld] ADDR VAL MASK") + BAREBOX_CMD_OPTS("[-bwlq] [-d FILE] ADDR VAL MASK") BAREBOX_CMD_GROUP(CMD_GRP_MEM) BAREBOX_CMD_HELP(cmd_mm_help) BAREBOX_CMD_END diff --git a/commands/mmc.c b/commands/mmc.c index c696e7b881..fa01b89cdf 100644 --- a/commands/mmc.c +++ b/commands/mmc.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only + #include <command.h> #include <mci.h> #include <stdio.h> @@ -63,23 +65,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[]) { @@ -93,6 +78,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; } @@ -145,6 +131,95 @@ error: 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; + } + } + + free(ext_csd); + + return COMMAND_SUCCESS; + +error: + 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[]); @@ -152,6 +227,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, } }; @@ -186,11 +267,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 5bd4bdd58f..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; @@ -110,12 +112,17 @@ BAREBOX_CMD_HELP_OPT ("-l", "long access (32 bit)") BAREBOX_CMD_HELP_OPT ("-q", "quad access (64 bit)") BAREBOX_CMD_HELP_OPT ("-d FILE", "write file (default /dev/mem)") BAREBOX_CMD_HELP_OPT ("-x", "swap bytes") +BAREBOX_CMD_HELP_TEXT("") +BAREBOX_CMD_HELP_TEXT("Memory regions can be specified in two different forms: START+SIZE") +BAREBOX_CMD_HELP_TEXT("or START-END, If START is omitted it defaults to 0x100") +BAREBOX_CMD_HELP_TEXT("Sizes can be specified as decimal, or if prefixed with 0x as hexadecimal.") +BAREBOX_CMD_HELP_TEXT("An optional suffix of k, M or G is for kbytes, Megabytes or Gigabytes.") BAREBOX_CMD_HELP_END BAREBOX_CMD_START(mw) .cmd = do_mem_mw, BAREBOX_CMD_DESC("memory write") - BAREBOX_CMD_OPTS("[-bwldx] REGION DATA...") + BAREBOX_CMD_OPTS("[-bwlqx] [-d FILE] REGION DATA...") BAREBOX_CMD_GROUP(CMD_GRP_MEM) BAREBOX_CMD_HELP(cmd_mw_help) BAREBOX_CMD_END 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/nandtest.c b/commands/nandtest.c index bfe4c4c0ed..4a7db9cc74 100644 --- a/commands/nandtest.c +++ b/commands/nandtest.c @@ -169,8 +169,10 @@ static int erase_and_write(loff_t ofs, unsigned char *data, printf("\ncompare failed. seed %d\n", seed); for (i = 0; i < meminfo.erasesize; i++) { if (data[i] != rbuf[i]) - printf("Byte 0x%x is %02x should be %02x\n", - i, rbuf[i], data[i]); + printf("Block 0x%llx byte 0x%0x (page 0x%x offset 0x%x) is %02x should be %02x\n", + div64_ul(ofs, meminfo.erasesize), i, + i / meminfo.writesize, i % meminfo.writesize, + rbuf[i], data[i]); } return ret; } @@ -178,12 +180,14 @@ static int erase_and_write(loff_t ofs, unsigned char *data, } /* Print stats of nandtest. */ -static void print_stats(int nr_passes, int length) +static void print_stats(int nr_passes, loff_t length) { unsigned int i; + uint64_t blocks = (uint64_t)length; + + do_div(blocks, meminfo.erasesize); printf("-------- Summary --------\n"); - printf("Tested blocks : %d\n", (length/meminfo.erasesize) - * nr_passes); + printf("Tested blocks : %lld\n", blocks * nr_passes); for (i = 0; i < MAX_ECC_BITS; i++) printf("ECC %d bit error(s) : %u\n", i + 1, ecc_stats[i]); diff --git a/commands/nvmem.c b/commands/nvmem.c new file mode 100644 index 0000000000..a0e3d092e3 --- /dev/null +++ b/commands/nvmem.c @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: GPL-2.0 +// SPDX-FileCopyrightText: © 2021 Ahmad Fatoum, Pengutronix + +#include <common.h> +#include <command.h> +#include <linux/nvmem-consumer.h> + +static int do_nvmem(int argc, char *argv[]) +{ + nvmem_devices_print(); + + return 0; +} + +BAREBOX_CMD_HELP_START(nvmem) +BAREBOX_CMD_HELP_TEXT("Usage: nvmem") +BAREBOX_CMD_HELP_END + +BAREBOX_CMD_START(nvmem) + .cmd = do_nvmem, + BAREBOX_CMD_DESC("list nvmem devices") + BAREBOX_CMD_GROUP(CMD_GRP_HWMANIP) + BAREBOX_CMD_HELP(cmd_nvmem_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 ec039776cf..623b033c73 100644 --- a/commands/of_diff.c +++ b/commands/of_diff.c @@ -16,74 +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_copy_node(NULL, 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_copy_node(NULL, 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); - - 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); - of_diff(a, b, 0); + if (!IS_ERR(a) && !IS_ERR(b)) + ret = of_diff(a, b, 0) ? COMMAND_ERROR : COMMAND_SUCCESS; - ret = 0; -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; @@ -93,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 27b91f311a..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); - - free(fdt); - + root = of_read_file(dtbfile); if (IS_ERR(root)) return PTR_ERR(root); - } else { root = of_get_root_node(); } @@ -98,9 +78,9 @@ static int do_of_display_timings(int argc, char *argv[]) int found = 0; const char *node = "display-timings"; - for_each_node_by_name_from(display, root, node) { + 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; } } @@ -113,13 +93,13 @@ static int do_of_display_timings(int argc, char *argv[]) int found = 0; const char *node = "display-timings"; - for_each_node_by_name_from(display, root, node) { + for_each_node_by_name_address_from(display, root, node) { timings = of_parse_phandle_from(display, root, "native-mode", 0); 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 6792af3afc..2508d4ce11 100644 --- a/commands/of_dump.c +++ b/commands/of_dump.c @@ -21,10 +21,13 @@ 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) + list_for_each_entry(n, &node->children, parent_list) { + if (ctrlc()) + return; of_print_nodenames(n); + } } static int do_of_dump(int argc, char *argv[]) @@ -34,11 +37,11 @@ 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; - int names_only = 0; + unsigned maxpropsize = ~0; + int names_only = 0, properties_only = 0; - while ((opt = getopt(argc, argv, "Ff:n")) > 0) { + while ((opt = getopt(argc, argv, "Ff:npP:")) > 0) { switch (opt) { case 'f': dtbfile = optarg; @@ -49,6 +52,14 @@ static int do_of_dump(int argc, char *argv[]) case 'n': names_only = 1; break; + case 'p': + properties_only = 1; + break; + case 'P': + ret = kstrtouint(optarg, 0, &maxpropsize); + if (ret) + return ret; + break; default: return COMMAND_ERROR_USAGE; } @@ -60,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); - - 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); - - 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) { @@ -111,14 +94,15 @@ static int do_of_dump(int argc, char *argv[]) goto out; } - if (names_only) + if (names_only && !properties_only) of_print_nodenames(node); + else if (properties_only && !names_only) + of_print_properties(node, maxpropsize); else - of_print_nodes(node, 0); + of_print_nodes(node, 0, maxpropsize); out: - if (of_free) - of_delete_node(of_free); + of_delete_node(of_free); return ret; } @@ -128,12 +112,14 @@ BAREBOX_CMD_HELP_TEXT("Options:") BAREBOX_CMD_HELP_OPT ("-f dtb", "work on dtb instead of internal devicetree") BAREBOX_CMD_HELP_OPT ("-F", "return fixed devicetree") BAREBOX_CMD_HELP_OPT ("-n", "Print node names only, no properties") +BAREBOX_CMD_HELP_OPT ("-p", "Print properties only, no child nodes") +BAREBOX_CMD_HELP_OPT ("-P len", "print only len property bytes") BAREBOX_CMD_HELP_END BAREBOX_CMD_START(of_dump) .cmd = do_of_dump, BAREBOX_CMD_DESC("dump devicetree nodes") - BAREBOX_CMD_OPTS("[-fFn] [NODE]") + BAREBOX_CMD_OPTS("[-fFnpP] [NODE]") BAREBOX_CMD_GROUP(CMD_GRP_MISC) BAREBOX_CMD_COMPLETE(devicetree_file_complete) BAREBOX_CMD_HELP(cmd_of_dump_help) 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 aa4b6484ca..2013c4b278 100644 --- a/commands/of_overlay.c +++ b/commands/of_overlay.c @@ -10,45 +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 opt, ret; - struct fdt_header *fdt; + int ret; struct device_node *overlay; - const char *search_path = NULL; + bool live_tree = false; + int opt; - while ((opt = getopt(argc, argv, "S:")) > 0) { + while ((opt = getopt(argc, argv, "l")) > 0) { switch (opt) { - case 'S': - search_path = optarg; + case 'l': + live_tree = true; break; - default: - return COMMAND_ERROR_USAGE; } } if (argc != optind + 1) return COMMAND_ERROR_USAGE; - fdt = read_file(argv[optind], NULL); - 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); - free(fdt); + overlay = of_read_file(argv[optind]); if (IS_ERR(overlay)) return PTR_ERR(overlay); - if (search_path) { - ret = of_firmware_load_overlay(overlay, search_path); + 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); } - ret = of_register_overlay(overlay); if (ret) { printf("cannot apply oftree overlay: %s\n", strerror(-ret)); goto err; @@ -62,14 +63,21 @@ err: } 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("-S path", "load firmware using this search path") +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("[-S path] 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 3d5097165b..0c914c55c6 100644 --- a/commands/of_property.c +++ b/commands/of_property.c @@ -4,6 +4,7 @@ /* of_property.c - device tree property handling support */ #include <common.h> +#include <libfile.h> #include <environment.h> #include <fdt.h> #include <of.h> @@ -18,7 +19,7 @@ #include <init.h> #include <xfuncs.h> -static int of_parse_prop_cells(char * const *newval, int count, char *data, int *len) +static int of_parse_prop_cells(struct device_node *root, char * const *newval, int count, char *data, int *len) { char *cp; unsigned long tmp; /* holds converted values */ @@ -60,7 +61,7 @@ static int of_parse_prop_cells(char * const *newval, int count, char *data, int str = xzalloc(len + 1); strncpy(str, cp, len); - n = of_find_node_by_path_or_alias(NULL, str); + n = of_find_node_by_path_or_alias(root, str); if (!n) printf("Cannot find node '%s'\n", str); @@ -164,7 +165,7 @@ static int of_parse_prop_string(char * const *newval, int count, char *data, int * data: A bytestream to be placed in the property * len: The length of the resulting bytestream */ -static int of_parse_prop(char * const *newval, int count, char *data, int *len) +static int of_parse_prop(struct device_node *root, char * const *newval, int count, char *data, int *len) { char *newp; /* temporary newval char pointer */ @@ -177,7 +178,7 @@ static int of_parse_prop(char * const *newval, int count, char *data, int *len) switch (*newp) { case '<': - return of_parse_prop_cells(newval, count, data, len); + return of_parse_prop_cells(root, newval, count, data, len); case '[': return of_parse_prop_stream(newval, count, data, len); default: @@ -302,8 +303,12 @@ static int do_of_property(int argc, char *argv[]) int set = 0; int fixup = 0; char *path, *propname; + char *dtbfile = NULL; + int ret = 0; + struct fdt_header *fdt = NULL; + struct device_node *root = NULL; - while ((opt = getopt(argc, argv, "dsf")) > 0) { + while ((opt = getopt(argc, argv, "dsfe:")) > 0) { switch (opt) { case 'd': delete = 1; @@ -314,6 +319,9 @@ static int do_of_property(int argc, char *argv[]) case 'f': fixup = 1; break; + case 'e': + dtbfile = optarg; + break; default: return COMMAND_ERROR_USAGE; } @@ -327,8 +335,16 @@ static int do_of_property(int argc, char *argv[]) debug("path: %s propname: %s\n", path, propname); + if ( !(set || delete)) + return COMMAND_ERROR_USAGE; + + if (dtbfile) { + root = of_read_file(dtbfile); + if (IS_ERR(root)) + return PTR_ERR(root); + } + if (set) { - int ret; int len; void *data; @@ -340,10 +356,10 @@ static int do_of_property(int argc, char *argv[]) if (!data) return -ENOMEM; - ret = of_parse_prop(&argv[optind + 2], argc - optind - 2, data, &len); + ret = of_parse_prop(root, &argv[optind + 2], argc - optind - 2, data, &len); if (ret) { free(data); - return ret; + goto out; } if (fixup) { @@ -351,21 +367,36 @@ static int do_of_property(int argc, char *argv[]) if (ret) free(data); } else { - ret = do_of_property_set_now(NULL, path, propname, data, len); + ret = do_of_property_set_now(root, path, propname, data, len); free(data); } - return ret; - } + if (ret) + goto out; - if (delete) { + } else if (delete) { if (fixup) - return do_of_property_delete_fixup(path, propname); + ret = do_of_property_delete_fixup(path, propname); else - return do_of_property_delete_now(NULL, path, propname); + ret = do_of_property_delete_now(root, path, propname); + + if (ret) + goto out; } - return COMMAND_ERROR_USAGE; + if (root && !fixup) { + fdt = of_flatten_dtb(root); + + ret = write_file(dtbfile, fdt, fdt32_to_cpu(fdt->totalsize)); + + free(fdt); + } + +out: + + of_delete_node(root); + + return ret; } BAREBOX_CMD_HELP_START(of_property) @@ -373,6 +404,7 @@ BAREBOX_CMD_HELP_TEXT("Options:") BAREBOX_CMD_HELP_OPT ("-s", "set property to value") BAREBOX_CMD_HELP_OPT ("-d", "delete property") BAREBOX_CMD_HELP_OPT ("-f", "set/delete as a fixup (defer the action until booting)") +BAREBOX_CMD_HELP_OPT ("-e dtb", "set/delete/fixup from external dtb") BAREBOX_CMD_HELP_TEXT("") BAREBOX_CMD_HELP_TEXT("Valid formats for values:") BAREBOX_CMD_HELP_TEXT("<0x00112233 4 05> - an array of cells. cells not beginning with a digit are") @@ -384,8 +416,8 @@ BAREBOX_CMD_HELP_END BAREBOX_CMD_START(of_property) .cmd = do_of_property, BAREBOX_CMD_DESC("handle device tree properties") - BAREBOX_CMD_OPTS("[-sd] [-f] NODE [PROPERTY] [VALUES]") + BAREBOX_CMD_OPTS("[-sd] [-e] [-f] NODE [PROPERTY] [VALUES]") BAREBOX_CMD_GROUP(CMD_GRP_MISC) - BAREBOX_CMD_COMPLETE(devicetree_complete) + BAREBOX_CMD_COMPLETE(devicetree_file_complete) BAREBOX_CMD_HELP(cmd_of_property_help) BAREBOX_CMD_END diff --git a/commands/oftree.c b/commands/oftree.c index 1d902f2830..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); - - 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/readf.c b/commands/readf.c index 8dd5a2b55a..d9d1b51243 100644 --- a/commands/readf.c +++ b/commands/readf.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only + #include <common.h> #include <command.h> #include <fs.h> diff --git a/commands/readline.c b/commands/readline.c index 403ac8563a..57c8fbd7bc 100644 --- a/commands/readline.c +++ b/commands/readline.c @@ -10,14 +10,16 @@ static int do_readline(int argc, char *argv[]) { - char *buf = xzalloc(CONFIG_CBSIZE); + char *buf; if (argc < 3) return COMMAND_ERROR_USAGE; + buf = xzalloc(CONFIG_CBSIZE); + command_slice_release(); - if (readline(argv[1], buf, CONFIG_CBSIZE) < 0) { + if (readline(argv[1], buf, CONFIG_CBSIZE - 1) < 0) { command_slice_acquire(); free(buf); return COMMAND_ERROR; 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 e1cd5dc548..44793ca56e 100644 --- a/commands/rmdir.c +++ b/commands/rmdir.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only + #include <common.h> #include <command.h> #include <fs.h> @@ -12,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 new file mode 100644 index 0000000000..bb62575aa7 --- /dev/null +++ b/commands/selftest.c @@ -0,0 +1,88 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#define pr_fmt(fmt) "selftest: " fmt + +#include <common.h> +#include <command.h> +#include <getopt.h> +#include <bselftest.h> +#include <complete.h> + +static int run_selftest(const char *match, bool list) +{ + struct selftest *test; + int matches = 0; + int err = 0; + + list_for_each_entry(test, &selftests, list) { + if (list) { + printf("%s\n", test->name); + matches++; + continue; + } + + if (match && strcmp(test->name, match)) + continue; + + err |= selftest_run(test); + matches++; + } + + if (!matches) { + if (match) { + printf("No tests matching '%s' found.\n", match); + return -EINVAL; + } + + printf("No tests found.\n"); + } + + return err; +} + +static int do_selftest(int argc, char *argv[]) +{ + bool list = false; + int i, err = 0; + int opt; + + while((opt = getopt(argc, argv, "l")) > 0) { + switch(opt) { + case 'l': + list = true; + break; + default: + return COMMAND_ERROR_USAGE; + } + } + + if (optind == argc) { + err = run_selftest(NULL, list); + } else { + for (i = optind; i < argc; i++) { + err = run_selftest(argv[i], list); + if (err) + goto out; + } + } + +out: + return err ? COMMAND_ERROR : COMMAND_SUCCESS; +} + +BAREBOX_CMD_HELP_START(selftest) +BAREBOX_CMD_HELP_TEXT("Run enabled barebox self-tests") +BAREBOX_CMD_HELP_TEXT("If run without arguments, all tests are run") +BAREBOX_CMD_HELP_TEXT("") +BAREBOX_CMD_HELP_TEXT("Options:") +BAREBOX_CMD_HELP_OPT ("-l", "list available tests") +BAREBOX_CMD_HELP_END + +BAREBOX_CMD_START(selftest) + .cmd = do_selftest, + BAREBOX_CMD_DESC("Run selftests") + BAREBOX_CMD_OPTS("[-l] [tests..]") + BAREBOX_CMD_GROUP(CMD_GRP_MISC) + BAREBOX_CMD_COMPLETE(empty_complete) + BAREBOX_CMD_HELP(cmd_selftest_help) +BAREBOX_CMD_END diff --git a/commands/smc.c b/commands/smc.c index 2a53e1b647..3143065582 100644 --- a/commands/smc.c +++ b/commands/smc.c @@ -9,14 +9,15 @@ #include <asm/psci.h> #include <asm/secure.h> +#include <asm/barebox-arm.h> #include <linux/arm-smccc.h> -#define STACK_SIZE 100 +#define HANDSHAKE_STACK_SIZE 100 #define HANDSHAKE_MAGIC 0xBA12EB0C #define ERROR_MAGIC 0xDEADBEEF struct cpu_context { - unsigned long stack[STACK_SIZE]; + unsigned long stack[HANDSHAKE_STACK_SIZE]; long handshake; }; @@ -35,12 +36,12 @@ static void noinline cpu_handshake(long *handshake) ; } -static void __naked second_entry(unsigned long arg0) +static void NAKED second_entry(unsigned long arg0) { struct cpu_context *context = (void*)arg0; arm_cpu_lowlevel_init(); - arm_setup_stack((unsigned long)&context->stack[STACK_SIZE]); + arm_setup_stack((unsigned long)&context->stack[HANDSHAKE_STACK_SIZE]); barrier(); cpu_handshake(&context->handshake); @@ -110,6 +111,11 @@ static int do_smc(int argc, char *argv[]) printf("found psci version %ld.%ld\n", res.a0 >> 16, res.a0 & 0xffff); break; case 'c': + if (IS_ENABLED(CONFIG_CPU_64)) { + printf("CPU bootstrap test not supported for ARMv8\n"); + return COMMAND_ERROR; + } + if (!context) context = dma_alloc_coherent(sizeof(*context), DMA_ADDRESS_BROKEN); diff --git a/commands/spd_decode.c b/commands/spd_decode.c index e8ee339a91..fa8fe86cf8 100644 --- a/commands/spd_decode.c +++ b/commands/spd_decode.c @@ -16,13 +16,12 @@ static int do_spd_decode(int argc, char *argv[]) { int ret; - size_t size; void *data; if (argc != 2) return COMMAND_ERROR_USAGE; - ret = read_file_2(argv[1], &size, &data, 256); + ret = read_file_2(argv[1], NULL, &data, 256); if (ret && ret != -EFBIG) { printf("unable to read %s: %s\n", argv[1], strerror(-ret)); return COMMAND_ERROR; diff --git a/commands/splash.c b/commands/splash.c index f1cc8c83bd..2eb7c5dc39 100644 --- a/commands/splash.c +++ b/commands/splash.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only + #include <common.h> #include <command.h> #include <errno.h> 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/state.c b/commands/state.c index e7cb9902f7..56ef93b19f 100644 --- a/commands/state.c +++ b/commands/state.c @@ -53,6 +53,9 @@ static int do_state(int argc, char *argv[]) ret = state_save(state); } + if (ret == -ENOMEDIUM) + ret = 0; + return ret; } 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 25ba2da15e..a3f2704071 100644 --- a/commands/time.c +++ b/commands/time.c @@ -1,29 +1,36 @@ +// SPDX-License-Identifier: GPL-2.0-only + #include <common.h> #include <command.h> #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; - unsigned long diff; - int len = 1; /* '\0' */ - - if (argc < 2) - return COMMAND_ERROR_USAGE; + bool nanoseconds = false; + + while ((opt = getopt(argc, argv, "+n")) > 0) { + switch (opt) { + case 'n': + nanoseconds = true; + break; + default: + return COMMAND_ERROR_USAGE; + } + } - for (i = 1; i < argc; i++) - len += strlen(argv[i]) + 1; + argv += optind; + argc -= optind; - buf = xzalloc(len); + if (argc < 1) + return COMMAND_ERROR_USAGE; - for (i = 1; i < argc; i++) { - strcat(buf, argv[i]); - strcat(buf, " "); - } + buf = strjoin(" ", argv, argc); start = get_time_ns(); @@ -33,11 +40,10 @@ static int do_time(int argc, char *argv[]) diff64 = end - start; - do_div(diff64, 1000000); - - diff = diff64; + if (!nanoseconds) + do_div(diff64, 1000000); - printf("time: %lums\n", diff); + printf("time: %llu%cs\n", diff64, nanoseconds ? 'n' : 'm'); free(buf); @@ -47,12 +53,14 @@ static int do_time(int argc, char *argv[]) BAREBOX_CMD_HELP_START(time) BAREBOX_CMD_HELP_TEXT("Note: This command depends on COMMAND being interruptible,") BAREBOX_CMD_HELP_TEXT("otherwise the 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(time) .cmd = do_time, BAREBOX_CMD_DESC("measure execution duration of a command") - BAREBOX_CMD_OPTS("COMMAND") + BAREBOX_CMD_OPTS("[-n] COMMAND") BAREBOX_CMD_GROUP(CMD_GRP_MISC) BAREBOX_CMD_HELP(cmd_time_help) BAREBOX_CMD_END 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 new file mode 100644 index 0000000000..afe5b66f0b --- /dev/null +++ b/commands/tutorial.c @@ -0,0 +1,157 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-FileCopyrightText: (c) 2021 Ahmad Fatoum + +#include <common.h> +#include <command.h> +#include <unistd.h> +#include <fcntl.h> +#include <complete.h> +#include <sys/stat.h> +#include <glob.h> +#include <getopt.h> +#include <magicvar.h> +#include <globalvar.h> + +static int next_step; +BAREBOX_MAGICVAR(global.tutorial.step, "Next tutorial step."); + +#define BUFSIZE 1024 + +static glob_t steps; + +static int register_tutorial_vars(void) +{ + char *oldcwd; + int ret = 0; + + oldcwd = pushd("/env/data/tutorial"); + if (!oldcwd) + return 0; + + ret = glob("*", 0, NULL, &steps); + if (ret) + goto out; + + ret = globalvar_add_simple_enum("tutorial.step", &next_step, + (const char **)steps.gl_pathv, steps.gl_pathc); + +out: + popd(oldcwd); + return ret; + +} +postenvironment_initcall(register_tutorial_vars); + +static int print_tutorial_step(const char *step) +{ + bool highlight = false; + int fd, ret, i; + char *buf; + + fd = open(step, O_RDONLY); + if (fd < 0) { + printf("could not open /env/data/tutorial/%s\n", step); + return -errno; + } + + buf = malloc(BUFSIZE); + if (!buf) { + ret = -ENOMEM; + goto out; + } + + printf("%s\n", step); + + while((ret = read(fd, buf, BUFSIZE)) > 0) { + for(i = 0; i < ret; i++) { + if (buf[i] != '`') { + putchar(buf[i]); + continue; + } + + puts(highlight ? "\e[0m" : "\e[1;31m"); + highlight = !highlight; + } + } + + free(buf); +out: + close(fd); + + return ret; +} + +static int do_tutorial_next(int argc, char *argv[]) +{ + int opt, i; + char *oldcwd; + ssize_t ret = 0; + bool is_prev = *argv[0] == 'p'; + + while ((opt = getopt(argc, argv, "rh")) > 0) { + switch (opt) { + case 'r': + if (steps.gl_pathc) { + globalvar_remove("tutorial.step"); + next_step = 0; + globfree(&steps); + steps.gl_pathc = 0; + } + ret = register_tutorial_vars(); + if (ret == 0 && steps.gl_pathc == 0) + ret = -ENOENT; + if (ret) + printf("could not load /env/data/tutorial/\n"); + return ret; + case 'h': + default: + return COMMAND_ERROR_USAGE; + } + } + + if (optind > argc + 1) + return COMMAND_ERROR_USAGE; + + oldcwd = pushd("/env/data/tutorial"); + if (!oldcwd) + return ret; + + if (is_prev) + next_step = next_step > 0 ? next_step - 1 : 0; + + if (optind == argc) { + 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++) { + ret = print_tutorial_step(argv[i]); + if (ret) + break; + } + } + + popd(oldcwd); + + return ret; +} + +BAREBOX_CMD_HELP_START(next) +BAREBOX_CMD_HELP_TEXT("Help navigate the barebox tutorial") +BAREBOX_CMD_HELP_TEXT("Without a parameter, the next or previous tutorial step is printed") +BAREBOX_CMD_HELP_TEXT("Options:") +BAREBOX_CMD_HELP_OPT("-h\t", "show usage text") +BAREBOX_CMD_HELP_OPT("-r\t", "rewind and reload tutorial") +BAREBOX_CMD_HELP_END + +static __maybe_unused const char *const prev_alias[] = { "prev", NULL}; + +BAREBOX_CMD_START(next) + .cmd = do_tutorial_next, + .aliases = prev_alias, + BAREBOX_CMD_DESC("navigate the barebox tutorial") + BAREBOX_CMD_OPTS("[-hr] [STEP]") + BAREBOX_CMD_HELP(cmd_next_help) + BAREBOX_CMD_GROUP(CMD_GRP_INFO) + BAREBOX_CMD_COMPLETE(tutorial_complete) +BAREBOX_CMD_END diff --git a/commands/ubi.c b/commands/ubi.c index f866f00160..6abd054af3 100644 --- a/commands/ubi.c +++ b/commands/ubi.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only + #include <common.h> #include <command.h> #include <fs.h> 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 fb4df780bd..72b827b5b2 100644 --- a/commands/uimage.c +++ b/commands/uimage.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only + #include <common.h> #include <command.h> #include <image.h> @@ -11,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 3b115f147d..e69660fde5 100644 --- a/commands/usbgadget.c +++ b/commands/usbgadget.c @@ -12,32 +12,35 @@ #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[]) { + struct usbgadget_funcs funcs = {}; int opt; - bool acm = false, dfu = false, fastboot = false, export_bbu = false; - const char *fastboot_opts = NULL, *dfu_opts = NULL; - while ((opt = getopt(argc, argv, "asdA::D::b")) > 0) { + while ((opt = getopt(argc, argv, "asdA::D::S::b")) > 0) { switch (opt) { case 'a': case 's': - acm = true; + funcs.flags |= USBGADGET_ACM; break; case 'D': - dfu = true; - dfu_opts = optarg; + funcs.flags |= USBGADGET_DFU; + funcs.dfu_opts = optarg; break; case 'A': - fastboot = true; - fastboot_opts = optarg; + funcs.flags |= USBGADGET_FASTBOOT; + funcs.fastboot_opts = optarg; + break; + case 'S': + funcs.flags |= USBGADGET_MASS_STORAGE; + funcs.ums_opts = optarg; break; case 'b': - export_bbu = true; + funcs.flags |= USBGADGET_EXPORT_BBU; break; case 'd': usb_multi_unregister(); @@ -47,8 +50,8 @@ static int do_usbgadget(int argc, char *argv[]) } } - return usbgadget_register(dfu, dfu_opts, fastboot, fastboot_opts, acm, - export_bbu); + + return usbgadget_register(&funcs); } BAREBOX_CMD_HELP_START(usbgadget) @@ -58,16 +61,19 @@ 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," + "fallback directly to 'global.system.partitions' variable.") BAREBOX_CMD_HELP_OPT ("-d\t", "Disable the currently running gadget") BAREBOX_CMD_HELP_END BAREBOX_CMD_START(usbgadget) .cmd = do_usbgadget, BAREBOX_CMD_DESC("Create USB Gadget multifunction device") - BAREBOX_CMD_OPTS("[-adAD]") + BAREBOX_CMD_OPTS("[-adADS]") BAREBOX_CMD_GROUP(CMD_GRP_HWMANIP) BAREBOX_CMD_HELP(cmd_usbgadget_help) BAREBOX_CMD_END 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; } diff --git a/commands/wd.c b/commands/wd.c index c186244b2b..11f888133a 100644 --- a/commands/wd.c +++ b/commands/wd.c @@ -18,11 +18,13 @@ static int do_wd(int argc, char *argv[]) int opt; int rc; - while ((opt = getopt(argc, argv, "d:")) > 0) { + while ((opt = getopt(argc, argv, "d:x")) > 0) { switch (opt) { case 'd': wd = watchdog_get_by_name(optarg); break; + case 'x': + return watchdog_inhibit_all(); default: return COMMAND_ERROR_USAGE; } @@ -66,12 +68,13 @@ BAREBOX_CMD_HELP_TEXT("When TIME is 0, the watchdog gets disabled,") BAREBOX_CMD_HELP_TEXT("Without a parameter the watchdog will be re-triggered.") BAREBOX_CMD_HELP_TEXT("Options:") BAREBOX_CMD_HELP_OPT("-d DEVICE\t", "watchdog name (default is highest priority watchdog)") +BAREBOX_CMD_HELP_OPT("-x\t", "inhibit all watchdogs (i.e. disable or autopoll if possible)") BAREBOX_CMD_HELP_END BAREBOX_CMD_START(wd) .cmd = do_wd, BAREBOX_CMD_DESC("enable/disable/trigger the watchdog") - BAREBOX_CMD_OPTS("[-d DEVICE] [TIME]") + BAREBOX_CMD_OPTS("[-d DEVICE] [-x] [TIME]") BAREBOX_CMD_GROUP(CMD_GRP_HWMANIP) BAREBOX_CMD_HELP(cmd_wd_help) BAREBOX_CMD_COMPLETE(device_complete) |