uboot/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(struct stdio_dev *dev, const char c);
  37static void logbuff_puts(struct stdio_dev *dev, 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(struct stdio_dev *dev, 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(struct stdio_dev *dev, 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        struct stdio_dev *sdev = NULL;
 185        char *s;
 186        unsigned long i, start, size;
 187
 188        if (strcmp(argv[1], "append") == 0) {
 189                /* Log concatenation of all arguments separated by spaces */
 190                for (i = 2; i < argc; i++) {
 191                        logbuff_printk(argv[i]);
 192                        logbuff_putc(sdev, (i < argc - 1) ? ' ' : '\n');
 193                }
 194                return 0;
 195        }
 196
 197        switch (argc) {
 198
 199        case 2:
 200                if (strcmp(argv[1], "show") == 0) {
 201                        if (log_version == 2) {
 202                                start = log->v2.start;
 203                                size = log->v2.end - log->v2.start;
 204                        } else {
 205                                start = log->v1.start;
 206                                size = log->v1.size;
 207                        }
 208                        if (size > LOGBUFF_LEN)
 209                                size = LOGBUFF_LEN;
 210                        for (i = 0; i < size; i++) {
 211                                s = lbuf + ((start + i) & LOGBUFF_MASK);
 212                                putc(*s);
 213                        }
 214                        return 0;
 215                } else if (strcmp(argv[1], "reset") == 0) {
 216                        logbuff_reset();
 217                        return 0;
 218                } else if (strcmp(argv[1], "info") == 0) {
 219                        printf("Logbuffer   at  %08lx\n", (unsigned long)lbuf);
 220                        if (log_version == 2) {
 221                                printf("log_start    =  %08lx\n",
 222                                        log->v2.start);
 223                                printf("log_end      =  %08lx\n", log->v2.end);
 224                                printf("log_con      =  %08lx\n", log->v2.con);
 225                                printf("logged_chars =  %08lx\n",
 226                                        log->v2.chars);
 227                        }
 228                        else {
 229                                printf("log_start    =  %08lx\n",
 230                                        log->v1.start);
 231                                printf("log_size     =  %08lx\n",
 232                                        log->v1.size);
 233                                printf("logged_chars =  %08lx\n",
 234                                        log->v1.chars);
 235                        }
 236                        return 0;
 237                }
 238                return CMD_RET_USAGE;
 239
 240        default:
 241                return CMD_RET_USAGE;
 242        }
 243}
 244
 245U_BOOT_CMD(
 246        log,     255,   1,      do_log,
 247        "manipulate logbuffer",
 248        "info   - show pointer details\n"
 249        "log reset  - clear contents\n"
 250        "log show   - show contents\n"
 251        "log append <msg> - append <msg> to the logbuffer"
 252);
 253
 254static int logbuff_printk(const char *line)
 255{
 256        int i;
 257        char *msg, *p, *buf_end;
 258        int line_feed;
 259        static signed char msg_level = -1;
 260
 261        strcpy(buf + 3, line);
 262        i = strlen(line);
 263        buf_end = buf + 3 + i;
 264        for (p = buf + 3; p < buf_end; p++) {
 265                msg = p;
 266                if (msg_level < 0) {
 267                        if (
 268                                p[0] != '<' ||
 269                                p[1] < '0' ||
 270                                p[1] > '7' ||
 271                                p[2] != '>'
 272                        ) {
 273                                p -= 3;
 274                                p[0] = '<';
 275                                p[1] = default_message_loglevel + '0';
 276                                p[2] = '>';
 277                        } else {
 278                                msg += 3;
 279                        }
 280                        msg_level = p[1] - '0';
 281                }
 282                line_feed = 0;
 283                for (; p < buf_end; p++) {
 284                        if (log_version == 2) {
 285                                lbuf[log->v2.end & LOGBUFF_MASK] = *p;
 286                                log->v2.end++;
 287                                if (log->v2.end - log->v2.start > LOGBUFF_LEN)
 288                                        log->v2.start++;
 289                                log->v2.chars++;
 290                        } else {
 291                                lbuf[(log->v1.start + log->v1.size) &
 292                                         LOGBUFF_MASK] = *p;
 293                                if (log->v1.size < LOGBUFF_LEN)
 294                                        log->v1.size++;
 295                                else
 296                                        log->v1.start++;
 297                                log->v1.chars++;
 298                        }
 299                        if (*p == '\n') {
 300                                line_feed = 1;
 301                                break;
 302                        }
 303                }
 304                if (msg_level < console_loglevel) {
 305                        printf("%s", msg);
 306                }
 307                if (line_feed)
 308                        msg_level = -1;
 309        }
 310        return i;
 311}
 312