// SPDX-License-Identifier: GPL-2.0+ /* * (C) Copyright 2000-2002 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. */ #include #include #include #include #include #include #include #include char *display_options_get_banner_priv(bool newlines, const char *build_tag, char *buf, int size) { int len; len = snprintf(buf, size, "%s%s", newlines ? "\n\n" : "", version_string); if (build_tag && len < size) len += snprintf(buf + len, size - len, ", Build: %s", build_tag); if (len > size - 3) len = size - 3; if (len < 0) len = 0; snprintf(buf + len, size - len, "\n\n"); return buf; } #ifndef BUILD_TAG #define BUILD_TAG NULL #endif char *display_options_get_banner(bool newlines, char *buf, int size) { return display_options_get_banner_priv(newlines, BUILD_TAG, buf, size); } int display_options(void) { char buf[DISPLAY_OPTIONS_BANNER_LENGTH]; display_options_get_banner(true, buf, sizeof(buf)); printf("%s", buf); return 0; } void print_freq(uint64_t freq, const char *s) { unsigned long m = 0; uint32_t f; static const char names[] = {'G', 'M', 'k'}; unsigned long d = 1e9; char c = 0; unsigned int i; for (i = 0; i < ARRAY_SIZE(names); i++, d /= 1000) { if (freq >= d) { c = names[i]; break; } } if (!c) { printf("%llu Hz%s", freq, s); return; } f = do_div(freq, d); /* If there's a remainder, show the first few digits */ if (f) { m = f; while (m > 1000) m /= 10; while (m && !(m % 10)) m /= 10; if (m >= 100) m = (m / 10) + (m % 100 >= 50); } printf("%lu", (unsigned long) freq); if (m) printf(".%ld", m); printf(" %cHz%s", c, s); } void print_size(uint64_t size, const char *s) { unsigned long m = 0, n; uint64_t f; static const char names[] = {'E', 'P', 'T', 'G', 'M', 'K'}; unsigned long d = 10 * ARRAY_SIZE(names); char c = 0; unsigned int i; for (i = 0; i < ARRAY_SIZE(names); i++, d -= 10) { if (size >> d) { c = names[i]; break; } } if (!c) { /* * SPL tiny-printf is not capable for printing uint64_t. * We have just checked that the size is small enought to fit * unsigned int safely. */ printf("%u Bytes%s", (unsigned int)size, s); return; } n = size >> d; f = size & ((1ULL << d) - 1); /* If there's a remainder, deal with it */ if (f) { m = (10ULL * f + (1ULL << (d - 1))) >> d; if (m >= 10) { m -= 10; n += 1; if (n == 1024 && i > 0) { n = 1; m = 0; c = names[i - 1]; } } } printf ("%lu", n); if (m) { printf (".%ld", m); } printf (" %ciB%s", c, s); } #define MAX_LINE_LENGTH_BYTES 64 #define DEFAULT_LINE_LENGTH_BYTES 16 int hexdump_line(ulong addr, const void *data, uint width, uint count, uint linelen, char *out, int size) { /* linebuf as a union causes proper alignment */ union linebuf { uint64_t uq[MAX_LINE_LENGTH_BYTES/sizeof(uint64_t) + 1]; uint32_t ui[MAX_LINE_LENGTH_BYTES/sizeof(uint32_t) + 1]; uint16_t us[MAX_LINE_LENGTH_BYTES/sizeof(uint16_t) + 1]; uint8_t uc[MAX_LINE_LENGTH_BYTES/sizeof(uint8_t) + 1]; } lb; uint thislinelen; int i; ulong x; if (linelen * width > MAX_LINE_LENGTH_BYTES) linelen = MAX_LINE_LENGTH_BYTES / width; if (linelen < 1) linelen = DEFAULT_LINE_LENGTH_BYTES / width; /* * Check the size here so that we don't need to use snprintf(). This * helps to reduce code size */ if (size < HEXDUMP_MAX_BUF_LENGTH(linelen * width)) return -ENOSPC; thislinelen = linelen; out += sprintf(out, "%08lx:", addr); /* check for overflow condition */ if (count < thislinelen) thislinelen = count; /* Copy from memory into linebuf and print hex values */ for (i = 0; i < thislinelen; i++) { if (width == 4) x = lb.ui[i] = *(volatile uint32_t *)data; else if (MEM_SUPPORT_64BIT_DATA && width == 8) x = lb.uq[i] = *(volatile ulong *)data; else if (width == 2) x = lb.us[i] = *(volatile uint16_t *)data; else x = lb.uc[i] = *(volatile uint8_t *)data; if (CONFIG_IS_ENABLED(USE_TINY_PRINTF)) out += sprintf(out, " %x", (uint)x); else out += sprintf(out, " %0*lx", width * 2, x); data += width; } /* fill line with whitespace for nice ASCII print */ for (i = 0; i < (linelen - thislinelen) * (width * 2 + 1); i++) *out++ = ' '; /* Print data in ASCII characters */ for (i = 0; i < thislinelen * width; i++) { if (!isprint(lb.uc[i]) || lb.uc[i] >= 0x80) lb.uc[i] = '.'; } lb.uc[i] = '\0'; out += sprintf(out, " %s", lb.uc); return thislinelen; } int print_buffer(ulong addr, const void *data, uint width, uint count, uint linelen) { if (linelen*width > MAX_LINE_LENGTH_BYTES) linelen = MAX_LINE_LENGTH_BYTES / width; if (linelen < 1) linelen = DEFAULT_LINE_LENGTH_BYTES / width; while (count) { uint thislinelen; char buf[HEXDUMP_MAX_BUF_LENGTH(width * linelen)]; thislinelen = hexdump_line(addr, data, width, count, linelen, buf, sizeof(buf)); assert(thislinelen >= 0); puts(buf); putc('\n'); /* update references */ data += thislinelen * width; addr += thislinelen * width; count -= thislinelen; if (!IS_ENABLED(CONFIG_SPL_BUILD) && ctrlc()) return -EINTR; } return 0; }