]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/infra/v2_0/src/diag.cxx
TX53 Release 2011-06-16
[karo-tx-redboot.git] / packages / infra / v2_0 / src / diag.cxx
1 /*========================================================================
2 //
3 //      diag.c
4 //
5 //      Infrastructure diagnostic output code
6 //
7 //========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
12 // Copyright (C) 2002, 2004 Gary Thomas
13 //
14 // eCos is free software; you can redistribute it and/or modify it under
15 // the terms of the GNU General Public License as published by the Free
16 // Software Foundation; either version 2 or (at your option) any later version.
17 //
18 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
19 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
20 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
21 // for more details.
22 //
23 // You should have received a copy of the GNU General Public License along
24 // with eCos; if not, write to the Free Software Foundation, Inc.,
25 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
26 //
27 // As a special exception, if other files instantiate templates or use macros
28 // or inline functions from this file, or you compile this file and link it
29 // with other works to produce a work based on this file, this file does not
30 // by itself cause the resulting work to be covered by the GNU General Public
31 // License. However the source code for this file must still be made available
32 // in accordance with section (3) of the GNU General Public License.
33 //
34 // This exception does not invalidate any other reasons why a work based on
35 // this file might be covered by the GNU General Public License.
36 //
37 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
38 // at http://sources.redhat.com/ecos/ecos-license/
39 // -------------------------------------------
40 //####ECOSGPLCOPYRIGHTEND####
41 //========================================================================
42 //#####DESCRIPTIONBEGIN####
43 //
44 // Author(s):    nickg,gthomas,jlarmour
45 // Contributors:
46 // Date:         1999-02-22
47 // Purpose:      Infrastructure diagnostic output
48 // Description:  Implementations of infrastructure diagnostic routines.
49 //
50 //####DESCRIPTIONEND####
51 //
52 //======================================================================*/
53
54 #include <pkgconf/system.h>
55 #include <pkgconf/hal.h>
56 #include <pkgconf/infra.h>
57
58 #include <cyg/infra/cyg_type.h>         // base types
59
60 #include <cyg/infra/diag.h>             // HAL polled output
61 #include <cyg/hal/hal_arch.h>           // architectural stuff for...
62 #include <cyg/hal/hal_intr.h>           // interrupt control
63 #include <cyg/hal/hal_diag.h>           // diagnostic output routines
64 #include <stdarg.h>
65 #include <limits.h>
66 #include <ctype.h>
67
68 #ifdef CYG_HAL_DIAG_LOCK_DATA_DEFN
69 CYG_HAL_DIAG_LOCK_DATA_DEFN;
70 #endif
71
72 /*----------------------------------------------------------------------*/
73
74 externC void diag_write_num(
75         cyg_uint64      n,                      /* number to write                      */
76         cyg_ucount8 base,               /* radix to write to            */
77         cyg_ucount8 sign,               /* sign, '-' if -ve, '+' if +ve */
78         cyg_bool        pfzero,         /* prefix with zero ?           */
79         cyg_ucount8 width               /* min width of number          */
80         );
81
82 class Cyg_dummy_diag_init_class {
83 public:
84         Cyg_dummy_diag_init_class() {
85                 HAL_DIAG_INIT();
86         }
87 };
88
89 // Initialize after HAL.
90 static Cyg_dummy_diag_init_class cyg_dummy_diag_init_obj
91 CYGBLD_ATTRIB_INIT_AFTER(CYG_INIT_HAL);
92
93 /*----------------------------------------------------------------------*/
94 /* Write single char to output                                          */
95
96 externC void diag_write_char(char c)
97 {
98         /* Translate LF into CRLF */
99
100         if (c == '\n') {
101                 HAL_DIAG_WRITE_CHAR('\r');
102         }
103
104         HAL_DIAG_WRITE_CHAR(c);
105 }
106
107 // Default wrapper function used by diag_printf
108 static void
109 _diag_write_char(char c, void *param)
110 {
111         diag_write_char(c);
112 }
113
114 /*----------------------------------------------------------------------*/
115 /* Initialize. Call to pull in diag initializing constructor            */
116
117 externC void diag_init(void)
118 {
119 }
120
121 //
122 // This routine is used to send characters during 'printf()' functions.
123 // It can be replaced by providing a replacement via diag_init_putc().
124 //
125 static void (*_putc)(char c, void *param) = _diag_write_char;
126
127 externC void
128 diag_init_putc(void (*putc)(char c, void *param))
129 {
130         _putc = putc;
131 }
132
133 /*----------------------------------------------------------------------*/
134 /* Write zero terminated string                                         */
135
136 externC void diag_write_string(const char *psz)
137 {
138         while (*psz)
139                 diag_write_char(*psz++);
140 }
141
142 /*----------------------------------------------------------------------*/
143 /* Write decimal value                                                  */
144
145 externC void diag_write_dec(cyg_int32 n)
146 {
147         cyg_ucount8 sign;
148
149         if (n < 0)
150                 n = -n, sign = '-';
151         else
152                 sign = '+';
153
154         diag_write_num(n, 10, sign, false, 0);
155 }
156
157 /*----------------------------------------------------------------------*/
158 /* Write hexadecimal value                                              */
159
160 externC void diag_write_hex(cyg_uint32 n)
161 {
162         diag_write_num(n, 16, '+', false, 0);
163 }
164
165 /*----------------------------------------------------------------------*/
166 /* Generic number writing function                                      */
167 /* The parameters determine what radix is used, the signed-ness of the  */
168 /* number, its minimum width and whether it is zero or space filled on  */
169 /* the left.                                                            */
170
171 externC void diag_write_long_num(
172         cyg_uint64      n,                      /* number to write                      */
173         cyg_ucount8 base,               /* radix to write to            */
174         cyg_ucount8 sign,               /* sign, '-' if -ve, '+' if +ve */
175         cyg_bool        pfzero,         /* prefix with zero ?           */
176         cyg_ucount8 width               /* min width of number          */
177         )
178 {
179         char buf[32];
180         cyg_count8 bpos;
181         char bufinit = pfzero?'0':' ';
182         const char *digits = "0123456789ABCDEF";
183
184         /* init buffer to padding char: space or zero */
185         for (bpos = 0; bpos < (cyg_count8)sizeof(buf); bpos++)
186                 buf[bpos] = bufinit;
187
188         /* Set pos to start */
189         bpos = 0;
190
191         /* construct digits into buffer in reverse order */
192         if (n == 0)
193                 buf[bpos++] = '0';
194         else
195                 while (n != 0) {
196                         cyg_ucount8 d = n % base;
197                         buf[bpos++] = digits[d];
198                         n /= base;
199                 }
200
201         /* set pos to width if less. */
202         if ((cyg_count8)width > bpos)
203                 bpos = width;
204
205         /* set sign if negative. */
206         if (sign == '-') {
207                 if (buf[bpos-1] == bufinit) bpos--;
208                 buf[bpos] = sign;
209         } else {
210                 bpos--;
211         }
212
213         /* Now write it out in correct order. */
214         while(bpos >= 0)
215                 diag_write_char(buf[bpos--]);
216 }
217
218 externC void diag_write_num(
219         cyg_uint64      n,                      /* number to write                      */
220         cyg_ucount8 base,               /* radix to write to            */
221         cyg_ucount8 sign,               /* sign, '-' if -ve, '+' if +ve */
222         cyg_bool        pfzero,         /* prefix with zero ?           */
223         cyg_ucount8 width               /* min width of number          */
224         )
225 {
226         diag_write_long_num(n, base, sign, pfzero, width);
227 }
228
229 /*----------------------------------------------------------------------*/
230 /* perform some simple sanity checks on a string to ensure that it      */
231 /* consists of printable characters and is of reasonable length.        */
232
233 static cyg_bool diag_check_string(const char *str)
234 {
235         cyg_bool result = true;
236         const char *s;
237
238         if (str == NULL)
239                 return false;
240
241         for (s = str ; result && *s ; s++) {
242                 char c = *s;
243
244                 /* Check for a reasonable length string. */
245                 if (s - str > 2048)
246                         result = false;
247
248                 /* We only really support CR, NL, tab and backspace at present.
249                  * If we want to use other special chars, this test will
250                  * have to be expanded.  */
251                 if (c == '\n' || c == '\r' || c == '\b' || c == '\t')
252                         continue;
253
254                 /* Check for printable chars. This assumes ASCII */
255                 if (c < ' ' || c > '~')
256                         result = false;
257         }
258
259         return result;
260 }
261
262 /*----------------------------------------------------------------------*/
263
264 static int
265 _cvt(unsigned long long val, char *buf, long radix, const char *digits)
266 {
267         char temp[80];
268         char *cp = temp;
269         int length = 0;
270
271         if (val == 0) {
272                 /* Special case */
273                 *cp++ = '0';
274         } else {
275                 while (val) {
276                         *cp++ = digits[val % radix];
277                         val /= radix;
278                 }
279         }
280         while (cp != temp) {
281                 *buf++ = *--cp;
282                 length++;
283         }
284         *buf = '\0';
285         return length;
286 }
287
288 #define is_digit(c) ((c >= '0') && (c <= '9'))
289
290 static int
291 _vprintf(void (*putc)(char c, void *param), void *param, const char *fmt, va_list ap)
292 {
293         char buf[sizeof(long long) * 8];
294         char c, sign;
295         const char *cp = buf;
296         int left_prec, right_prec, zero_fill, pad, pad_on_right,
297                 i, islong, islonglong;
298         long long val = 0;
299         int res = 0, length = 0;
300
301         if (!diag_check_string(fmt)) {
302                 diag_write_string("<Bad format string: ");
303                 diag_write_hex((cyg_uint32)fmt);
304                 diag_write_string(" :");
305                 for (i = 0; i < 8; i++) {
306                         diag_write_char(' ');
307                         val = va_arg(ap, unsigned long);
308                         diag_write_hex(val);
309                 }
310                 diag_write_string(">\n");
311                 return 0;
312         }
313         while ((c = *fmt++) != '\0') {
314                 if (c == '%') {
315                         c = *fmt++;
316                         left_prec = right_prec = pad_on_right = islong = islonglong = 0;
317                         if (c == '-') {
318                                 c = *fmt++;
319                                 pad_on_right++;
320                         }
321                         if (c == '0') {
322                                 zero_fill = true;
323                                 c = *fmt++;
324                         } else {
325                                 zero_fill = false;
326                         }
327                         while (is_digit(c)) {
328                                 left_prec = (left_prec * 10) + (c - '0');
329                                 c = *fmt++;
330                         }
331                         if (c == '.') {
332                                 c = *fmt++;
333                                 zero_fill++;
334                                 while (is_digit(c)) {
335                                         right_prec = (right_prec * 10) + (c - '0');
336                                         c = *fmt++;
337                                 }
338                         } else {
339                                 right_prec = left_prec;
340                         }
341                         sign = '\0';
342                         if (c == 'l') {
343                                 // 'long' qualifier
344                                 c = *fmt++;
345                                 islong = 1;
346                                 if (c == 'l') {
347                                         // long long qualifier
348                                         c = *fmt++;
349                                         islonglong = 1;
350                                 }
351                         }
352                         if (c == 'z') {
353                                 c = *fmt++;
354                                 islong = sizeof(size_t) == sizeof(long);
355                         }
356                         // Fetch value [numeric descriptors only]
357                         switch (c) {
358                         case 'p':
359                                 islong = 1;
360                         case 'd':
361                         case 'D':
362                         case 'x':
363                         case 'X':
364                         case 'u':
365                         case 'U':
366                         case 'b':
367                         case 'B':
368                                 if (islonglong) {
369                                         val = va_arg(ap, long long);
370                                 } else if (islong) {
371                                         val = (long long)va_arg(ap, long);
372                                 } else{
373                                         val = (long long)va_arg(ap, int);
374                                 }
375                                 if ((c == 'd') || (c == 'D')) {
376                                         if (val < 0) {
377                                                 sign = '-';
378                                                 val = -val;
379                                         }
380                                 } else {
381                                         // Mask to unsigned, sized quantity
382                                         if (!islonglong) {
383                                                 // no need to mask longlong
384                                                 if (islong)
385                                                         val &= ((long long)1 << (sizeof(long) * 8)) - 1;
386                                                 else
387                                                         val &= ((long long)1 << (sizeof(int) * 8)) - 1;
388                                         }
389                                 }
390                                 break;
391                         default:
392                                 break;
393                         }
394                         // Process output
395                         switch (c) {
396                         case 'p':  // Pointer
397                                 putc('0', param);
398                                 putc('x', param);
399                                 zero_fill = true;
400                                 left_prec = sizeof(unsigned long) * 2;
401                                 res += 2;  // Account for "0x" leadin
402                         case 'd':
403                         case 'D':
404                         case 'u':
405                         case 'U':
406                         case 'x':
407                         case 'X':
408                                 switch (c) {
409                                 case 'd':
410                                 case 'D':
411                                 case 'u':
412                                 case 'U':
413                                         length = _cvt(val, buf, 10, "0123456789");
414                                         break;
415                                 case 'p':
416                                 case 'x':
417                                         length = _cvt(val, buf, 16, "0123456789abcdef");
418                                         break;
419                                 case 'X':
420                                         length = _cvt(val, buf, 16, "0123456789ABCDEF");
421                                         break;
422                                 }
423                                 cp = buf;
424                                 break;
425                         case 's':
426                         case 'S':
427                                 cp = va_arg(ap, char *);
428                                 if (cp == NULL)
429                                         cp = "<null>";
430 #if !CYGINT_ISO_CTYPE
431 #warning enable CYGINT_ISO_CTYPE to get sensible string output instead of bogus '<Not a string 0x...>' messages for unprintable characters
432                                 else if (!diag_check_string(cp)) {
433                                         diag_write_string("<Not a string: 0x");
434                                         diag_write_hex((cyg_uint32)cp);
435                                         cp = ">";
436                                 }
437 #endif
438                                 length = 0;
439                                 while (cp[length] != '\0') length++;
440                                 break;
441                         case 'c':
442                         case 'C':
443                                 c = va_arg(ap, int /*char*/);
444                                 putc(c, param);
445                                 res++;
446                                 continue;
447                         case 'b':
448                         case 'B':
449                                 length = left_prec;
450                                 if (left_prec == 0) {
451                                         if (islonglong)
452                                                 length = sizeof(long long) * 8;
453                                         else if (islong)
454                                                 length = sizeof(long) * 8;
455                                         else
456                                                 length = sizeof(int) * 8;
457                                 }
458                                 for (i = 0;  i < length-1;  i++) {
459                                         buf[i] = ((val & ((long long)1<<i)) ? '1' : '.');
460                                 }
461                                 cp = buf;
462                                 break;
463                         case '%':
464                                 putc('%', param);
465                                 res++;
466                                 continue;
467                         default:
468                                 putc('%', param);
469                                 putc(c, param);
470                                 res += 2;
471                                 continue;
472                         }
473                         pad = left_prec - length;
474                         if (sign != '\0') {
475                                 pad--;
476                         }
477                         if (zero_fill) {
478                                 c = '0';
479                                 if (sign != '\0') {
480                                         putc(sign, param);
481                                         res++;
482                                         sign = '\0';
483                                 }
484                         } else {
485                                 c = ' ';
486                         }
487                         if (!pad_on_right) {
488                                 while (pad-- > 0) {
489                                         putc(c, param);
490                                         res++;
491                                 }
492                         }
493                         if (sign != '\0') {
494                                 putc(sign, param);
495                                 res++;
496                         }
497                         while (length-- > 0) {
498                                 c = *cp++;
499 #if CYGINT_ISO_CTYPE
500                                 if (isprint(c) || isspace(c)) {
501                                         putc(c, param);
502                                 } else if (iscntrl(c)) {
503                                         putc('\\', param);
504                                         putc('C', param);
505                                         putc('-', param);
506                                         putc(c | 0x40, param);
507                                 } else {
508                                         int len = _cvt(c, buf, 16, "0123456789ABCDEF");
509                                         putc('\\', param);
510                                         putc('0', param);
511                                         putc('x', param);
512                                         for (int i = 0; i < len; i++) {
513                                                 putc(buf[i], param);
514                                         }
515                                 }
516 #else
517                                 putc(c, param);
518 #endif
519                                 res++;
520                         }
521                         if (pad_on_right) {
522                                 while (pad-- > 0) {
523                                         putc(' ', param);
524                                         res++;
525                                 }
526                         }
527                 } else {
528                         putc(c, param);
529                         res++;
530                 }
531         }
532         return res;
533 }
534
535 struct _sputc_info {
536         char *ptr;
537         int max, len;
538 };
539
540 static void
541 _sputc(char c, void *param)
542 {
543         struct _sputc_info *info = (struct _sputc_info *)param;
544
545         if (info->len < info->max) {
546                 *info->ptr++ = c;
547                 *info->ptr = '\0';
548                 info->len++;
549         }
550 }
551
552 int
553 diag_sprintf(char *buf, const char *fmt, ...)
554 {
555         int ret;
556         va_list ap;
557         struct _sputc_info info;
558
559         va_start(ap, fmt);
560         info.ptr = buf;
561         info.max = 1024;  // Unlimited
562         info.len = 0;
563         ret = _vprintf(_sputc, &info, fmt, ap);
564         va_end(ap);
565         return info.len;
566 }
567
568 int
569 diag_snprintf(char *buf, size_t len, const char *fmt, ...)
570 {
571         int ret;
572         va_list ap;
573         struct _sputc_info info;
574
575         va_start(ap, fmt);
576         info.ptr = buf;
577         info.len = 0;
578         info.max = len-1;
579         ret = _vprintf(_sputc, &info, fmt, ap);
580         va_end(ap);
581         return info.len;
582 }
583
584 int
585 diag_vsprintf(char *buf, const char *fmt, va_list ap)
586 {
587         int ret;
588         struct _sputc_info info;
589
590         info.ptr = buf;
591         info.max = 1024;  // Unlimited
592         info.len = 0;
593         ret = _vprintf(_sputc, &info, fmt, ap);
594         return info.len;
595 }
596
597 int
598 diag_printf(const char *fmt, ...)
599 {
600         va_list ap;
601         int ret;
602
603         va_start(ap, fmt);
604         ret = _vprintf(_putc, NULL, fmt, ap);
605         va_end(ap);
606         return ret;
607 }
608
609 int
610 diag_vprintf(const char *fmt, va_list ap)
611 {
612         int ret;
613
614         ret = _vprintf(_putc, NULL, fmt, ap);
615         return ret;
616 }
617
618 void
619 diag_vdump_buf_with_offset(__printf_fun *pf,
620                                                    cyg_uint8    *p,
621                                                    CYG_ADDRWORD  s,
622                                                    cyg_uint8    *base)
623 {
624         int i, c;
625
626         if ((CYG_ADDRWORD)s > (CYG_ADDRWORD)p) {
627                 s = (CYG_ADDRWORD)s - (CYG_ADDRWORD)p;
628         }
629         while ((int)s > 0) {
630                 if (base) {
631                         pf("%08X: ", (CYG_ADDRWORD)p - (CYG_ADDRWORD)base);
632                 } else {
633                         pf("%08X: ", p);
634                 }
635                 for (i = 0;  i < 16;  i++) {
636                         if (i < (int)s) {
637                                 pf("%02X ", p[i] & 0xFF);
638                         } else {
639                                 pf("   ");
640                         }
641                         if (i == 7)
642                                 pf(" ");
643                 }
644                 pf(" |");
645                 for (i = 0;  i < 16;  i++) {
646                         if (i < (int)s) {
647                                 c = p[i] & 0xFF;
648                                 if ((c < 0x20) || (c >= 0x7F)) c = '.';
649                         } else {
650                                 c = ' ';
651                         }
652                         pf("%c", c);
653                 }
654                 pf("|\n");
655                 s -= 16;
656                 p += 16;
657         }
658 }
659
660 void
661 diag_dump_buf_with_offset(cyg_uint8             *p,
662                                                   CYG_ADDRWORD   s,
663                                                   cyg_uint8             *base)
664 {
665         diag_vdump_buf_with_offset(diag_printf, p, s, base);
666 }
667
668 void
669 diag_dump_buf(void *p, CYG_ADDRWORD s)
670 {
671    diag_dump_buf_with_offset((cyg_uint8 *)p, s, 0);
672 }
673
674 void
675 diag_dump_buf_with_offset_32bit(cyg_uint32   *p,
676                                                                 CYG_ADDRWORD  s,
677                                                                 cyg_uint32   *base)
678 {
679         int i;
680
681         if ((CYG_ADDRWORD)s > (CYG_ADDRWORD)p) {
682                 s = (CYG_ADDRWORD)s - (CYG_ADDRWORD)p;
683         }
684         while ((int)s > 0) {
685                 if (base) {
686                         diag_printf("%08X: ", (CYG_ADDRWORD)p - (CYG_ADDRWORD)base);
687                 } else {
688                         diag_printf("%08X: ", (CYG_ADDRWORD)p);
689                 }
690                 for (i = 0;  i < 4;  i++) {
691                         if (i < (int)s / 4) {
692                                 diag_printf("%08X ", p[i]);
693                         } else {
694                                 diag_printf("         ");
695                         }
696                 }
697                 diag_printf("\n");
698                 s -= 16;
699                 p += 4;
700         }
701 }
702
703 externC void
704 diag_dump_buf_32bit(void *p, CYG_ADDRWORD s)
705 {
706    diag_dump_buf_with_offset_32bit((cyg_uint32 *)p, s, 0);
707 }
708
709 void
710 diag_dump_buf_with_offset_16bit(cyg_uint16   *p,
711                                                                 CYG_ADDRWORD  s,
712                                                                 cyg_uint16   *base)
713 {
714         int i;
715         if ((CYG_ADDRWORD)s > (CYG_ADDRWORD)p) {
716                 s = (CYG_ADDRWORD)s - (CYG_ADDRWORD)p;
717         }
718         while ((int)s > 0) {
719                 if (base) {
720                         diag_printf("%08X: ", (CYG_ADDRWORD)p - (CYG_ADDRWORD)base);
721                 } else {
722                         diag_printf("%08X: ", (CYG_ADDRWORD)p);
723                 }
724                 for (i = 0;  i < 8;  i++) {
725                         if (i < (int)s / 2) {
726                                 diag_printf("%04X ", p[i]);
727                                 if (i == 3) diag_printf(" ");
728                         } else {
729                                 diag_printf("     ");
730                         }
731                 }
732                 diag_printf("\n");
733                 s -= 16;
734                 p += 8;
735         }
736 }
737
738 externC void
739 diag_dump_buf_16bit(void *p, CYG_ADDRWORD s)
740 {
741    diag_dump_buf_with_offset_16bit((cyg_uint16 *)p, s, 0);
742 }
743
744 /*-----------------------------------------------------------------------*/
745 /* EOF infra/diag.c */