blob: 0b825d7e8c75f3b18933d3e3f77e5f40f2c7b658 [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0
/* Small "fetch" utility for U-Boot */
#ifdef CONFIG_ARM64
#include <asm/system.h>
#endif
#include <dm/device.h>
#include <dm/uclass-internal.h>
#include <display_options.h>
#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 * const 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 "::-" YELLOW "=+**###%%%%%%%%###**+= " 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,
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)
};
/*
* TODO/ideas:
* - Refactor to not use a for loop
* - Handle multiple network interfaces
* - Include stats about number of bound/probed devices
* - Show U-Boot's size and malloc usage, fdt size, etc.
*/
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;
size_t size;
ofnode np;
struct udevice *dev;
struct blk_desc *desc;
bool skip_ascii = false;
if (argc > 1 && strcmp(argv[1], "-n") == 0) {
skip_ascii = true;
num_lines = LAST_LINE;
}
for (int line = 0; line < num_lines; line++) {
if (!skip_ascii) {
if (line < ARRAY_SIZE(logo_lines))
printf("%s ", logo_lines[line]);
else
printf("%*c ", LINE_WIDTH, ' ');
}
switch (line) {
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:
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("ipaddr");
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);
printf("Commands:" RESET " %d (help)\n", n_cmds);
break;
case CONSOLES:
printf("Consoles:" RESET " %s", env_get("stdout"));
if (gd->baudrate)
printf(" (%d baud)", gd->baudrate);
putc('\n');
break;
case FEATURES:
printf("Features:" RESET " ");
if (IS_ENABLED(CONFIG_NET))
printf("Net");
if (IS_ENABLED(CONFIG_EFI_LOADER))
printf(", EFI");
if (IS_ENABLED(CONFIG_CMD_CAT))
printf(", cat :3");
#ifdef CONFIG_ARM64
switch (current_el()) {
case 2:
printf(", VMs");
break;
case 3:
printf(", full control!");
break;
}
#endif
printf("\n");
break;
case RELOCATION:
if (gd->flags & GD_FLG_SKIP_RELOC)
printf("Relocated:" RESET " no\n");
else
printf("Relocated:" RESET " to %#011lx\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:
for (int j = 0; j < CONFIG_NR_DRAM_BANKS && gd->bd->bi_dram[j].size; j++)
size += gd->bd->bi_dram[j].size;
printf("Memory:" RESET " ");
print_size(size, "\n");
break;
case STORAGE:
default:
ret = uclass_find_device_by_seq(UCLASS_BLK, line - STORAGE, &dev);
if (!ret && dev) {
desc = dev_get_uclass_plat(dev);
size = desc->lba * desc->blksz;
printf("%4s %d: " RESET, blk_get_uclass_name(desc->uclass_id),
desc->lun);
if (size)
print_size(size, "");
else
printf("No media");
} else if (ret == -ENODEV && (skip_ascii || line > ARRAY_SIZE(logo_lines))) {
break;
}
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"
);