diff options
Diffstat (limited to 'cmd')
-rw-r--r-- | cmd/Kconfig | 214 | ||||
-rw-r--r-- | cmd/Makefile | 7 | ||||
-rw-r--r-- | cmd/bootmenu.c | 4 | ||||
-rw-r--r-- | cmd/button.c | 4 | ||||
-rw-r--r-- | cmd/fat.c | 43 | ||||
-rw-r--r-- | cmd/load.c | 44 | ||||
-rw-r--r-- | cmd/log.c | 352 | ||||
-rw-r--r-- | cmd/misc.c | 168 | ||||
-rw-r--r-- | cmd/mux.c | 184 | ||||
-rw-r--r-- | cmd/optee_rpmb.c | 272 | ||||
-rw-r--r-- | cmd/pstore.c | 544 | ||||
-rw-r--r-- | cmd/sleep.c | 57 | ||||
-rw-r--r-- | cmd/timer.c | 34 |
13 files changed, 1637 insertions, 290 deletions
diff --git a/cmd/Kconfig b/cmd/Kconfig index b25d2b02ed5..1595de999b5 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -66,123 +66,6 @@ config SYS_XTRACE To enable the tracer a variable "xtrace" needs to be defined in the environment. -menu "Autoboot options" - -config AUTOBOOT - bool "Autoboot" - default y - help - This enables the autoboot. See doc/README.autoboot for detail. - -config AUTOBOOT_KEYED - bool "Stop autobooting via specific input key / string" - default n - help - This option enables stopping (aborting) of the automatic - boot feature only by issuing a specific input key or - string. If not enabled, any input key will abort the - U-Boot automatic booting process and bring the device - to the U-Boot prompt for user input. - -config AUTOBOOT_PROMPT - string "Autoboot stop prompt" - depends on AUTOBOOT_KEYED - default "Autoboot in %d seconds\\n" - help - This string is displayed before the boot delay selected by - CONFIG_BOOTDELAY starts. If it is not defined there is no - output indicating that autoboot is in progress. - - Note that this define is used as the (only) argument to a - printf() call, so it may contain '%' format specifications, - provided that it also includes, sepearated by commas exactly - like in a printf statement, the required arguments. It is - the responsibility of the user to select only such arguments - that are valid in the given context. - -config AUTOBOOT_ENCRYPTION - bool "Enable encryption in autoboot stopping" - depends on AUTOBOOT_KEYED - help - This option allows a string to be entered into U-Boot to stop the - autoboot. The string itself is hashed and compared against the hash - in the environment variable 'bootstopkeysha256'. If it matches then - boot stops and a command-line prompt is presented. - - This provides a way to ship a secure production device which can also - be accessed at the U-Boot command line. - -config AUTOBOOT_DELAY_STR - string "Delay autobooting via specific input key / string" - depends on AUTOBOOT_KEYED && !AUTOBOOT_ENCRYPTION - help - This option delays the automatic boot feature by issuing - a specific input key or string. If CONFIG_AUTOBOOT_DELAY_STR - or the environment variable "bootdelaykey" is specified - and this string is received from console input before - autoboot starts booting, U-Boot gives a command prompt. The - U-Boot prompt will time out if CONFIG_BOOT_RETRY_TIME is - used, otherwise it never times out. - -config AUTOBOOT_STOP_STR - string "Stop autobooting via specific input key / string" - depends on AUTOBOOT_KEYED && !AUTOBOOT_ENCRYPTION - help - This option enables stopping (aborting) of the automatic - boot feature only by issuing a specific input key or - string. If CONFIG_AUTOBOOT_STOP_STR or the environment - variable "bootstopkey" is specified and this string is - received from console input before autoboot starts booting, - U-Boot gives a command prompt. The U-Boot prompt never - times out, even if CONFIG_BOOT_RETRY_TIME is used. - -config AUTOBOOT_KEYED_CTRLC - bool "Enable Ctrl-C autoboot interruption" - depends on AUTOBOOT_KEYED && !AUTOBOOT_ENCRYPTION - default n - help - This option allows for the boot sequence to be interrupted - by ctrl-c, in addition to the "bootdelaykey" and "bootstopkey". - Setting this variable provides an escape sequence from the - limited "password" strings. - -config AUTOBOOT_STOP_STR_SHA256 - string "Stop autobooting via SHA256 encrypted password" - depends on AUTOBOOT_KEYED && AUTOBOOT_ENCRYPTION - help - This option adds the feature to only stop the autobooting, - and therefore boot into the U-Boot prompt, when the input - string / password matches a values that is encypted via - a SHA256 hash and saved in the environment. - -config AUTOBOOT_USE_MENUKEY - bool "Allow a specify key to run a menu from the environment" - depends on !AUTOBOOT_KEYED - help - If a specific key is pressed to stop autoboot, then the commands in - the environment variable 'menucmd' are executed before boot starts. - -config AUTOBOOT_MENUKEY - int "ASCII value of boot key to show a menu" - default 0 - depends on AUTOBOOT_USE_MENUKEY - help - If this key is pressed to stop autoboot, then the commands in the - environment variable 'menucmd' will be executed before boot starts. - For example, 33 means "!" in ASCII, so pressing ! at boot would take - this action. - -config AUTOBOOT_MENU_SHOW - bool "Show a menu on boot" - depends on CMD_BOOTMENU - help - This enables the boot menu, controlled by environment variables - defined by the board. The menu starts after running the 'preboot' - environmnent variable (if enabled) and before handling the boot delay. - See README.bootmenu for more details. - -endmenu - config BUILD_BIN2C bool @@ -1142,6 +1025,14 @@ config CMD_LSBLK Print list of available block device drivers, and for each, the list of known block devices. +config CMD_MISC + bool "misc" + depends on MISC + help + Enable the command "misc" for accessing miscellaneous devices with + a MISC uclass driver. The command provides listing all MISC devices + as well as read and write functionalities via their drivers. + config CMD_MMC bool "mmc" help @@ -1183,6 +1074,14 @@ config CMD_CLONE initial flashing by external block device without network or usb support. +config CMD_OPTEE_RPMB + bool "Enable read/write support on RPMB via OPTEE" + depends on SUPPORT_EMMC_RPMB && OPTEE + help + Enable the commands for reading, writing persistent named values + in the Replay Protection Memory Block partition in eMMC by + using Persistent Objects in OPTEE + config CMD_MTD bool "mtd" depends on MTD @@ -1190,6 +1089,12 @@ config CMD_MTD help MTD commands support. +config CMD_MUX + bool "mux" + depends on MULTIPLEXER + help + List, select, and deselect mux controllers on the fly. + config CMD_NAND bool "nand" default y if NAND_SUNXI @@ -1825,8 +1730,7 @@ config CMD_RNG help Print bytes from the hardware random number generator. -# TODO: rename to CMD_SLEEP -config CMD_MISC +config CMD_SLEEP bool "sleep" default y help @@ -1868,6 +1772,77 @@ config CMD_QFW feature is to allow easy loading of files passed to qemu-system via -kernel / -initrd +config CMD_PSTORE + bool "pstore" + help + This provides access to Linux PStore with Rammoops backend. The main + feature is to allow to display or save PStore records. + + See doc/pstore.rst for more information. + +if CMD_PSTORE + +config CMD_PSTORE_MEM_ADDR + hex "Memory Address" + depends on CMD_PSTORE + help + Base addr used for PStore ramoops memory, should be identical to + ramoops.mem_address parameter used by kernel + +config CMD_PSTORE_MEM_SIZE + hex "Memory size" + depends on CMD_PSTORE + default "0x10000" + help + Size of PStore ramoops memory, should be identical to ramoops.mem_size + parameter used by kernel, a power of 2 and larger than the sum of the + record sizes + +config CMD_PSTORE_RECORD_SIZE + hex "Dump record size" + depends on CMD_PSTORE + default "0x1000" + help + Size of each dump done on oops/panic, should be identical to + ramoops.record_size parameter used by kernel and a power of 2 + Must be non-zero + +config CMD_PSTORE_CONSOLE_SIZE + hex "Kernel console log size" + depends on CMD_PSTORE + default "0x1000" + help + Size of kernel console log, should be identical to + ramoops.console_size parameter used by kernel and a power of 2 + Must be non-zero + +config CMD_PSTORE_FTRACE_SIZE + hex "FTrace log size" + depends on CMD_PSTORE + default "0x1000" + help + Size of ftrace log, should be identical to ramoops.ftrace_size + parameter used by kernel and a power of 2 + +config CMD_PSTORE_PMSG_SIZE + hex "User space message log size" + depends on CMD_PSTORE + default "0x1000" + help + Size of user space message log, should be identical to + ramoops.pmsg_size parameter used by kernel and a power of 2 + +config CMD_PSTORE_ECC_SIZE + int "ECC size" + depends on CMD_PSTORE + default "0" + help + if non-zero, the option enables ECC support and specifies ECC buffer + size in bytes (1 is a special value, means 16 bytes ECC), should be + identical to ramoops.ramoops_ecc parameter used by kernel + +endif + source "cmd/mvebu/Kconfig" config CMD_TERMINAL @@ -2264,6 +2239,7 @@ config CMD_KGDB config CMD_LOG bool "log - Generation, control and access to logging" select LOG + select GETOPT help This provides access to logging features. It allows the output of log data to be controlled to a limited extent (setting up the default diff --git a/cmd/Makefile b/cmd/Makefile index 015b83764c6..dd86675bf2a 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -94,9 +94,11 @@ obj-$(CONFIG_CMD_MEMORY) += mem.o obj-$(CONFIG_CMD_IO) += io.o obj-$(CONFIG_CMD_MFSL) += mfsl.o obj-$(CONFIG_CMD_MII) += mii.o -obj-$(CONFIG_CMD_MDIO) += mdio.o obj-$(CONFIG_CMD_MISC) += misc.o +obj-$(CONFIG_CMD_MDIO) += mdio.o +obj-$(CONFIG_CMD_SLEEP) += sleep.o obj-$(CONFIG_CMD_MMC) += mmc.o +obj-$(CONFIG_CMD_OPTEE_RPMB) += optee_rpmb.o obj-$(CONFIG_MP) += mp.o obj-$(CONFIG_CMD_MTD) += mtd.o obj-$(CONFIG_CMD_MTDPARTS) += mtdparts.o @@ -104,6 +106,7 @@ obj-$(CONFIG_CMD_CLONE) += clone.o ifneq ($(CONFIG_CMD_NAND)$(CONFIG_CMD_SF),) obj-y += legacy-mtd-utils.o endif +obj-$(CONFIG_CMD_MUX) += mux.o obj-$(CONFIG_CMD_NAND) += nand.o obj-$(CONFIG_CMD_NET) += net.o obj-$(CONFIG_CMD_NVEDIT_EFI) += nvedit_efi.o @@ -116,6 +119,7 @@ obj-$(CONFIG_CMD_PCI) += pci.o endif obj-$(CONFIG_CMD_PINMUX) += pinmux.o obj-$(CONFIG_CMD_PMC) += pmc.o +obj-$(CONFIG_CMD_PSTORE) += pstore.o obj-$(CONFIG_CMD_PXE) += pxe.o pxe_utils.o obj-$(CONFIG_CMD_WOL) += wol.o obj-$(CONFIG_CMD_QFW) += qfw.o @@ -140,6 +144,7 @@ obj-$(CONFIG_CMD_SMC) += smccc.o obj-$(CONFIG_CMD_SYSBOOT) += sysboot.o pxe_utils.o obj-$(CONFIG_CMD_TERMINAL) += terminal.o obj-$(CONFIG_CMD_TIME) += time.o +obj-$(CONFIG_CMD_TIMER) += timer.o obj-$(CONFIG_CMD_TRACE) += trace.o obj-$(CONFIG_HUSH_PARSER) += test.o obj-$(CONFIG_CMD_TPM) += tpm-common.o diff --git a/cmd/bootmenu.c b/cmd/bootmenu.c index 18efe25751f..1ba7b622e50 100644 --- a/cmd/bootmenu.c +++ b/cmd/bootmenu.c @@ -99,7 +99,7 @@ static void bootmenu_autoboot_loop(struct bootmenu_data *menu, } menu->delay = -1; - c = getc(); + c = getchar(); switch (c) { case '\e': @@ -141,7 +141,7 @@ static void bootmenu_loop(struct bootmenu_data *menu, mdelay(10); } - c = getc(); + c = getchar(); switch (*esc) { case 0: diff --git a/cmd/button.c b/cmd/button.c index 84ad1653c7b..64c5a8fa046 100644 --- a/cmd/button.c +++ b/cmd/button.c @@ -75,11 +75,11 @@ int do_button(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) ret = show_button_state(dev); - return 0; + return !ret; } U_BOOT_CMD( - button, 4, 1, do_button, + button, 2, 1, do_button, "manage buttons", "<button_label> \tGet button state\n" "button list\t\tShow a list of buttons" diff --git a/cmd/fat.c b/cmd/fat.c index b438ce16c91..69ce1fa5300 100644 --- a/cmd/fat.c +++ b/cmd/fat.c @@ -98,48 +98,7 @@ U_BOOT_CMD( static int do_fat_fswrite(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { - loff_t size; - int ret; - unsigned long addr; - unsigned long count; - long offset; - struct blk_desc *dev_desc = NULL; - struct disk_partition info; - int dev = 0; - int part = 1; - void *buf; - - if (argc < 5) - return cmd_usage(cmdtp); - - part = blk_get_device_part_str(argv[1], argv[2], &dev_desc, &info, 1); - if (part < 0) - return 1; - - dev = dev_desc->devnum; - - if (fat_set_blk_dev(dev_desc, &info) != 0) { - printf("\n** Unable to use %s %d:%d for fatwrite **\n", - argv[1], dev, part); - return 1; - } - addr = simple_strtoul(argv[3], NULL, 16); - count = (argc <= 5) ? 0 : simple_strtoul(argv[5], NULL, 16); - /* offset should be a hex, but "-1" is allowed */ - offset = (argc <= 6) ? 0 : simple_strtol(argv[6], NULL, 16); - - buf = map_sysmem(addr, count); - ret = file_fat_write(argv[4], buf, offset, count, &size); - unmap_sysmem(buf); - if (ret < 0) { - printf("\n** Unable to write \"%s\" from %s %d:%d **\n", - argv[4], argv[1], dev, part); - return 1; - } - - printf("%llu bytes written\n", size); - - return 0; + return do_save(cmdtp, flag, argc, argv, FS_TYPE_FAT); } U_BOOT_CMD( diff --git a/cmd/load.c b/cmd/load.c index 63a94145430..9a3a16979c7 100644 --- a/cmd/load.c +++ b/cmd/load.c @@ -81,7 +81,7 @@ static int do_load_serial(struct cmd_tbl *cmdtp, int flag, int argc, serial_setbrg(); udelay(50000); for (;;) { - if (getc() == '\r') + if (getchar() == '\r') break; } } @@ -102,7 +102,7 @@ static int do_load_serial(struct cmd_tbl *cmdtp, int flag, int argc, */ for (i=0; i<100; ++i) { if (tstc()) { - (void) getc(); + getchar(); } udelay(1000); } @@ -124,7 +124,7 @@ static int do_load_serial(struct cmd_tbl *cmdtp, int flag, int argc, serial_setbrg(); udelay(50000); for (;;) { - if (getc() == 0x1B) /* ESC */ + if (getchar() == 0x1B) /* ESC */ break; } } @@ -212,7 +212,7 @@ static int read_record(char *buf, ulong len) --len; /* always leave room for terminating '\0' byte */ for (p=buf; p < buf+len; ++p) { - c = getc(); /* read character */ + c = getchar(); /* read character */ if (do_echo) putc(c); /* ... and echo it */ @@ -229,7 +229,7 @@ static int read_record(char *buf, ulong len) } /* Check for the console hangup (if any different from serial) */ - if (gd->jt->getc != getc) { + if (gd->jt->getc != getchar) { if (ctrlc()) { return (-1); } @@ -276,7 +276,7 @@ int do_save_serial(struct cmd_tbl *cmdtp, int flag, int argc, serial_setbrg(); udelay(50000); for (;;) { - if (getc() == '\r') + if (getchar() == '\r') break; } } @@ -288,7 +288,7 @@ int do_save_serial(struct cmd_tbl *cmdtp, int flag, int argc, printf("## Ready for S-Record upload, press ENTER to proceed ...\n"); for (;;) { - if (getc() == '\r') + if (getchar() == '\r') break; } if (save_serial(offset, size)) { @@ -305,7 +305,7 @@ int do_save_serial(struct cmd_tbl *cmdtp, int flag, int argc, serial_setbrg(); udelay(50000); for (;;) { - if (getc() == 0x1B) /* ESC */ + if (getchar() == 0x1B) /* ESC */ break; } } @@ -459,7 +459,7 @@ static int do_load_serial_bin(struct cmd_tbl *cmdtp, int flag, int argc, serial_setbrg(); udelay(50000); for (;;) { - if (getc() == '\r') + if (getchar() == '\r') break; } } @@ -505,7 +505,7 @@ static int do_load_serial_bin(struct cmd_tbl *cmdtp, int flag, int argc, serial_setbrg(); udelay(50000); for (;;) { - if (getc() == 0x1B) /* ESC */ + if (getchar() == 0x1B) /* ESC */ break; } } @@ -528,7 +528,7 @@ static ulong load_serial_bin(ulong offset) */ for (i=0; i<100; ++i) { if (tstc()) { - (void) getc(); + getchar(); } udelay(1000); } @@ -831,7 +831,7 @@ static int k_recv(void) /* get a packet */ /* wait for the starting character or ^C */ for (;;) { - switch (getc ()) { + switch (getchar()) { case START_CHAR: /* start packet */ goto START; case ETX_CHAR: /* ^C waiting for packet */ @@ -843,13 +843,13 @@ static int k_recv(void) START: /* get length of packet */ sum = 0; - new_char = getc(); + new_char = getchar(); if ((new_char & 0xE0) == 0) goto packet_error; sum += new_char & 0xff; length = untochar(new_char); /* get sequence number */ - new_char = getc(); + new_char = getchar(); if ((new_char & 0xE0) == 0) goto packet_error; sum += new_char & 0xff; @@ -876,7 +876,7 @@ START: /* END NEW CODE */ /* get packet type */ - new_char = getc(); + new_char = getchar(); if ((new_char & 0xE0) == 0) goto packet_error; sum += new_char & 0xff; @@ -886,19 +886,19 @@ START: if (length == -2) { /* (length byte was 0, decremented twice) */ /* get the two length bytes */ - new_char = getc(); + new_char = getchar(); if ((new_char & 0xE0) == 0) goto packet_error; sum += new_char & 0xff; len_hi = untochar(new_char); - new_char = getc(); + new_char = getchar(); if ((new_char & 0xE0) == 0) goto packet_error; sum += new_char & 0xff; len_lo = untochar(new_char); length = len_hi * 95 + len_lo; /* check header checksum */ - new_char = getc(); + new_char = getchar(); if ((new_char & 0xE0) == 0) goto packet_error; if (new_char != tochar((sum + ((sum >> 6) & 0x03)) & 0x3f)) @@ -908,7 +908,7 @@ START: } /* bring in rest of packet */ while (length > 1) { - new_char = getc(); + new_char = getchar(); if ((new_char & 0xE0) == 0) goto packet_error; sum += new_char & 0xff; @@ -925,13 +925,13 @@ START: } } /* get and validate checksum character */ - new_char = getc(); + new_char = getchar(); if ((new_char & 0xE0) == 0) goto packet_error; if (new_char != tochar((sum + ((sum >> 6) & 0x03)) & 0x3f)) goto packet_error; /* get END_CHAR */ - new_char = getc(); + new_char = getchar(); if (new_char != END_CHAR) { packet_error: /* restore state machines */ @@ -955,7 +955,7 @@ START: static int getcxmodem(void) { if (tstc()) - return (getc()); + return (getchar()); return -1; } static ulong load_serial_ymodem(ulong offset, int mode) diff --git a/cmd/log.c b/cmd/log.c index 6afe6ead251..ca1c51e0672 100644 --- a/cmd/log.c +++ b/cmd/log.c @@ -7,27 +7,298 @@ #include <common.h> #include <command.h> #include <dm.h> +#include <getopt.h> #include <log.h> +#include <malloc.h> static char log_fmt_chars[LOGF_COUNT] = "clFLfm"; +static enum log_level_t parse_log_level(char *const arg) +{ + enum log_level_t ret; + ulong level; + + if (!strict_strtoul(arg, 10, &level)) { + if (level > _LOG_MAX_LEVEL) { + printf("Only log levels <= %d are supported\n", + _LOG_MAX_LEVEL); + return LOGL_NONE; + } + return level; + } + + ret = log_get_level_by_name(arg); + if (ret == LOGL_NONE) + printf("Unknown log level \"%s\"\n", arg); + return ret; +} + static int do_log_level(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { + enum log_level_t log_level; + if (argc > 1) { - long log_level = simple_strtol(argv[1], NULL, 10); + log_level = parse_log_level(argv[1]); - if (log_level < 0 || log_level > _LOG_MAX_LEVEL) { - printf("Only log levels <= %d are supported\n", - _LOG_MAX_LEVEL); + if (log_level == LOGL_NONE) return CMD_RET_FAILURE; - } gd->default_log_level = log_level; } else { - printf("Default log level: %d\n", gd->default_log_level); + for (log_level = LOGL_FIRST; log_level <= _LOG_MAX_LEVEL; + log_level++) + printf("%s%s\n", log_get_level_name(log_level), + log_level == gd->default_log_level ? + " (default)" : ""); } - return 0; + return CMD_RET_SUCCESS; +} + +static int do_log_categories(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + enum log_category_t cat; + const char *name; + + for (cat = LOGC_FIRST; cat < LOGC_COUNT; cat++) { + name = log_get_cat_name(cat); + /* + * Invalid category names (e.g. <invalid> or <missing>) begin + * with '<'. + */ + if (name[0] == '<') + continue; + printf("%s\n", name); + } + + return CMD_RET_SUCCESS; +} + +static int do_log_drivers(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + struct log_device *ldev; + + list_for_each_entry(ldev, &gd->log_head, sibling_node) + printf("%s\n", ldev->drv->name); + + return CMD_RET_SUCCESS; +} + +static int do_log_filter_list(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + int opt; + const char *drv_name = "console"; + struct getopt_state gs; + struct log_filter *filt; + struct log_device *ldev; + + getopt_init_state(&gs); + while ((opt = getopt(&gs, argc, argv, "d:")) > 0) { + switch (opt) { + case 'd': + drv_name = gs.arg; + break; + default: + return CMD_RET_USAGE; + } + } + + if (gs.index != argc) + return CMD_RET_USAGE; + + ldev = log_device_find_by_name(drv_name); + if (!ldev) { + printf("Could not find log device for \"%s\"\n", drv_name); + return CMD_RET_FAILURE; + } + + /* <3> < 6 > <2+1 + 7 > < 16 > < unbounded... */ + printf("num policy level categories files\n"); + list_for_each_entry(filt, &ldev->filter_head, sibling_node) { + printf("%3d %6.6s %s %-7.7s ", filt->filter_num, + filt->flags & LOGFF_DENY ? "deny" : "allow", + filt->flags & LOGFF_LEVEL_MIN ? ">=" : "<=", + log_get_level_name(filt->level)); + + if (filt->flags & LOGFF_HAS_CAT) { + int i; + + if (filt->cat_list[0] != LOGC_END) + printf("%16.16s %s\n", + log_get_cat_name(filt->cat_list[0]), + filt->file_list ? filt->file_list : ""); + + for (i = 1; i < LOGF_MAX_CATEGORIES && + filt->cat_list[i] != LOGC_END; i++) + printf("%21c %16.16s\n", ' ', + log_get_cat_name(filt->cat_list[i])); + } else { + printf("%16c %s\n", ' ', + filt->file_list ? filt->file_list : ""); + } + } + + return CMD_RET_SUCCESS; +} + +static int do_log_filter_add(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + bool level_set = false; + bool print_num = false; + bool type_set = false; + char *file_list = NULL; + const char *drv_name = "console"; + int opt, err; + int cat_count = 0; + int flags = 0; + enum log_category_t cat_list[LOGF_MAX_CATEGORIES + 1]; + enum log_level_t level = LOGL_MAX; + struct getopt_state gs; + + getopt_init_state(&gs); + while ((opt = getopt(&gs, argc, argv, "Ac:d:Df:l:L:p")) > 0) { + switch (opt) { + case 'A': +#define do_type() do { \ + if (type_set) { \ + printf("Allow or deny set twice\n"); \ + return CMD_RET_USAGE; \ + } \ + type_set = true; \ +} while (0) + do_type(); + break; + case 'c': { + enum log_category_t cat; + + if (cat_count >= LOGF_MAX_CATEGORIES) { + printf("Too many categories\n"); + return CMD_RET_FAILURE; + } + + cat = log_get_cat_by_name(gs.arg); + if (cat == LOGC_NONE) { + printf("Unknown category \"%s\"\n", gs.arg); + return CMD_RET_FAILURE; + } + + cat_list[cat_count++] = cat; + break; + } + case 'd': + drv_name = gs.arg; + break; + case 'D': + do_type(); + flags |= LOGFF_DENY; + break; + case 'f': + file_list = gs.arg; + break; + case 'l': +#define do_level() do { \ + if (level_set) { \ + printf("Log level set twice\n"); \ + return CMD_RET_USAGE; \ + } \ + level = parse_log_level(gs.arg); \ + if (level == LOGL_NONE) \ + return CMD_RET_FAILURE; \ + level_set = true; \ +} while (0) + do_level(); + break; + case 'L': + do_level(); + flags |= LOGFF_LEVEL_MIN; + break; + case 'p': + print_num = true; + break; + default: + return CMD_RET_USAGE; + } + } + + if (gs.index != argc) + return CMD_RET_USAGE; + + cat_list[cat_count] = LOGC_END; + err = log_add_filter_flags(drv_name, cat_count ? cat_list : NULL, level, + file_list, flags); + if (err < 0) { + printf("Could not add filter (err = %d)\n", err); + return CMD_RET_FAILURE; + } else if (print_num) { + printf("%d\n", err); + } + + return CMD_RET_SUCCESS; +} + +static int do_log_filter_remove(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + bool all = false; + int opt, err; + ulong filter_num; + const char *drv_name = "console"; + struct getopt_state gs; + + getopt_init_state(&gs); + while ((opt = getopt(&gs, argc, argv, "ad:")) > 0) { + switch (opt) { + case 'a': + all = true; + break; + case 'd': + drv_name = gs.arg; + break; + default: + return CMD_RET_USAGE; + } + } + + if (all) { + struct log_filter *filt, *tmp_filt; + struct log_device *ldev; + + if (gs.index != argc) + return CMD_RET_USAGE; + + ldev = log_device_find_by_name(drv_name); + if (!ldev) { + printf("Could not find log device for \"%s\"\n", + drv_name); + return CMD_RET_FAILURE; + } + + list_for_each_entry_safe(filt, tmp_filt, &ldev->filter_head, + sibling_node) { + list_del(&filt->sibling_node); + free(filt); + } + } else { + if (gs.index + 1 != argc) + return CMD_RET_USAGE; + + if (strict_strtoul(argv[gs.index], 10, &filter_num)) { + printf("Invalid filter number \"%s\"\n", argv[gs.index]); + return CMD_RET_FAILURE; + } + + err = log_remove_filter(drv_name, filter_num); + if (err) { + printf("Could not remove filter (err = %d)\n", err); + return CMD_RET_FAILURE; + } + } + + return CMD_RET_SUCCESS; } static int do_log_format(struct cmd_tbl *cmdtp, int flag, int argc, @@ -103,39 +374,31 @@ static int do_log_rec(struct cmd_tbl *cmdtp, int flag, int argc, return 0; } -static struct cmd_tbl log_sub[] = { - U_BOOT_CMD_MKENT(level, CONFIG_SYS_MAXARGS, 1, do_log_level, "", ""), -#ifdef CONFIG_LOG_TEST - U_BOOT_CMD_MKENT(test, 2, 1, do_log_test, "", ""), -#endif - U_BOOT_CMD_MKENT(format, CONFIG_SYS_MAXARGS, 1, do_log_format, "", ""), - U_BOOT_CMD_MKENT(rec, CONFIG_SYS_MAXARGS, 1, do_log_rec, "", ""), -}; - -static int do_log(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) -{ - struct cmd_tbl *cp; - - if (argc < 2) - return CMD_RET_USAGE; - - /* drop initial "log" arg */ - argc--; - argv++; - - cp = find_cmd_tbl(argv[0], log_sub, ARRAY_SIZE(log_sub)); - if (cp) - return cp->cmd(cmdtp, flag, argc, argv); - - return CMD_RET_USAGE; -} - #ifdef CONFIG_SYS_LONGHELP static char log_help_text[] = - "level - get/set log level\n" -#ifdef CONFIG_LOG_TEST - "log test - run log tests\n" -#endif + "level [<level>] - get/set log level\n" + "categories - list log categories\n" + "drivers - list log drivers\n" + "log filter-list [OPTIONS] - list all filters for a log driver\n" + "\t-d <driver> - Specify the log driver to list filters from; defaults\n" + "\t to console\n" + "log filter-add [OPTIONS] - add a new filter to a driver\n" + "\t-A - Allow messages matching this filter; mutually exclusive with -D\n" + "\t This is the default.\n" + "\t-c <category> - Category to match; may be specified multiple times\n" + "\t-d <driver> - Specify the log driver to add the filter to; defaults\n" + "\t to console\n" + "\t-D - Deny messages matching this filter; mutually exclusive with -A\n" + "\t-f <files_list> - A comma-separated list of files to match\n" + "\t-l <level> - Match log levels less than or equal to <level>;\n" + "\t mutually-exclusive with -L\n" + "\t-L <level> - Match log levels greather than or equal to <level>;\n" + "\t mutually-exclusive with -l\n" + "\t-p - Print the filter number on success\n" + "log filter-remove [OPTIONS] [<num>] - Remove filter number <num>\n" + "\t-a - Remove ALL filters\n" + "\t-d <driver> - Specify the log driver to remove the filter from;\n" + "\t defaults to console\n" "log format <fmt> - set log output format. <fmt> is a string where\n" "\teach letter indicates something that should be displayed:\n" "\tc=category, l=level, F=file, L=line number, f=function, m=msg\n" @@ -145,7 +408,14 @@ static char log_help_text[] = ; #endif -U_BOOT_CMD( - log, CONFIG_SYS_MAXARGS, 1, do_log, - "log system", log_help_text +U_BOOT_CMD_WITH_SUBCMDS(log, "log system", log_help_text, + U_BOOT_SUBCMD_MKENT(level, 2, 1, do_log_level), + U_BOOT_SUBCMD_MKENT(categories, 1, 1, do_log_categories), + U_BOOT_SUBCMD_MKENT(drivers, 1, 1, do_log_drivers), + U_BOOT_SUBCMD_MKENT(filter-list, 3, 1, do_log_filter_list), + U_BOOT_SUBCMD_MKENT(filter-add, CONFIG_SYS_MAXARGS, 1, + do_log_filter_add), + U_BOOT_SUBCMD_MKENT(filter-remove, 4, 1, do_log_filter_remove), + U_BOOT_SUBCMD_MKENT(format, 2, 1, do_log_format), + U_BOOT_SUBCMD_MKENT(rec, 7, 1, do_log_rec), ); diff --git a/cmd/misc.c b/cmd/misc.c index 20ab943494e..653deed7f57 100644 --- a/cmd/misc.c +++ b/cmd/misc.c @@ -1,88 +1,134 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * (C) Copyright 2001 - * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * Copyright (c) 2020 Wind River Systems, Inc. + * + * Author: + * Bin Meng <bin.meng@windriver.com> + * + * A command interface to access misc devices with MISC uclass driver APIs. */ -/* - * Misc functions - */ #include <common.h> #include <command.h> -#include <console.h> -#include <linux/delay.h> - -static int do_sleep(struct cmd_tbl *cmdtp, int flag, int argc, - char *const argv[]) +#include <dm.h> +#include <errno.h> +#include <misc.h> + +enum misc_op { + MISC_OP_READ, + MISC_OP_WRITE +}; + +static char *misc_op_str[] = { + "read", + "write" +}; + +static int do_misc_list(struct cmd_tbl *cmdtp, int flag, + int argc, char *const argv[]) { - ulong start = get_timer(0); - ulong mdelay = 0; - ulong delay; - char *frpart; - - if (argc != 2) - return CMD_RET_USAGE; + struct udevice *dev; + + printf("Device Index Driver\n"); + printf("-------------------------------------\n"); + for (uclass_first_device(UCLASS_MISC, &dev); + dev; + uclass_next_device(&dev)) { + printf("%-20s %5d %10s\n", dev->name, dev->seq, + dev->driver->name); + } - delay = simple_strtoul(argv[1], NULL, 10) * CONFIG_SYS_HZ; + return 0; +} - frpart = strchr(argv[1], '.'); +static int do_misc_op(struct cmd_tbl *cmdtp, int flag, + int argc, char *const argv[], enum misc_op op) +{ + int (*misc_op)(struct udevice *, int, void *, int); + struct udevice *dev; + int offset; + void *buf; + int size; + int ret; + + ret = uclass_get_device_by_name(UCLASS_MISC, argv[0], &dev); + if (ret) { + printf("Unable to find device %s\n", argv[0]); + return ret; + } - if (frpart) { - uint mult = CONFIG_SYS_HZ / 10; - for (frpart++; *frpart != '\0' && mult > 0; frpart++) { - if (*frpart < '0' || *frpart > '9') { - mdelay = 0; - break; - } - mdelay += (*frpart - '0') * mult; - mult /= 10; + offset = simple_strtoul(argv[1], NULL, 16); + buf = (void *)simple_strtoul(argv[2], NULL, 16); + size = simple_strtoul(argv[3], NULL, 16); + + if (op == MISC_OP_READ) + misc_op = misc_read; + else + misc_op = misc_write; + + ret = misc_op(dev, offset, buf, size); + if (ret < 0) { + if (ret == -ENOSYS) { + printf("The device does not support %s\n", + misc_op_str[op]); + ret = 0; } + } else { + if (ret == size) + ret = 0; + else + printf("Partially %s %d bytes\n", misc_op_str[op], ret); } - delay += mdelay; - - while (get_timer(start) < delay) { - if (ctrlc()) - return (-1); + return ret; +} - udelay(100); - } +static int do_misc_read(struct cmd_tbl *cmdtp, int flag, + int argc, char *const argv[]) +{ + return do_misc_op(cmdtp, flag, argc, argv, MISC_OP_READ); +} - return 0; +static int do_misc_write(struct cmd_tbl *cmdtp, int flag, + int argc, char *const argv[]) +{ + return do_misc_op(cmdtp, flag, argc, argv, MISC_OP_WRITE); } -U_BOOT_CMD( - sleep , 2, 1, do_sleep, - "delay execution for some time", - "N\n" - " - delay execution for N seconds (N is _decimal_ and can be\n" - " fractional)" -); +static struct cmd_tbl misc_commands[] = { + U_BOOT_CMD_MKENT(list, 0, 1, do_misc_list, "", ""), + U_BOOT_CMD_MKENT(read, 4, 1, do_misc_read, "", ""), + U_BOOT_CMD_MKENT(write, 4, 1, do_misc_write, "", ""), +}; -#ifdef CONFIG_CMD_TIMER -static int do_timer(struct cmd_tbl *cmdtp, int flag, int argc, - char *const argv[]) +static int do_misc(struct cmd_tbl *cmdtp, int flag, + int argc, char *const argv[]) { - static ulong start; + struct cmd_tbl *misc_cmd; + int ret; - if (argc != 2) + if (argc < 2) + return CMD_RET_USAGE; + misc_cmd = find_cmd_tbl(argv[1], misc_commands, + ARRAY_SIZE(misc_commands)); + argc -= 2; + argv += 2; + if (!misc_cmd || argc != misc_cmd->maxargs) return CMD_RET_USAGE; - if (!strcmp(argv[1], "start")) - start = get_timer(0); + ret = misc_cmd->cmd(misc_cmd, flag, argc, argv); - if (!strcmp(argv[1], "get")) { - ulong msecs = get_timer(start) * 1000 / CONFIG_SYS_HZ; - printf("%ld.%03d\n", msecs / 1000, (int)(msecs % 1000)); - } - - return 0; + return cmd_process_error(misc_cmd, ret); } U_BOOT_CMD( - timer, 2, 1, do_timer, - "access the system timer", - "start - Reset the timer reference.\n" - "timer get - Print the time since 'start'." + misc, 6, 1, do_misc, + "Access miscellaneous devices with MISC uclass driver APIs", + "list - list all miscellaneous devices\n" + "misc read name offset addr len - read `len' bytes starting at\n" + " `offset' of device `name'\n" + " to memory at `addr'\n" + "misc write name offset addr len - write `len' bytes starting at\n" + " `offset' of device `name'\n" + " from memory at `addr'" ); -#endif diff --git a/cmd/mux.c b/cmd/mux.c new file mode 100644 index 00000000000..833266f08b1 --- /dev/null +++ b/cmd/mux.c @@ -0,0 +1,184 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * List, select, and deselect mux controllers on the fly. + * + * Copyright (c) 2020 Texas Instruments Inc. + * Author: Pratyush Yadav <p.yadav@ti.com> + */ + +#include <common.h> +#include <command.h> +#include <errno.h> +#include <dm.h> +#include <dm/device_compat.h> +#include <mux.h> +#include <mux-internal.h> +#include <linux/err.h> +#include <dt-bindings/mux/mux.h> + +#define COLUMN_SIZE 16 + +/* + * Print a member of a column. The total size of the text printed, including + * trailing whitespace, will always be COLUMN_SIZE. + */ +#define PRINT_COLUMN(fmt, args...) do { \ + char buf[COLUMN_SIZE + 1]; \ + snprintf(buf, COLUMN_SIZE + 1, fmt, ##args); \ + printf("%-*s", COLUMN_SIZE, buf); \ +} while (0) + +/* + * Find a mux based on its device name in argv[1] and index in the chip in + * argv[2]. + */ +static struct mux_control *cmd_mux_find(char *const argv[]) +{ + struct udevice *dev; + struct mux_chip *chip; + int ret; + unsigned long id; + + ret = strict_strtoul(argv[2], 10, &id); + if (ret) + return ERR_PTR(ret); + + ret = uclass_get_device_by_name(UCLASS_MUX, argv[1], &dev); + if (ret) + return ERR_PTR(ret); + + chip = dev_get_uclass_priv(dev); + if (!chip) + return ERR_PTR(ret); + + if (id >= chip->controllers) + return ERR_PTR(-EINVAL); + + return &chip->mux[id]; +} + +/* + * Print the details of a mux. The columns printed correspond to: "Selected", + * "Current State", "Idle State", and "Num States". + */ +static void print_mux(struct mux_control *mux) +{ + PRINT_COLUMN("%s", mux->in_use ? "yes" : "no"); + + if (mux->cached_state == MUX_IDLE_AS_IS) + PRINT_COLUMN("%s", "unknown"); + else + PRINT_COLUMN("0x%x", mux->cached_state); + + if (mux->idle_state == MUX_IDLE_AS_IS) + PRINT_COLUMN("%s", "as-is"); + else if (mux->idle_state == MUX_IDLE_DISCONNECT) + PRINT_COLUMN("%s", "disconnect"); + else + PRINT_COLUMN("0x%x", mux->idle_state); + + PRINT_COLUMN("0x%x", mux->states); + + printf("\n"); +} + +static int do_mux_list(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + struct udevice *dev; + struct mux_chip *chip; + int j; + + for (uclass_first_device(UCLASS_MUX, &dev); + dev; + uclass_next_device(&dev)) { + chip = dev_get_uclass_priv(dev); + if (!chip) { + dev_err(dev, "can't find mux chip\n"); + continue; + } + + printf("%s:\n", dev->name); + + printf(" "); + PRINT_COLUMN("ID"); + PRINT_COLUMN("Selected"); + PRINT_COLUMN("Current State"); + PRINT_COLUMN("Idle State"); + PRINT_COLUMN("Num States"); + printf("\n"); + for (j = 0; j < chip->controllers; j++) { + printf(" "); + PRINT_COLUMN("%d", j); + print_mux(&chip->mux[j]); + } + printf("\n"); + } + + return 0; +} + +static int do_mux_select(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + struct mux_control *mux; + int ret; + unsigned long state; + + if (argc != 4) + return CMD_RET_USAGE; + + mux = cmd_mux_find(argv); + if (IS_ERR_OR_NULL(mux)) { + printf("Failed to find the specified mux\n"); + return CMD_RET_FAILURE; + } + + ret = strict_strtoul(argv[3], 16, &state); + if (ret) { + printf("Invalid state\n"); + return CMD_RET_FAILURE; + } + + ret = mux_control_select(mux, state); + if (ret) { + printf("Failed to select requested state\n"); + return CMD_RET_FAILURE; + } + + return CMD_RET_SUCCESS; +} + +static int do_mux_deselect(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + struct mux_control *mux; + int ret; + + if (argc != 3) + return CMD_RET_USAGE; + + mux = cmd_mux_find(argv); + if (IS_ERR_OR_NULL(mux)) { + printf("Failed to find the specified mux\n"); + return CMD_RET_FAILURE; + } + + ret = mux_control_deselect(mux); + if (ret) { + printf("Failed to deselect mux\n"); + return CMD_RET_FAILURE; + } + + return CMD_RET_SUCCESS; +} + +static char mux_help_text[] = + "list - List all Muxes and their states\n" + "select <chip> <id> <state> - Select the given mux state\n" + "deselect <chip> <id> - Deselect the given mux and reset it to its idle state"; + +U_BOOT_CMD_WITH_SUBCMDS(mux, "List, select, and deselect muxes", mux_help_text, + U_BOOT_SUBCMD_MKENT(list, 1, 1, do_mux_list), + U_BOOT_SUBCMD_MKENT(select, 4, 0, do_mux_select), + U_BOOT_SUBCMD_MKENT(deselect, 3, 0, do_mux_deselect)); diff --git a/cmd/optee_rpmb.c b/cmd/optee_rpmb.c new file mode 100644 index 00000000000..0d6b1cb1d83 --- /dev/null +++ b/cmd/optee_rpmb.c @@ -0,0 +1,272 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2020 NXP + */ + +#include <command.h> +#include <common.h> +#include <env.h> +#include <errno.h> +#include <image.h> +#include <malloc.h> +#include <mmc.h> +#include <tee.h> +#include <tee/optee_ta_avb.h> + +static struct udevice *tee; +static u32 session; + +static int avb_ta_open_session(void) +{ + const struct tee_optee_ta_uuid uuid = TA_AVB_UUID; + struct tee_open_session_arg arg; + int rc; + + tee = tee_find_device(tee, NULL, NULL, NULL); + if (!tee) + return -ENODEV; + + memset(&arg, 0, sizeof(arg)); + tee_optee_ta_uuid_to_octets(arg.uuid, &uuid); + rc = tee_open_session(tee, &arg, 0, NULL); + if (!rc) + session = arg.session; + + return 0; +} + +static int invoke_func(u32 func, ulong num_param, struct tee_param *param) +{ + struct tee_invoke_arg arg; + + if (!tee) + if (avb_ta_open_session()) + return -ENODEV; + + memset(&arg, 0, sizeof(arg)); + arg.func = func; + arg.session = session; + + if (tee_invoke_func(tee, &arg, num_param, param)) + return -EFAULT; + switch (arg.ret) { + case TEE_SUCCESS: + return 0; + case TEE_ERROR_OUT_OF_MEMORY: + case TEE_ERROR_STORAGE_NO_SPACE: + return -ENOSPC; + case TEE_ERROR_ITEM_NOT_FOUND: + return -EIO; + case TEE_ERROR_TARGET_DEAD: + /* + * The TA has paniced, close the session to reload the TA + * for the next request. + */ + tee_close_session(tee, session); + tee = NULL; + return -EIO; + default: + return -EIO; + } +} + +static int read_persistent_value(const char *name, + size_t buffer_size, + u8 *out_buffer, + size_t *out_num_bytes_read) +{ + int rc = 0; + struct tee_shm *shm_name; + struct tee_shm *shm_buf; + struct tee_param param[2]; + size_t name_size = strlen(name) + 1; + + if (!tee) + if (avb_ta_open_session()) + return -ENODEV; + + rc = tee_shm_alloc(tee, name_size, + TEE_SHM_ALLOC, &shm_name); + if (rc) + return -ENOMEM; + + rc = tee_shm_alloc(tee, buffer_size, + TEE_SHM_ALLOC, &shm_buf); + if (rc) { + rc = -ENOMEM; + goto free_name; + } + + memcpy(shm_name->addr, name, name_size); + + memset(param, 0, sizeof(param)); + param[0].attr = TEE_PARAM_ATTR_TYPE_MEMREF_INPUT; + param[0].u.memref.shm = shm_name; + param[0].u.memref.size = name_size; + param[1].attr = TEE_PARAM_ATTR_TYPE_MEMREF_INOUT; + param[1].u.memref.shm = shm_buf; + param[1].u.memref.size = buffer_size; + + rc = invoke_func(TA_AVB_CMD_READ_PERSIST_VALUE, + 2, param); + if (rc) + goto out; + + if (param[1].u.memref.size > buffer_size) { + rc = -EINVAL; + goto out; + } + + *out_num_bytes_read = param[1].u.memref.size; + + memcpy(out_buffer, shm_buf->addr, *out_num_bytes_read); + +out: + tee_shm_free(shm_buf); +free_name: + tee_shm_free(shm_name); + + return rc; +} + +static int write_persistent_value(const char *name, + size_t value_size, + const u8 *value) +{ + int rc = 0; + struct tee_shm *shm_name; + struct tee_shm *shm_buf; + struct tee_param param[2]; + size_t name_size = strlen(name) + 1; + + if (!tee) { + if (avb_ta_open_session()) + return -ENODEV; + } + if (!value_size) + return -EINVAL; + + rc = tee_shm_alloc(tee, name_size, + TEE_SHM_ALLOC, &shm_name); + if (rc) + return -ENOMEM; + + rc = tee_shm_alloc(tee, value_size, + TEE_SHM_ALLOC, &shm_buf); + if (rc) { + rc = -ENOMEM; + goto free_name; + } + + memcpy(shm_name->addr, name, name_size); + memcpy(shm_buf->addr, value, value_size); + + memset(param, 0, sizeof(param)); + param[0].attr = TEE_PARAM_ATTR_TYPE_MEMREF_INPUT; + param[0].u.memref.shm = shm_name; + param[0].u.memref.size = name_size; + param[1].attr = TEE_PARAM_ATTR_TYPE_MEMREF_INPUT; + param[1].u.memref.shm = shm_buf; + param[1].u.memref.size = value_size; + + rc = invoke_func(TA_AVB_CMD_WRITE_PERSIST_VALUE, + 2, param); + if (rc) + goto out; + +out: + tee_shm_free(shm_buf); +free_name: + tee_shm_free(shm_name); + + return rc; +} + +int do_optee_rpmb_read(struct cmd_tbl *cmdtp, int flag, int argc, + char * const argv[]) +{ + const char *name; + size_t bytes; + size_t bytes_read; + void *buffer; + char *endp; + + if (argc != 3) + return CMD_RET_USAGE; + + name = argv[1]; + bytes = simple_strtoul(argv[2], &endp, 10); + if (*endp && *endp != '\n') + return CMD_RET_USAGE; + + buffer = malloc(bytes); + if (!buffer) + return CMD_RET_FAILURE; + + if (read_persistent_value(name, bytes, buffer, &bytes_read) == 0) { + printf("Read %zu bytes, value = %s\n", bytes_read, + (char *)buffer); + free(buffer); + return CMD_RET_SUCCESS; + } + + printf("Failed to read persistent value\n"); + + free(buffer); + + return CMD_RET_FAILURE; +} + +int do_optee_rpmb_write(struct cmd_tbl *cmdtp, int flag, int argc, + char * const argv[]) +{ + const char *name; + const char *value; + + if (argc != 3) + return CMD_RET_USAGE; + + name = argv[1]; + value = argv[2]; + + if (write_persistent_value(name, strlen(value) + 1, + (const uint8_t *)value) == 0) { + printf("Wrote %zu bytes\n", strlen(value) + 1); + return CMD_RET_SUCCESS; + } + + printf("Failed to write persistent value\n"); + + return CMD_RET_FAILURE; +} + +static struct cmd_tbl cmd_optee_rpmb[] = { + U_BOOT_CMD_MKENT(read_pvalue, 3, 0, do_optee_rpmb_read, "", ""), + U_BOOT_CMD_MKENT(write_pvalue, 3, 0, do_optee_rpmb_write, "", ""), +}; + +static int do_optee_rpmb(struct cmd_tbl *cmdtp, int flag, int argc, + char * const argv[]) +{ + struct cmd_tbl *cp; + + cp = find_cmd_tbl(argv[1], cmd_optee_rpmb, ARRAY_SIZE(cmd_optee_rpmb)); + + argc--; + argv++; + + if (!cp || argc > cp->maxargs) + return CMD_RET_USAGE; + + if (flag == CMD_FLAG_REPEAT) + return CMD_RET_FAILURE; + + return cp->cmd(cmdtp, flag, argc, argv); +} + +U_BOOT_CMD ( + optee_rpmb, 29, 0, do_optee_rpmb, + "Provides commands for testing secure storage on RPMB on OPTEE", + "read_pvalue <name> <bytes> - read a persistent value <name>\n" + "optee_rpmb write_pvalue <name> <value> - write a persistent value <name>\n" + ); diff --git a/cmd/pstore.c b/cmd/pstore.c new file mode 100644 index 00000000000..9a8b38c7f26 --- /dev/null +++ b/cmd/pstore.c @@ -0,0 +1,544 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright © 2019 Collabora Ltd + */ + +#include <config.h> +#include <command.h> +#include <fs.h> +#include <log.h> +#include <mapmem.h> +#include <memalign.h> +#include <part.h> + +struct persistent_ram_buffer { + u32 sig; + u32 start; + u32 size; + u8 data[0]; +}; + +#define PERSISTENT_RAM_SIG (0x43474244) /* DBGC */ +#define RAMOOPS_KERNMSG_HDR "====" + +#define PSTORE_TYPE_DMESG 0 +#define PSTORE_TYPE_CONSOLE 2 +#define PSTORE_TYPE_FTRACE 3 +#define PSTORE_TYPE_PMSG 7 +#define PSTORE_TYPE_ALL 255 + +static phys_addr_t pstore_addr = CONFIG_CMD_PSTORE_MEM_ADDR; +static phys_size_t pstore_length = CONFIG_CMD_PSTORE_MEM_SIZE; +static unsigned int pstore_record_size = CONFIG_CMD_PSTORE_RECORD_SIZE; +static unsigned int pstore_console_size = CONFIG_CMD_PSTORE_CONSOLE_SIZE; +static unsigned int pstore_ftrace_size = CONFIG_CMD_PSTORE_FTRACE_SIZE; +static unsigned int pstore_pmsg_size = CONFIG_CMD_PSTORE_PMSG_SIZE; +static unsigned int pstore_ecc_size = CONFIG_CMD_PSTORE_ECC_SIZE; +static unsigned int buffer_size; + + /** + * pstore_read_kmsg_hdr() - Check kernel header and get compression flag if + * available. + * @buffer: Kernel messages buffer. + * @compressed: Returns TRUE if kernel buffer is compressed, else FALSE. + * + * Check if buffer starts with a kernel header of the form: + * ====<secs>.<nsecs>[-<compression>]\n + * If <compression> is equal to 'C' then the buffer is compressed, else iter + * should be 'D'. + * + * Return: Length of kernel header. + */ +static int pstore_read_kmsg_hdr(char *buffer, bool *compressed) +{ + char *ptr = buffer; + *compressed = false; + + if (strncmp(RAMOOPS_KERNMSG_HDR, ptr, strlen(RAMOOPS_KERNMSG_HDR)) != 0) + return 0; + + ptr += strlen(RAMOOPS_KERNMSG_HDR); + + ptr = strchr(ptr, '\n'); + if (!ptr) + return 0; + + if (ptr[-2] == '-' && ptr[-1] == 'C') + *compressed = true; + + return ptr - buffer + 1; +} + +/** + * pstore_get_buffer() - Get unwrapped record buffer + * @sig: Signature to check + * @buffer: Buffer containing wrapped record + * @size: wrapped record size + * @dest: Buffer used to store unwrapped record + * + * The record starts with <signature><start><size> header. + * The signature is 'DBGC' for all records except for Ftrace's record(s) wich + * use LINUX_VERSION_CODE ^ 'DBGC'. + * Use 0 for @sig to prevent checking signature. + * Start and size are 4 bytes long. + * + * Return: record's length + */ +static u32 pstore_get_buffer(u32 sig, phys_addr_t buffer, u32 size, char *dest) +{ + struct persistent_ram_buffer *prb = + (struct persistent_ram_buffer *)map_sysmem(buffer, size); + u32 dest_size; + + if (sig == 0 || prb->sig == sig) { + if (prb->size == 0) { + log_debug("found existing empty buffer\n"); + return 0; + } + + if (prb->size > size) { + log_debug("found existing invalid buffer, size %u, start %u\n", + prb->size, prb->start); + return 0; + } + } else { + log_debug("no valid data in buffer (sig = 0x%08x)\n", prb->sig); + return 0; + } + + log_debug("found existing buffer, size %u, start %u\n", + prb->size, prb->start); + + memcpy(dest, &prb->data[prb->start], prb->size - prb->start); + memcpy(dest + prb->size - prb->start, &prb->data[0], prb->start); + + dest_size = prb->size; + unmap_sysmem(prb); + + return dest_size; +} + +/** + * pstore_init_buffer_size() - Init buffer size to largest record size + * + * Records, console, FTrace and user logs can use different buffer sizes. + * This function allows to retrieve the biggest one. + */ +static void pstore_init_buffer_size(void) +{ + if (pstore_record_size > buffer_size) + buffer_size = pstore_record_size; + + if (pstore_console_size > buffer_size) + buffer_size = pstore_console_size; + + if (pstore_ftrace_size > buffer_size) + buffer_size = pstore_ftrace_size; + + if (pstore_pmsg_size > buffer_size) + buffer_size = pstore_pmsg_size; +} + +/** + * pstore_set() - Initialize PStore settings from command line arguments + * @cmdtp: Command data struct pointer + * @flag: Command flag + * @argc: Command-line argument count + * @argv: Array of command-line arguments + * + * Set pstore reserved memory info, starting at 'addr' for 'len' bytes. + * Default length for records is 4K. + * Mandatory arguments: + * - addr: ramoops starting address + * - len: ramoops total length + * Optional arguments: + * - record-size: size of one panic or oops record ('dump' type) + * - console-size: size of the kernel logs record + * - ftrace-size: size of the ftrace record(s), this can be a single record or + * divided in parts based on number of CPUs + * - pmsg-size: size of the user space logs record + * - ecc-size: enables/disables ECC support and specifies ECC buffer size in + * bytes (0 disables it, 1 is a special value, means 16 bytes ECC) + * + * Return: zero on success, CMD_RET_USAGE in case of misuse and negative + * on error. + */ +static int pstore_set(struct cmd_tbl *cmdtp, int flag, int argc, + char * const argv[]) +{ + if (argc < 3) + return CMD_RET_USAGE; + + /* Address is specified since argc > 2 + */ + pstore_addr = simple_strtoul(argv[1], NULL, 16); + + /* Length is specified since argc > 2 + */ + pstore_length = simple_strtoul(argv[2], NULL, 16); + + if (argc > 3) + pstore_record_size = simple_strtoul(argv[3], NULL, 16); + + if (argc > 4) + pstore_console_size = simple_strtoul(argv[4], NULL, 16); + + if (argc > 5) + pstore_ftrace_size = simple_strtoul(argv[5], NULL, 16); + + if (argc > 6) + pstore_pmsg_size = simple_strtoul(argv[6], NULL, 16); + + if (argc > 7) + pstore_ecc_size = simple_strtoul(argv[7], NULL, 16); + + if (pstore_length < (pstore_record_size + pstore_console_size + + pstore_ftrace_size + pstore_pmsg_size)) { + printf("pstore <len> should be larger than the sum of all records sizes\n"); + pstore_length = 0; + } + + log_debug("pstore set done: start 0x%08llx - length 0x%llx\n", + (unsigned long long)pstore_addr, + (unsigned long long)pstore_length); + + return 0; +} + +/** + * pstore_print_buffer() - Print buffer + * @type: buffer type + * @buffer: buffer to print + * @size: buffer size + * + * Print buffer type and content + */ +static void pstore_print_buffer(char *type, char *buffer, u32 size) +{ + u32 i = 0; + + printf("**** %s\n", type); + while (i < size && buffer[i] != 0) { + putc(buffer[i]); + i++; + } +} + +/** + * pstore_display() - Display existing records in pstore reserved memory + * @cmdtp: Command data struct pointer + * @flag: Command flag + * @argc: Command-line argument count + * @argv: Array of command-line arguments + * + * A 'record-type' can be given to only display records of this kind. + * If no 'record-type' is given, all valid records are dispayed. + * 'record-type' can be one of 'dump', 'console', 'ftrace' or 'user'. For 'dump' + * and 'ftrace' types, a 'nb' can be given to only display one record. + * + * Return: zero on success, CMD_RET_USAGE in case of misuse and negative + * on error. + */ +static int pstore_display(struct cmd_tbl *cmdtp, int flag, int argc, + char * const argv[]) +{ + int type = PSTORE_TYPE_ALL; + phys_addr_t ptr; + char *buffer; + u32 size; + int header_len = 0; + bool compressed; + + if (argc > 1) { + if (!strcmp(argv[1], "dump")) + type = PSTORE_TYPE_DMESG; + else if (!strcmp(argv[1], "console")) + type = PSTORE_TYPE_CONSOLE; + else if (!strcmp(argv[1], "ftrace")) + type = PSTORE_TYPE_FTRACE; + else if (!strcmp(argv[1], "user")) + type = PSTORE_TYPE_PMSG; + else + return CMD_RET_USAGE; + } + + if (pstore_length == 0) { + printf("Please set PStore configuration\n"); + return CMD_RET_USAGE; + } + + if (buffer_size == 0) + pstore_init_buffer_size(); + + buffer = malloc_cache_aligned(buffer_size); + + if (type == PSTORE_TYPE_DMESG || type == PSTORE_TYPE_ALL) { + ptr = pstore_addr; + phys_addr_t ptr_end = ptr + pstore_length - pstore_pmsg_size + - pstore_ftrace_size - pstore_console_size; + + if (argc > 2) { + ptr += simple_strtoul(argv[2], NULL, 10) + * pstore_record_size; + ptr_end = ptr + pstore_record_size; + } + + while (ptr < ptr_end) { + size = pstore_get_buffer(PERSISTENT_RAM_SIG, ptr, + pstore_record_size, buffer); + ptr += pstore_record_size; + + if (size == 0) + continue; + + header_len = pstore_read_kmsg_hdr(buffer, &compressed); + if (header_len == 0) { + log_debug("no valid kernel header\n"); + continue; + } + + if (compressed) { + printf("Compressed buffer, display not available\n"); + continue; + } + + pstore_print_buffer("Dump", buffer + header_len, + size - header_len); + } + } + + if (type == PSTORE_TYPE_CONSOLE || type == PSTORE_TYPE_ALL) { + ptr = pstore_addr + pstore_length - pstore_pmsg_size + - pstore_ftrace_size - pstore_console_size; + size = pstore_get_buffer(PERSISTENT_RAM_SIG, ptr, + pstore_console_size, buffer); + if (size != 0) + pstore_print_buffer("Console", buffer, size); + } + + if (type == PSTORE_TYPE_FTRACE || type == PSTORE_TYPE_ALL) { + ptr = pstore_addr + pstore_length - pstore_pmsg_size + - pstore_ftrace_size; + /* The FTrace record(s) uses LINUX_VERSION_CODE ^ 'DBGC' + * signature, pass 0 to pstore_get_buffer to prevent + * checking it + */ + size = pstore_get_buffer(0, ptr, pstore_ftrace_size, buffer); + if (size != 0) + pstore_print_buffer("FTrace", buffer, size); + } + + if (type == PSTORE_TYPE_PMSG || type == PSTORE_TYPE_ALL) { + ptr = pstore_addr + pstore_length - pstore_pmsg_size; + size = pstore_get_buffer(PERSISTENT_RAM_SIG, ptr, + pstore_pmsg_size, buffer); + if (size != 0) + pstore_print_buffer("User", buffer, size); + } + + free(buffer); + + return 0; +} + +/** + * pstore_save() - Save existing records from pstore reserved memory + * @cmdtp: Command data struct pointer + * @flag: Command flag + * @argc: Command-line argument count + * @argv: Array of command-line arguments + * + * the records are saved under 'directory path', which should already exist, + * to partition 'part' on device type 'interface' instance 'dev' + * Filenames are automatically generated, depending on record type, like in + * /sys/fs/pstore under Linux + * + * Return: zero on success, CMD_RET_USAGE in case of misuse and negative + * on error. + */ +static int pstore_save(struct cmd_tbl *cmdtp, int flag, int argc, + char * const argv[]) +{ + phys_addr_t ptr, ptr_end; + char *buffer; + char *save_argv[6]; + char addr[19], length[19]; + char path[256]; + u32 size; + unsigned int index; + int header_len = 0; + bool compressed; + + if (argc < 4) + return CMD_RET_USAGE; + + if (pstore_length == 0) { + printf("Please set PStore configuration\n"); + return CMD_RET_USAGE; + } + + if (buffer_size == 0) + pstore_init_buffer_size(); + + buffer = malloc_cache_aligned(buffer_size); + sprintf(addr, "0x%p", buffer); + + save_argv[0] = argv[0]; + save_argv[1] = argv[1]; + save_argv[2] = argv[2]; + save_argv[3] = addr; + save_argv[4] = path; + save_argv[5] = length; + + /* Save all Dump records */ + ptr = pstore_addr; + ptr_end = ptr + pstore_length - pstore_pmsg_size - pstore_ftrace_size + - pstore_console_size; + index = 0; + while (ptr < ptr_end) { + size = pstore_get_buffer(PERSISTENT_RAM_SIG, ptr, + pstore_record_size, buffer); + ptr += pstore_record_size; + + if (size == 0) + continue; + + header_len = pstore_read_kmsg_hdr(buffer, &compressed); + if (header_len == 0) { + log_debug("no valid kernel header\n"); + continue; + } + + sprintf(addr, "0x%08lx", (ulong)map_to_sysmem(buffer + header_len)); + sprintf(length, "0x%X", size - header_len); + sprintf(path, "%s/dmesg-ramoops-%u%s", argv[3], index, + compressed ? ".enc.z" : ""); + do_save(cmdtp, flag, 6, save_argv, FS_TYPE_ANY); + index++; + } + + sprintf(addr, "0x%08lx", (ulong)map_to_sysmem(buffer)); + + /* Save Console record */ + size = pstore_get_buffer(PERSISTENT_RAM_SIG, ptr, pstore_console_size, + buffer); + if (size != 0) { + sprintf(length, "0x%X", size); + sprintf(path, "%s/console-ramoops-0", argv[3]); + do_save(cmdtp, flag, 6, save_argv, FS_TYPE_ANY); + } + ptr += pstore_console_size; + + /* Save FTrace record(s) + * The FTrace record(s) uses LINUX_VERSION_CODE ^ 'DBGC' signature, + * pass 0 to pstore_get_buffer to prevent checking it + */ + size = pstore_get_buffer(0, ptr, pstore_ftrace_size, buffer); + if (size != 0) { + sprintf(length, "0x%X", size); + sprintf(path, "%s/ftrace-ramoops-0", argv[3]); + do_save(cmdtp, flag, 6, save_argv, FS_TYPE_ANY); + } + ptr += pstore_ftrace_size; + + /* Save Console record */ + size = pstore_get_buffer(PERSISTENT_RAM_SIG, ptr, pstore_pmsg_size, + buffer); + if (size != 0) { + sprintf(length, "0x%X", size); + sprintf(path, "%s/pmsg-ramoops-0", argv[3]); + do_save(cmdtp, flag, 6, save_argv, FS_TYPE_ANY); + } + + free(buffer); + + return 0; +} + +static struct cmd_tbl cmd_pstore_sub[] = { + U_BOOT_CMD_MKENT(set, 8, 0, pstore_set, "", ""), + U_BOOT_CMD_MKENT(display, 3, 0, pstore_display, "", ""), + U_BOOT_CMD_MKENT(save, 4, 0, pstore_save, "", ""), +}; + +static int do_pstore(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[]) +{ + struct cmd_tbl *c; + + if (argc < 2) + return CMD_RET_USAGE; + + /* Strip off leading argument */ + argc--; + argv++; + + c = find_cmd_tbl(argv[0], cmd_pstore_sub, ARRAY_SIZE(cmd_pstore_sub)); + + if (!c) + return CMD_RET_USAGE; + + return c->cmd(cmdtp, flag, argc, argv); +} + +void fdt_fixup_pstore(void *blob) +{ + char node[32]; + int nodeoffset; /* node offset from libfdt */ + + nodeoffset = fdt_path_offset(blob, "/"); + if (nodeoffset < 0) { + /* Not found or something else bad happened. */ + log_err("fdt_path_offset() returned %s\n", fdt_strerror(nodeoffset)); + return; + } + + nodeoffset = fdt_add_subnode(blob, nodeoffset, "reserved-memory"); + if (nodeoffset < 0) { + log_err("Add 'reserved-memory' node failed: %s\n", + fdt_strerror(nodeoffset)); + return; + } + fdt_setprop_u32(blob, nodeoffset, "#address-cells", 2); + fdt_setprop_u32(blob, nodeoffset, "#size-cells", 2); + fdt_setprop_empty(blob, nodeoffset, "ranges"); + + sprintf(node, "ramoops@%llx", (unsigned long long)pstore_addr); + nodeoffset = fdt_add_subnode(blob, nodeoffset, node); + if (nodeoffset < 0) { + log_err("Add '%s' node failed: %s\n", node, fdt_strerror(nodeoffset)); + return; + } + fdt_setprop_string(blob, nodeoffset, "compatible", "ramoops"); + fdt_setprop_u64(blob, nodeoffset, "reg", pstore_addr); + fdt_appendprop_u64(blob, nodeoffset, "reg", pstore_length); + fdt_setprop_u32(blob, nodeoffset, "record-size", pstore_record_size); + fdt_setprop_u32(blob, nodeoffset, "console-size", pstore_console_size); + fdt_setprop_u32(blob, nodeoffset, "ftrace-size", pstore_ftrace_size); + fdt_setprop_u32(blob, nodeoffset, "pmsg-size", pstore_pmsg_size); + fdt_setprop_u32(blob, nodeoffset, "ecc-size", pstore_ecc_size); +} + +U_BOOT_CMD(pstore, 10, 0, do_pstore, + "Manage Linux Persistent Storage", + "set <addr> <len> [record-size] [console-size] [ftrace-size] [pmsg_size] [ecc-size]\n" + "- Set pstore reserved memory info, starting at 'addr' for 'len' bytes.\n" + " Default length for records is 4K.\n" + " 'record-size' is the size of one panic or oops record ('dump' type).\n" + " 'console-size' is the size of the kernel logs record.\n" + " 'ftrace-size' is the size of the ftrace record(s), this can be a single\n" + " record or divided in parts based on number of CPUs.\n" + " 'pmsg-size' is the size of the user space logs record.\n" + " 'ecc-size' enables/disables ECC support and specifies ECC buffer size in\n" + " bytes (0 disables it, 1 is a special value, means 16 bytes ECC).\n" + "pstore display [record-type] [nb]\n" + "- Display existing records in pstore reserved memory. A 'record-type' can\n" + " be given to only display records of this kind. 'record-type' can be one\n" + " of 'dump', 'console', 'ftrace' or 'user'. For 'dump' and 'ftrace' types,\n" + " a 'nb' can be given to only display one record.\n" + "pstore save <interface> <dev[:part]> <directory-path>\n" + "- Save existing records in pstore reserved memory under 'directory path'\n" + " to partition 'part' on device type 'interface' instance 'dev'.\n" + " Filenames are automatically generated, depending on record type, like\n" + " in /sys/fs/pstore under Linux.\n" + " The 'directory-path' should already exist.\n" +); diff --git a/cmd/sleep.c b/cmd/sleep.c new file mode 100644 index 00000000000..f0c78a8efb6 --- /dev/null +++ b/cmd/sleep.c @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2001 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + */ + +#include <common.h> +#include <command.h> +#include <console.h> +#include <linux/delay.h> + +static int do_sleep(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + ulong start = get_timer(0); + ulong mdelay = 0; + ulong delay; + char *frpart; + + if (argc != 2) + return CMD_RET_USAGE; + + delay = simple_strtoul(argv[1], NULL, 10) * CONFIG_SYS_HZ; + + frpart = strchr(argv[1], '.'); + + if (frpart) { + uint mult = CONFIG_SYS_HZ / 10; + for (frpart++; *frpart != '\0' && mult > 0; frpart++) { + if (*frpart < '0' || *frpart > '9') { + mdelay = 0; + break; + } + mdelay += (*frpart - '0') * mult; + mult /= 10; + } + } + + delay += mdelay; + + while (get_timer(start) < delay) { + if (ctrlc()) + return (-1); + + udelay(100); + } + + return 0; +} + +U_BOOT_CMD( + sleep , 2, 1, do_sleep, + "delay execution for some time", + "N\n" + " - delay execution for N seconds (N is _decimal_ and can be\n" + " fractional)" +); diff --git a/cmd/timer.c b/cmd/timer.c new file mode 100644 index 00000000000..551be5dd54e --- /dev/null +++ b/cmd/timer.c @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2001 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + */ + +#include <common.h> +#include <command.h> + +static int do_timer(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + static ulong start; + + if (argc != 2) + return CMD_RET_USAGE; + + if (!strcmp(argv[1], "start")) + start = get_timer(0); + + if (!strcmp(argv[1], "get")) { + ulong msecs = get_timer(start) * 1000 / CONFIG_SYS_HZ; + printf("%ld.%03d\n", msecs / 1000, (int)(msecs % 1000)); + } + + return 0; +} + +U_BOOT_CMD( + timer, 2, 1, do_timer, + "access the system timer", + "start - Reset the timer reference.\n" + "timer get - Print the time since 'start'." +); |