[PATCH] cmd: add a fetch utility

Heinrich Schuchardt xypron.glpk at gmx.de
Fri Aug 9 08:18:43 CEST 2024



Am 8. August 2024 18:24:24 MESZ schrieb Caleb Connolly <caleb.connolly at linaro.org>:
>While U-Boot does a pretty good job at printing information at startup
>about what hardware it's running on, it can be hard to take pretty
>pictures of this to show off on the internet (by far the most
>important aspect of porting a device in 2024!).
>
>Add a small utility "ufetch" for displaying some information about U-Boot and
>the hardware it's running on in a similar fashion to the popular neofetch tool
>for *nix's [1].
>
>While the output is meant to be useful, it should also be pleasing to look at
>and look good in screenshots. The ufetch command brings this to U-Boot,
>featuring a colorful ASCII art version of the U-Boot logo and a fancy layout.
>
>Finally, tireless device porters can properly show off their hard work and get
>the internet points they so deserve!
>
>Not everything is fully supported yet, but this seemed good enough for initial
>inclusion. Only one MMC device is detected, and other than SCSI other storage
>devices aren't supported.


This command is not very generic. E.g. it supports SCSI drives but not SATA. Many boards have eMMC and SD-card. This lks more ike an RFC tan something ready to merge.

Why don't you use a script or an EFI program to print whatever information you need?

>
>[1]: https://en.wikipedia.org/wiki/Neofetch
>
>Signed-off-by: Caleb Connolly <caleb.connolly at linaro.org>
>---
>Ephemeral demo image: https://0x0.st/XVUa.png
>---
> cmd/Kconfig  |   7 ++
> cmd/Makefile |   1 +
> cmd/ufetch.c | 201 +++++++++++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 209 insertions(+)
> create mode 100644 cmd/ufetch.c
>
>diff --git a/cmd/Kconfig b/cmd/Kconfig
>index 978f44eda426..70acb5727b04 100644
>--- a/cmd/Kconfig
>+++ b/cmd/Kconfig
>@@ -175,8 +175,15 @@ config CMD_CPU
> 	  number of CPUs, type (e.g. manufacturer, architecture, product or
> 	  internal name) and clock frequency. Other information may be
> 	  available depending on the CPU driver.
> 
>+config CMD_UFETCH
>+	bool "U-Boot fetch"
>+	depends on BLK
>+	help
>+	  Fetch utility for U-Boot (akin to neofetch). Prints information
>+	  about U-Boot and the board it is running on in a pleasing format.
>+
> config CMD_FWU_METADATA
> 	bool "fwu metadata read"
> 	depends on FWU_MULTI_BANK_UPDATE
> 	help
>diff --git a/cmd/Makefile b/cmd/Makefile
>index 87133cc27a8a..ffb04c8f2e0a 100644
>--- a/cmd/Makefile
>+++ b/cmd/Makefile
>@@ -53,8 +53,9 @@ obj-$(CONFIG_CMD_CONSOLE) += console.o
> obj-$(CONFIG_CMD_CPU) += cpu.o
> obj-$(CONFIG_CMD_DATE) += date.o
> obj-$(CONFIG_CMD_DEMO) += demo.o
> obj-$(CONFIG_CMD_DM) += dm.o
>+obj-$(CONFIG_CMD_UFETCH) += ufetch.o
> obj-$(CONFIG_CMD_SOUND) += sound.o
> ifdef CONFIG_POST
> obj-$(CONFIG_CMD_DIAG) += diag.o
> endif
>diff --git a/cmd/ufetch.c b/cmd/ufetch.c
>new file mode 100644
>index 000000000000..f7374eb2e364
>--- /dev/null
>+++ b/cmd/ufetch.c
>@@ -0,0 +1,201 @@
>+// SPDX-License-Identifier: GPL-2.0
>+
>+/* Small "fetch" utility for U-Boot */
>+
>+#include <mmc.h>
>+#include <time.h>
>+#include <asm/global_data.h>
>+#include <cli.h>
>+#include <command.h>
>+#include <dm/ofnode.h>
>+#include <env.h>
>+#include <rand.h>
>+#include <vsprintf.h>
>+#include <linux/delay.h>
>+#include <linux/kernel.h>
>+#include <version.h>
>+
>+DECLARE_GLOBAL_DATA_PTR;
>+
>+#define LINE_WIDTH 40
>+#define BLUE "\033[38;5;4m"
>+#define YELLOW "\033[38;5;11m"
>+#define BOLD "\033[1m"
>+#define RESET "\033[0m"
>+static const char *logo_lines[] = {
>+	BLUE BOLD "                  ......::......                   ",
>+	BLUE BOLD "             ...::::::::::::::::::...              ",
>+	BLUE BOLD "          ..::::::::::::::::::::::::::..           ",
>+	BLUE BOLD "        .::::.:::::::::::::::...::::.::::.         ",
>+	BLUE BOLD "      .::::::::::::::::::::..::::::::::::::.       ",
>+	BLUE BOLD "    .::.:::::::::::::::::::" YELLOW "=*%#*" BLUE "::::::::::.::.     ",
>+	BLUE BOLD "   .:::::::::::::::::....." YELLOW "*%%*-" BLUE ":....::::::::::.    ",
>+	BLUE BOLD "  .:.:::...:::::::::.:-" YELLOW "===##*---==-" BLUE "::::::::::.:.   ",
>+	BLUE BOLD " .::::..::::........" YELLOW "-***#****###****-" BLUE "...::::::.:.  ",
>+	BLUE BOLD " ::.:.-" YELLOW "+***+=" BLUE "::-" YELLOW "=+**#%%%%%%%%%%%%###*= " BLUE "-::...::::. ",
>+	BLUE BOLD ".:.::-" YELLOW "*****###%%%%%%%%%%%%%%%%%%%%%%%%%%#*=" BLUE ":..:::: ",
>+	BLUE BOLD ".::" YELLOW "##" BLUE ":" YELLOW "***#%%%%%%#####%%%%%%%####%%%%%####%%%*" BLUE "-.::. ",
>+	BLUE BOLD ":.:" YELLOW "#%" BLUE "::" YELLOW "*%%%%%%%#*****##%%%#*****##%%##*****#%%+" BLUE ".::.",
>+	BLUE BOLD ".::" YELLOW "**==#%%%%%%%##****#%%%%##****#%%%%#****###%%" BLUE ":.. ",
>+	BLUE BOLD "..:" YELLOW "#%" BLUE "::" YELLOW "*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#%%%%%+ " BLUE ".:.",
>+	BLUE BOLD " ::" YELLOW "##" BLUE ":" YELLOW "+**#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%* " BLUE "-.:: ",
>+	BLUE BOLD " ..::-" YELLOW "#****#%#%%%%%%%%%%%%%%%%%%%%%%%%%%#*=" BLUE "-..::.  ",
>+	BLUE BOLD "  ...:=" YELLOW "*****=" BLUE "::-\033[38;5;7m=+**###%%%%%%%%###**+=  " BLUE "--:...:::  ",
>+	BLUE BOLD "   .::.::--:........::::::--::::::......::::::.    ",
>+	BLUE BOLD "    .::.....::::::::::...........:::::::::.::.     ",
>+	BLUE BOLD "      .::::::::::::::::::::::::::::::::::::.       ",
>+	BLUE BOLD "        .::::.::::::::::::::::::::::.::::.         ",
>+	BLUE BOLD "          ..::::::::::::::::::::::::::..           ",
>+	BLUE BOLD "             ...::::::::::::::::::...              ",
>+	BLUE BOLD "                  ......::......                   ",
>+};
>+
>+enum output_lines {
>+	FIRST,
>+	SECOND,
>+	KERNEL,
>+	SYSINFO,
>+	HOST,
>+	UPTIME,
>+	IP,
>+	CMDS,
>+	CONSOLES,
>+	DEVICES,
>+	FEATURES,
>+	RELOCATION,
>+	CORES,
>+	MEMORY,
>+	STORAGE,
>+
>+	/* Up to 10 storage devices... Should be enough for anyone right? */
>+	_LAST_LINE = (STORAGE + 10),
>+#define LAST_LINE (_LAST_LINE - 1UL)
>+};
>+
>+static int do_ufetch(struct cmd_tbl *cmdtp, int flag, int argc,
>+		     char *const argv[])
>+{
>+	int num_lines = max(LAST_LINE + 1, ARRAY_SIZE(logo_lines));
>+	const char *model, *compatible;
>+	char *ipaddr;
>+	int n_cmds, n_cpus = 0, ret, compatlen;
>+	ofnode np;
>+	struct mmc *mmc;
>+	struct blk_desc *scsi_desc;
>+	bool skip_ascii = false;
>+
>+	if (argc > 1 && strcmp(argv[1], "-n") == 0) {
>+		skip_ascii = true;
>+		num_lines = LAST_LINE;
>+	}
>+
>+	for (int i = 0; i < num_lines; i++) {
>+		if (!skip_ascii) {
>+			if (i < ARRAY_SIZE(logo_lines))
>+				printf("%s ", logo_lines[i]);
>+			else
>+				printf("%*c ", LINE_WIDTH, ' ');
>+		}
>+		switch (i) {
>+		case FIRST:
>+			compatible = ofnode_read_string(ofnode_root(), "compatible");
>+			if (!compatible)
>+				compatible = "unknown";
>+			printf(RESET "%s\n", compatible);
>+			compatlen = strlen(compatible);
>+			break;
>+		case SECOND:
>+			for (int j = 0; j < compatlen; j++)
>+				putc('-');
>+			putc('\n');
>+			break;
>+		case KERNEL:

Please, do not use misleading variable names.


>+			printf("Kernel:" RESET " %s\n", U_BOOT_VERSION);
>+			break;
>+		case SYSINFO:
>+			printf("Config:" RESET " %s_defconfig\n", CONFIG_SYS_CONFIG_NAME);
>+			break;
>+		case HOST:
>+			model = ofnode_read_string(ofnode_root(), "model");
>+			if (model)
>+				printf("Host:" RESET " %s\n", model);
>+			break;
>+		case UPTIME:
>+			printf("Uptime:" RESET " %ld seconds\n", get_timer(0) / 1000);
>+			break;
>+		case IP:
>+			ipaddr = env_get("ipvaddr");
>+			if (!ipaddr)
>+				ipaddr = "none";
>+			printf("IP Address:" RESET " %s", ipaddr);
>+			ipaddr = env_get("ipv6addr");
>+			if (ipaddr)
>+				printf(", %s\n", ipaddr);
>+			else
>+				putc('\n');
>+			break;
>+		case CMDS:
>+			n_cmds = ll_entry_count(struct cmd_tbl, cmd);

Who cares if you have 50 commands or 51 if you don't know which?


>+			printf("Commands:" RESET " %d (help)\n", n_cmds);
>+			break;
>+		case CONSOLES:
>+			printf("Consoles:" RESET " %s (%d baud)\n", env_get("stdout"),
>+			       gd->baudrate);
>+			break;
>+		case DEVICES:
>+			printf("Devices:" RESET " ");
>+			/* TODO: walk the DM tree */
>+			printf("Uncountable!\n");

Nothing we should merge.

>+			break;
>+		case FEATURES:
>+			printf("Features:" RESET " ");
>+			if (IS_ENABLED(CONFIG_NET))
>+				printf("Net");

Wouuldn't you want to know which devices where detected?

>+			if (IS_ENABLED(CONFIG_EFI_LOADER))
>+				printf(", EFI");
>+			printf("\n");
>+			break;
>+		case RELOCATION:
>+			if (gd->flags & GD_FLG_SKIP_RELOC)
>+				printf("Relocated:" RESET " no\n");
>+			else
>+				printf("Relocated:" RESET " to %#09lx\n", gd->relocaddr);
>+			break;
>+		case CORES:
>+			ofnode_for_each_subnode(np, ofnode_path("/cpus")) {
>+				if (ofnode_name_eq(np, "cpu"))
>+					n_cpus++;
>+			}
>+			printf("CPU:" RESET " %d (1 in use)\n", n_cpus);
>+			break;
>+		case MEMORY:
>+			printf("Memory:" RESET " %lu MB\n", (ulong)gd->ram_size >> 20);
>+			break;
>+		case STORAGE:
>+		default:
>+			if (i == STORAGE && get_mmc_num() > 0) {
>+				mmc = find_mmc_device(0);
>+				if (mmc)
>+					printf("Storage:" RESET "  mmc 0: %llu MB", mmc->capacity >> 20);

And if my eMMC is device 1 and SD card is 0?

Why wouldn't you iterate over all UCLASS_BLK devices?

Best regards

Heinrich

>+			}
>+			if (i >= STORAGE + 1) {
>+				ret = blk_get_desc(UCLASS_SCSI, i - (STORAGE + 1), &scsi_desc);
>+				if (!ret && scsi_desc->type != DEV_TYPE_UNKNOWN)
>+					/* The calculation here is really lossy but close enough */
>+					printf("Storage:" RESET " scsi %d: %lu MB", i - (STORAGE + 1),
>+					       ((scsi_desc->lba >> 9) * scsi_desc->blksz) >> 11);
>+			}
>+			printf("\n");
>+		}
>+	}
>+
>+	printf(RESET "\n\n");
>+
>+	return 0;
>+}
>+
>+U_BOOT_CMD(ufetch, 2, 1, do_ufetch,
>+	"U-Boot fetch utility",
>+	"Print information about your device.\n"
>+	"    -n    Don't print the ASCII logo"
>+);


More information about the U-Boot mailing list