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 <devices.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->bd->bi_memsize - LOGBUFF_LEN;
  72}
  73unsigned long logbuffer_base (void) __attribute__((weak, alias("__logbuffer_base")));
  74
  75void logbuff_init_ptrs (void)
  76{
  77        unsigned long tag, post_word;
  78        char *s;
  79
  80#ifdef CONFIG_ALT_LB_ADDR
  81        log = (logbuff_t *)CONFIG_ALT_LH_ADDR;
  82        lbuf = (char *)CONFIG_ALT_LB_ADDR;
  83#else
  84        log = (logbuff_t *)(logbuffer_base ()) - 1;
  85        lbuf = (char *)log->buf;
  86#endif
  87
  88        /* Set up log version */
  89        if ((s = getenv ("logversion")) != NULL)
  90                log_version = (int)simple_strtoul (s, NULL, 10);
  91
  92        if (log_version == 2)
  93                tag = log->v2.tag;
  94        else
  95                tag = log->v1.tag;
  96        post_word = post_word_load();
  97#ifdef CONFIG_POST
  98        /* The post routines have setup the word so we can simply test it */
  99        if (tag != LOGBUFF_MAGIC || (post_word & POST_COLDBOOT)) {
 100                logbuff_reset ();
 101        }
 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        device_t 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 = device_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                /* Can happen only for pre-relocated errors as logging */
 181                /* at that stage should be disabled                    */
 182                puts (msg);
 183        }
 184}
 185
 186/*
 187 * Subroutine:  do_log
 188 *
 189 * Description: Handler for 'log' command..
 190 *
 191 * Inputs:      argv[1] contains the subcommand
 192 *
 193 * Return:      None
 194 *
 195 */
 196int do_log (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
 197{
 198        char *s;
 199        unsigned long i, start, size;
 200
 201        if (strcmp(argv[1],"append") == 0) {
 202                /* Log concatenation of all arguments separated by spaces */
 203                for (i=2; i<argc; i++) {
 204                        logbuff_printk (argv[i]);
 205                        logbuff_putc ((i<argc-1) ? ' ' : '\n');
 206                }
 207                return 0;
 208        }
 209
 210        switch (argc) {
 211
 212        case 2:
 213                if (strcmp(argv[1],"show") == 0) {
 214                        if (log_version == 2) {
 215                                start = log->v2.start;
 216                                size = log->v2.end - log->v2.start;
 217                        }
 218                        else {
 219                                start = log->v1.start;
 220                                size = log->v1.size;
 221                        }
 222                        for (i=0; i < (size&LOGBUFF_MASK); i++) {
 223                                s = lbuf+((start+i)&LOGBUFF_MASK);
 224                                putc (*s);
 225                        }
 226                        return 0;
 227                } else if (strcmp(argv[1],"reset") == 0) {
 228                        logbuff_reset ();
 229                        return 0;
 230                } else if (strcmp(argv[1],"info") == 0) {
 231                        printf ("Logbuffer   at  %08lx\n", (unsigned long)lbuf);
 232                        if (log_version == 2) {
 233                                printf ("log_start    =  %08lx\n", log->v2.start);
 234                                printf ("log_end      =  %08lx\n", log->v2.end);
 235                                printf ("logged_chars =  %08lx\n", log->v2.chars);
 236                        }
 237                        else {
 238                                printf ("log_start    =  %08lx\n", log->v1.start);
 239                                printf ("log_size     =  %08lx\n", log->v1.size);
 240                                printf ("logged_chars =  %08lx\n", log->v1.chars);
 241                        }
 242                        return 0;
 243                }
 244                printf ("Usage:\n%s\n", cmdtp->usage);
 245                return 1;
 246
 247        default:
 248                printf ("Usage:\n%s\n", cmdtp->usage);
 249                return 1;
 250        }
 251}
 252
 253U_BOOT_CMD(
 254        log,     255,   1,      do_log,
 255        "log     - manipulate logbuffer\n",
 256        "info   - show pointer details\n"
 257        "log reset  - clear contents\n"
 258        "log show   - show contents\n"
 259        "log append <msg> - append <msg> to the logbuffer\n"
 260);
 261
 262static int logbuff_printk(const char *line)
 263{
 264        int i;
 265        char *msg, *p, *buf_end;
 266        int line_feed;
 267        static signed char msg_level = -1;
 268
 269        strcpy (buf + 3, line);
 270        i = strlen (line);
 271        buf_end = buf + 3 + i;
 272        for (p = buf + 3; p < buf_end; p++) {
 273                msg = p;
 274                if (msg_level < 0) {
 275                        if (
 276                                p[0] != '<' ||
 277                                p[1] < '0' ||
 278                                p[1] > '7' ||
 279                                p[2] != '>'
 280                        ) {
 281                                p -= 3;
 282                                p[0] = '<';
 283                                p[1] = default_message_loglevel + '0';
 284                                p[2] = '>';
 285                        } else
 286                                msg += 3;
 287                        msg_level = p[1] - '0';
 288                }
 289                line_feed = 0;
 290                for (; p < buf_end; p++) {
 291                        if (log_version == 2) {
 292                                lbuf[log->v2.end & LOGBUFF_MASK] = *p;
 293                                log->v2.end++;
 294                                if (log->v2.end - log->v2.start > LOGBUFF_LEN)
 295                                        log->v2.start++;
 296                                log->v2.chars++;
 297                        }
 298                        else {
 299                                lbuf[(log->v1.start + log->v1.size) &
 300                                         LOGBUFF_MASK] = *p;
 301                                if (log->v1.size < LOGBUFF_LEN)
 302                                        log->v1.size++;
 303                                else
 304                                        log->v1.start++;
 305                                log->v1.chars++;
 306                        }
 307                        if (*p == '\n') {
 308                                line_feed = 1;
 309                                break;
 310                        }
 311                }
 312                if (msg_level < console_loglevel) {
 313                        printf("%s", msg);
 314                }
 315                if (line_feed)
 316                        msg_level = -1;
 317        }
 318        return i;
 319}
 320