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