uboot/common/cmd_log.c
<<
>>
Prefs
   1/*
   2 * (C) Copyright 2002-2007
   3 * Detlev Zundel, DENX Software Engineering, dzu@denx.de.
   4 *
   5 * Code used from linux/kernel/printk.c
   6 * Copyright (C) 1991, 1992  Linus Torvalds
   7 *
   8 * SPDX-License-Identifier:     GPL-2.0+
   9 *
  10 * Comments:
  11 *
  12 * After relocating the code, the environment variable "loglevel" is
  13 * copied to console_loglevel.  The functionality is similar to the
  14 * handling in the Linux kernel, i.e. messages logged with a priority
  15 * less than console_loglevel are also output to stdout.
  16 *
  17 * If you want messages with the default level (e.g. POST messages) to
  18 * appear on stdout also, make sure the environment variable
  19 * "loglevel" is set at boot time to a number higher than
  20 * default_message_loglevel below.
  21 */
  22
  23/*
  24 * Logbuffer handling routines
  25 */
  26
  27#include <common.h>
  28#include <command.h>
  29#include <stdio_dev.h>
  30#include <post.h>
  31#include <logbuff.h>
  32
  33DECLARE_GLOBAL_DATA_PTR;
  34
  35/* Local prototypes */
  36static void logbuff_putc(const char c);
  37static void logbuff_puts(const char *s);
  38static int logbuff_printk(const char *line);
  39
  40static char buf[1024];
  41
  42/* This combination will not print messages with the default loglevel */
  43static unsigned console_loglevel = 3;
  44static unsigned default_message_loglevel = 4;
  45static unsigned log_version = 1;
  46#ifdef CONFIG_ALT_LB_ADDR
  47static volatile logbuff_t *log;
  48#else
  49static logbuff_t *log;
  50#endif
  51static char *lbuf;
  52
  53unsigned long __logbuffer_base(void)
  54{
  55        return CONFIG_SYS_SDRAM_BASE + get_effective_memsize() - LOGBUFF_LEN;
  56}
  57unsigned long logbuffer_base(void)
  58__attribute__((weak, alias("__logbuffer_base")));
  59
  60void logbuff_init_ptrs(void)
  61{
  62        unsigned long tag, post_word;
  63        char *s;
  64
  65#ifdef CONFIG_ALT_LB_ADDR
  66        log = (logbuff_t *)CONFIG_ALT_LH_ADDR;
  67        lbuf = (char *)CONFIG_ALT_LB_ADDR;
  68#else
  69        log = (logbuff_t *)(logbuffer_base()) - 1;
  70        lbuf = (char *)log->buf;
  71#endif
  72
  73        /* Set up log version */
  74        if ((s = getenv ("logversion")) != NULL)
  75                log_version = (int)simple_strtoul(s, NULL, 10);
  76
  77        if (log_version == 2)
  78                tag = log->v2.tag;
  79        else
  80                tag = log->v1.tag;
  81        post_word = post_word_load();
  82#ifdef CONFIG_POST
  83        /* The post routines have setup the word so we can simply test it */
  84        if (tag != LOGBUFF_MAGIC || (post_word & POST_COLDBOOT))
  85                logbuff_reset();
  86#else
  87        /* No post routines, so we do our own checking                    */
  88        if (tag != LOGBUFF_MAGIC || post_word != LOGBUFF_MAGIC) {
  89                logbuff_reset ();
  90                post_word_store (LOGBUFF_MAGIC);
  91        }
  92#endif
  93        if (log_version == 2 && (long)log->v2.start > (long)log->v2.con)
  94                log->v2.start = log->v2.con;
  95
  96        /* Initialize default loglevel if present */
  97        if ((s = getenv ("loglevel")) != NULL)
  98                console_loglevel = (int)simple_strtoul(s, NULL, 10);
  99
 100        gd->flags |= GD_FLG_LOGINIT;
 101}
 102
 103void logbuff_reset(void)
 104{
 105#ifndef CONFIG_ALT_LB_ADDR
 106        memset(log, 0, sizeof(logbuff_t));
 107#endif
 108        if (log_version == 2) {
 109                log->v2.tag = LOGBUFF_MAGIC;
 110#ifdef CONFIG_ALT_LB_ADDR
 111                log->v2.start = 0;
 112                log->v2.con = 0;
 113                log->v2.end = 0;
 114                log->v2.chars = 0;
 115#endif
 116        } else {
 117                log->v1.tag = LOGBUFF_MAGIC;
 118#ifdef CONFIG_ALT_LB_ADDR
 119                log->v1.dummy = 0;
 120                log->v1.start = 0;
 121                log->v1.size = 0;
 122                log->v1.chars = 0;
 123#endif
 124        }
 125}
 126
 127int drv_logbuff_init(void)
 128{
 129        struct stdio_dev logdev;
 130        int rc;
 131
 132        /* Device initialization */
 133        memset (&logdev, 0, sizeof (logdev));
 134
 135        strcpy (logdev.name, "logbuff");
 136        logdev.ext   = 0;                       /* No extensions */
 137        logdev.flags = DEV_FLAGS_OUTPUT;        /* Output only */
 138        logdev.putc  = logbuff_putc;            /* 'putc' function */
 139        logdev.puts  = logbuff_puts;            /* 'puts' function */
 140
 141        rc = stdio_register(&logdev);
 142
 143        return (rc == 0) ? 1 : rc;
 144}
 145
 146static void logbuff_putc(const char c)
 147{
 148        char buf[2];
 149        buf[0] = c;
 150        buf[1] = '\0';
 151        logbuff_printk(buf);
 152}
 153
 154static void logbuff_puts(const char *s)
 155{
 156        logbuff_printk (s);
 157}
 158
 159void logbuff_log(char *msg)
 160{
 161        if ((gd->flags & GD_FLG_LOGINIT)) {
 162                logbuff_printk(msg);
 163        } else {
 164                /*
 165                 * Can happen only for pre-relocated errors as logging
 166                 * at that stage should be disabled
 167                 */
 168                puts (msg);
 169        }
 170}
 171
 172/*
 173 * Subroutine:  do_log
 174 *
 175 * Description: Handler for 'log' command..
 176 *
 177 * Inputs:      argv[1] contains the subcommand
 178 *
 179 * Return:      None
 180 *
 181 */
 182int do_log(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 183{
 184        char *s;
 185        unsigned long i, start, size;
 186
 187        if (strcmp(argv[1], "append") == 0) {
 188                /* Log concatenation of all arguments separated by spaces */
 189                for (i = 2; i < argc; i++) {
 190                        logbuff_printk(argv[i]);
 191                        logbuff_putc((i < argc - 1) ? ' ' : '\n');
 192                }
 193                return 0;
 194        }
 195
 196        switch (argc) {
 197
 198        case 2:
 199                if (strcmp(argv[1], "show") == 0) {
 200                        if (log_version == 2) {
 201                                start = log->v2.start;
 202                                size = log->v2.end - log->v2.start;
 203                        } else {
 204                                start = log->v1.start;
 205                                size = log->v1.size;
 206                        }
 207                        if (size > LOGBUFF_LEN)
 208                                size = LOGBUFF_LEN;
 209                        for (i = 0; i < size; i++) {
 210                                s = lbuf + ((start + i) & LOGBUFF_MASK);
 211                                putc(*s);
 212                        }
 213                        return 0;
 214                } else if (strcmp(argv[1], "reset") == 0) {
 215                        logbuff_reset();
 216                        return 0;
 217                } else if (strcmp(argv[1], "info") == 0) {
 218                        printf("Logbuffer   at  %08lx\n", (unsigned long)lbuf);
 219                        if (log_version == 2) {
 220                                printf("log_start    =  %08lx\n",
 221                                        log->v2.start);
 222                                printf("log_end      =  %08lx\n", log->v2.end);
 223                                printf("log_con      =  %08lx\n", log->v2.con);
 224                                printf("logged_chars =  %08lx\n",
 225                                        log->v2.chars);
 226                        }
 227                        else {
 228                                printf("log_start    =  %08lx\n",
 229                                        log->v1.start);
 230                                printf("log_size     =  %08lx\n",
 231                                        log->v1.size);
 232                                printf("logged_chars =  %08lx\n",
 233                                        log->v1.chars);
 234                        }
 235                        return 0;
 236                }
 237                return CMD_RET_USAGE;
 238
 239        default:
 240                return CMD_RET_USAGE;
 241        }
 242}
 243
 244U_BOOT_CMD(
 245        log,     255,   1,      do_log,
 246        "manipulate logbuffer",
 247        "info   - show pointer details\n"
 248        "log reset  - clear contents\n"
 249        "log show   - show contents\n"
 250        "log append <msg> - append <msg> to the logbuffer"
 251);
 252
 253static int logbuff_printk(const char *line)
 254{
 255        int i;
 256        char *msg, *p, *buf_end;
 257        int line_feed;
 258        static signed char msg_level = -1;
 259
 260        strcpy(buf + 3, line);
 261        i = strlen(line);
 262        buf_end = buf + 3 + i;
 263        for (p = buf + 3; p < buf_end; p++) {
 264                msg = p;
 265                if (msg_level < 0) {
 266                        if (
 267                                p[0] != '<' ||
 268                                p[1] < '0' ||
 269                                p[1] > '7' ||
 270                                p[2] != '>'
 271                        ) {
 272                                p -= 3;
 273                                p[0] = '<';
 274                                p[1] = default_message_loglevel + '0';
 275                                p[2] = '>';
 276                        } else {
 277                                msg += 3;
 278                        }
 279                        msg_level = p[1] - '0';
 280                }
 281                line_feed = 0;
 282                for (; p < buf_end; p++) {
 283                        if (log_version == 2) {
 284                                lbuf[log->v2.end & LOGBUFF_MASK] = *p;
 285                                log->v2.end++;
 286                                if (log->v2.end - log->v2.start > LOGBUFF_LEN)
 287                                        log->v2.start++;
 288                                log->v2.chars++;
 289                        } else {
 290                                lbuf[(log->v1.start + log->v1.size) &
 291                                         LOGBUFF_MASK] = *p;
 292                                if (log->v1.size < LOGBUFF_LEN)
 293                                        log->v1.size++;
 294                                else
 295                                        log->v1.start++;
 296                                log->v1.chars++;
 297                        }
 298                        if (*p == '\n') {
 299                                line_feed = 1;
 300                                break;
 301                        }
 302                }
 303                if (msg_level < console_loglevel) {
 304                        printf("%s", msg);
 305                }
 306                if (line_feed)
 307                        msg_level = -1;
 308        }
 309        return i;
 310}
 311