uboot/lib/display_options.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * (C) Copyright 2000-2002
   4 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
   5 */
   6
   7#include <common.h>
   8#include <compiler.h>
   9#include <console.h>
  10#include <div64.h>
  11#include <version.h>
  12#include <linux/ctype.h>
  13#include <asm/io.h>
  14
  15char *display_options_get_banner_priv(bool newlines, const char *build_tag,
  16                                      char *buf, int size)
  17{
  18        int len;
  19
  20        len = snprintf(buf, size, "%s%s", newlines ? "\n\n" : "",
  21                       version_string);
  22        if (build_tag && len < size)
  23                len += snprintf(buf + len, size - len, ", Build: %s",
  24                                build_tag);
  25        if (len > size - 3)
  26                len = size - 3;
  27        if (len < 0)
  28                len = 0;
  29        snprintf(buf + len, size - len, "\n\n");
  30
  31        return buf;
  32}
  33
  34#ifndef BUILD_TAG
  35#define BUILD_TAG NULL
  36#endif
  37
  38char *display_options_get_banner(bool newlines, char *buf, int size)
  39{
  40        return display_options_get_banner_priv(newlines, BUILD_TAG, buf, size);
  41}
  42
  43int display_options(void)
  44{
  45        char buf[DISPLAY_OPTIONS_BANNER_LENGTH];
  46
  47        display_options_get_banner(true, buf, sizeof(buf));
  48        printf("%s", buf);
  49
  50        return 0;
  51}
  52
  53void print_freq(uint64_t freq, const char *s)
  54{
  55        unsigned long m = 0;
  56        uint32_t f;
  57        static const char names[] = {'G', 'M', 'k'};
  58        unsigned long d = 1e9;
  59        char c = 0;
  60        unsigned int i;
  61
  62        for (i = 0; i < ARRAY_SIZE(names); i++, d /= 1000) {
  63                if (freq >= d) {
  64                        c = names[i];
  65                        break;
  66                }
  67        }
  68
  69        if (!c) {
  70                printf("%llu Hz%s", freq, s);
  71                return;
  72        }
  73
  74        f = do_div(freq, d);
  75
  76        /* If there's a remainder, show the first few digits */
  77        if (f) {
  78                m = f;
  79                while (m > 1000)
  80                        m /= 10;
  81                while (m && !(m % 10))
  82                        m /= 10;
  83                if (m >= 100)
  84                        m = (m / 10) + (m % 100 >= 50);
  85        }
  86
  87        printf("%lu", (unsigned long) freq);
  88        if (m)
  89                printf(".%ld", m);
  90        printf(" %cHz%s", c, s);
  91}
  92
  93void print_size(uint64_t size, const char *s)
  94{
  95        unsigned long m = 0, n;
  96        uint64_t f;
  97        static const char names[] = {'E', 'P', 'T', 'G', 'M', 'K'};
  98        unsigned long d = 10 * ARRAY_SIZE(names);
  99        char c = 0;
 100        unsigned int i;
 101
 102        for (i = 0; i < ARRAY_SIZE(names); i++, d -= 10) {
 103                if (size >> d) {
 104                        c = names[i];
 105                        break;
 106                }
 107        }
 108
 109        if (!c) {
 110                /*
 111                 * SPL tiny-printf is not capable for printing uint64_t.
 112                 * We have just checked that the size is small enought to fit
 113                 * unsigned int safely.
 114                 */
 115                printf("%u Bytes%s", (unsigned int)size, s);
 116                return;
 117        }
 118
 119        n = size >> d;
 120        f = size & ((1ULL << d) - 1);
 121
 122        /* If there's a remainder, deal with it */
 123        if (f) {
 124                m = (10ULL * f + (1ULL << (d - 1))) >> d;
 125
 126                if (m >= 10) {
 127                        m -= 10;
 128                        n += 1;
 129                }
 130        }
 131
 132        printf ("%lu", n);
 133        if (m) {
 134                printf (".%ld", m);
 135        }
 136        printf (" %ciB%s", c, s);
 137}
 138
 139#define MAX_LINE_LENGTH_BYTES           64
 140#define DEFAULT_LINE_LENGTH_BYTES       16
 141
 142int hexdump_line(ulong addr, const void *data, uint width, uint count,
 143                 uint linelen, char *out, int size)
 144{
 145        /* linebuf as a union causes proper alignment */
 146        union linebuf {
 147                uint64_t uq[MAX_LINE_LENGTH_BYTES/sizeof(uint64_t) + 1];
 148                uint32_t ui[MAX_LINE_LENGTH_BYTES/sizeof(uint32_t) + 1];
 149                uint16_t us[MAX_LINE_LENGTH_BYTES/sizeof(uint16_t) + 1];
 150                uint8_t  uc[MAX_LINE_LENGTH_BYTES/sizeof(uint8_t) + 1];
 151        } lb;
 152        uint thislinelen;
 153        int i;
 154        ulong x;
 155
 156        if (linelen * width > MAX_LINE_LENGTH_BYTES)
 157                linelen = MAX_LINE_LENGTH_BYTES / width;
 158        if (linelen < 1)
 159                linelen = DEFAULT_LINE_LENGTH_BYTES / width;
 160
 161        /*
 162         * Check the size here so that we don't need to use snprintf(). This
 163         * helps to reduce code size
 164         */
 165        if (size < HEXDUMP_MAX_BUF_LENGTH(linelen * width))
 166                return -ENOSPC;
 167
 168        thislinelen = linelen;
 169        out += sprintf(out, "%08lx:", addr);
 170
 171        /* check for overflow condition */
 172        if (count < thislinelen)
 173                thislinelen = count;
 174
 175        /* Copy from memory into linebuf and print hex values */
 176        for (i = 0; i < thislinelen; i++) {
 177                if (width == 4)
 178                        x = lb.ui[i] = *(volatile uint32_t *)data;
 179                else if (MEM_SUPPORT_64BIT_DATA && width == 8)
 180                        x = lb.uq[i] = *(volatile ulong *)data;
 181                else if (width == 2)
 182                        x = lb.us[i] = *(volatile uint16_t *)data;
 183                else
 184                        x = lb.uc[i] = *(volatile uint8_t *)data;
 185                if (CONFIG_IS_ENABLED(USE_TINY_PRINTF))
 186                        out += sprintf(out, " %x", (uint)x);
 187                else
 188                        out += sprintf(out, " %0*lx", width * 2, x);
 189                data += width;
 190        }
 191
 192        /* fill line with whitespace for nice ASCII print */
 193        for (i = 0; i < (linelen - thislinelen) * (width * 2 + 1); i++)
 194                *out++ = ' ';
 195
 196        /* Print data in ASCII characters */
 197        for (i = 0; i < thislinelen * width; i++) {
 198                if (!isprint(lb.uc[i]) || lb.uc[i] >= 0x80)
 199                        lb.uc[i] = '.';
 200        }
 201        lb.uc[i] = '\0';
 202        out += sprintf(out, "  %s", lb.uc);
 203
 204        return thislinelen;
 205}
 206
 207int print_buffer(ulong addr, const void *data, uint width, uint count,
 208                 uint linelen)
 209{
 210        if (linelen*width > MAX_LINE_LENGTH_BYTES)
 211                linelen = MAX_LINE_LENGTH_BYTES / width;
 212        if (linelen < 1)
 213                linelen = DEFAULT_LINE_LENGTH_BYTES / width;
 214
 215        while (count) {
 216                uint thislinelen;
 217                char buf[HEXDUMP_MAX_BUF_LENGTH(width * linelen)];
 218
 219                thislinelen = hexdump_line(addr, data, width, count, linelen,
 220                                           buf, sizeof(buf));
 221                assert(thislinelen >= 0);
 222                puts(buf);
 223                putc('\n');
 224
 225                /* update references */
 226                data += thislinelen * width;
 227                addr += thislinelen * width;
 228                count -= thislinelen;
 229
 230                if (!IS_ENABLED(CONFIG_SPL_BUILD) && ctrlc())
 231                        return -EINTR;
 232        }
 233
 234        return 0;
 235}
 236