source: trunk/kernel/kern/printk.c

Last change on this file was 683, checked in by alain, 4 years ago

All modifications required to support the <tcp_chat> application
including error recovery in case of packet loss.A

File size: 19.5 KB
Line 
1/*
2 * printk.c - Kernel Log & debug messages API implementation.
3 *
4 * authors  Alain Greiner (2016,2017,2018,2019,2020)
5 *
6 * Copyright (c) UPMC Sorbonne Universites
7 *
8 * This file is part of ALMOS-MKH..
9 *
10 * ALMOS-MKH. is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; version 2.0 of the License.
13 *
14 * ALMOS-MKH. is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with ALMOS-MKH.; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24#include <hal_kernel_types.h>
25#include <hal_irqmask.h>
26#include <hal_special.h>
27#include <dev_txt.h>
28#include <remote_busylock.h>
29#include <cluster.h>
30#include <thread.h>
31#include <chdev.h>
32#include <printk.h>
33#include <shared_syscalls.h>
34
35///////////////////////////////////////////////////////////////////////////////////
36//      Extern
37///////////////////////////////////////////////////////////////////////////////////
38
39extern chdev_directory_t  chdev_dir;  // defined in chdev.h / allocated in kernel_init.c
40
41//////////////////////////////////////////////////////////////////////////////////////
42// This static function is called by printk(), nolock_printk(), and snprintk(),
43// functions to build a string from a printf-like <format>, and stores it
44// in the buffer defined by the <string> and <size> arguments.
45// The <format> itself is supposed to be a NUL terminated string. The <string>
46// buffer <size> must be large enough to contains also the NUL terminating character.
47// If success, it returns the number of bytes actually copied in the <string> buffer,
48// but this length does NOT include the terminating NUL character.
49// It returns -2 in case of illegal format, it returns -1 if the formated string
50// exceeds the <size> argument.
51//////////////////////////////////////////////////////////////////////////////////////
52// @ string    : buffer allocated by caller.
53// @ size      : buffer size in bytes
54// @ format    : printf like format.
55// @ args      : va_list of arguments.
56// @ return string length if success / -1 if buffer too small / -2 if illegal format.
57//////////////////////////////////////////////////////////////////////////////////////
58static int32_t format_to_string( char       * string,
59                                 uint32_t     size,
60                                 const char * format, 
61                                 va_list    * args ) 
62{
63
64#define TO_STRING(x) do { string[ps] = (x); ps++; if(ps==size) return -1; } while(0);
65
66    uint32_t   ps = 0;        // index in string buffer
67
68format_to_string_text:
69
70    // handle one character per iteration
71    while ( *format != 0 ) 
72    {
73        if (*format == '%')   // copy argument to string
74        {
75            format++;
76            goto format_to_string_arguments;
77        }
78        else                  // copy one char of format to string
79        {
80            TO_STRING( *format );
81            format++;
82        }
83    }
84
85    TO_STRING( 0 );      // NUL character written in buffer
86    return (ps - 1);     // but not counted in length
87
88format_to_string_arguments:
89
90    {
91        char              buf[30];    // buffer to display one number
92        char *            pbuf;       // pointer on first char to display
93        uint32_t          len = 0;    // number of char to display
94        static const char HexaTab[] = "0123456789ABCDEF";
95        uint32_t          i;
96       
97        switch (*format) 
98        {
99            case ('c'):             // one printable character
100            {
101                buf[0] = (char)va_arg( *args , uint32_t );
102                pbuf   = buf;
103                len    = 1;
104                break;
105            }
106            case ('b'):             // one ASCII code value (2 hexadecimal digits)
107            {
108                uint8_t val = (uint8_t)va_arg( *args , uint32_t ); 
109                buf[1] = HexaTab[val & 0xF];
110                buf[0] = HexaTab[(val >> 4) & 0xF];
111                pbuf   = buf;
112                len    = 2;
113                break;
114            }           
115            case ('d'):            // one int32_t (up to 10 decimal digits after sign)
116            {
117                int32_t val = va_arg( *args , int32_t );
118                if (val < 0) 
119                {
120                    TO_STRING( '-' );
121                    val = -val;
122                }
123                for(i = 0; i < 10; i++) 
124                {
125                    buf[9 - i] = HexaTab[val % 10];
126                    if (!(val /= 10)) break;
127                }
128                len =  i + 1;
129                pbuf = &buf[9 - i];
130                break;
131            }
132            case ('u'):           // one uint32_t (up to 10 decimal digits)
133            {
134                uint32_t val = va_arg( *args , uint32_t );
135                for(i = 0; i < 10; i++) 
136                {
137                    buf[9 - i] = HexaTab[val % 10];
138                    if (!(val /= 10)) break;
139                }
140                len =  i + 1;
141                pbuf = &buf[9 - i];
142                break;
143            }
144            case ('x'):           // one uint32_t (up to 8 hexa digits after "0x")
145
146            {
147                uint32_t val = va_arg( *args , uint32_t );
148                TO_STRING( '0' );
149                TO_STRING( 'x' );
150                for(i = 0 ; i < 8 ; i++) 
151                {
152                    buf[7 - i] = HexaTab[val & 0xF];
153                    val = val >> 4;
154                    if(val == 0)  break;
155                }
156                len =  i + 1;
157                pbuf = &buf[7 - i];
158                break;
159            }
160            case ('X'):         // one uint32_t (exactly 8 hexa digits after "0x")
161            {
162                uint32_t val = va_arg( *args , uint32_t );
163                TO_STRING( '0' );
164                TO_STRING( 'x' );
165                for(i = 0 ; i < 8 ; i++) 
166                {
167                    buf[7 - i] = (val != 0) ? HexaTab[val & 0xF] : '0';
168                    val = val >> 4;
169                }
170                len = 8;
171                pbuf = &buf[0];
172                break;
173            }
174            case ('l'):          // one uint64_t (up to 16 digits hexa after "0x")
175            {
176                uint64_t val = (((uint64_t)va_arg( *args, uint32_t)) << 32) |
177                               ((uint64_t)va_arg( *args, uint32_t));
178                TO_STRING( '0' );
179                TO_STRING( 'x' );
180                for(i = 0 ; i < 16 ; i++) 
181                {
182                    buf[15 - i] = HexaTab[val & 0xF];
183                    val = val >> 4;
184                    if( val == 0)  break;
185                }
186                len =  i + 1;
187                pbuf = &buf[15 - i];
188                break;
189            }
190            case ('L'):          // one uint64_t (exactly 16 digits hexa after "0x")
191            {
192                uint64_t val = (((uint64_t)va_arg( *args, uint32_t)) << 32) |
193                               ((uint64_t)va_arg( *args, uint32_t));
194                TO_STRING( '0' );
195                TO_STRING( 'x' );
196                for(i = 0 ; i < 16 ; i++) 
197                {
198                    buf[15 - i] = (val != 0) ? HexaTab[val & 0xF] : '0';
199                    val = val >> 4;
200                }
201                len =  16;
202                pbuf = &buf[0];
203                break;
204            }
205            case ('s'):             /* one characters string */
206            {
207                char* str = va_arg( *args , char* );
208                while (str[len]) { len++; }
209                pbuf = str;
210                break;
211            }
212            default:       // unsupported argument type
213            {
214                return -2;
215            }
216        }  // end switch on  argument type
217
218        format++;
219
220        // copy argument sub-string to the string buffer
221        for( i = 0 ; i < len ; i++ )
222        {
223            TO_STRING( pbuf[i] );
224        }
225       
226        goto format_to_string_text;
227    }
228}   // end format_to_string()
229
230//////////////////////////////////
231void printk( char * format , ... )
232{
233    char          buffer[CONFIG_PRINTK_BUF_SIZE];
234    va_list       args;
235    int32_t       length;
236
237    // build args va_list
238    va_start( args , format );
239
240    // get pointers on TXT0 chdev
241    xptr_t    txt0_xp  = chdev_dir.txt_tx[0];
242    cxy_t     txt0_cxy = GET_CXY( txt0_xp );
243    chdev_t * txt0_ptr = GET_PTR( txt0_xp );
244
245    // get extended pointer on remote TXT0 lock
246    xptr_t  lock_xp = XPTR( txt0_cxy , &txt0_ptr->wait_lock );
247
248    // get TXT0 lock
249    remote_busylock_acquire( lock_xp );
250
251    // build a string from format
252    length = format_to_string( buffer,
253                               CONFIG_PRINTK_BUF_SIZE,
254                               format,
255                               &args );
256    va_end( args );
257
258    if( length > 0  )        // call TXT driver to display formated string on TXT0
259    {
260        dev_txt_sync_write( buffer , length );
261    }
262    else if( length == -2 )  // illegal format => display a warning on TXT0
263    {
264        thread_t * this = CURRENT_THREAD;
265
266        nolock_printk("\n[PANIC] from printk : illegal format\n"
267                      "thread[%x,%x] on core[%x,%d] at cycle %l\n",
268                      this->process->pid, this->trdid,
269                      local_cxy, this->core->lid, hal_get_cycles() );
270    }
271    else                     // format too long => display a warning on TXT0
272    {
273        thread_t * this = CURRENT_THREAD;
274
275        nolock_printk("\n[PANIC] from printk : formated string too long\n"
276                      "thread[%x,%x] on core[%x,%d] at cycle %l\n",
277                      this->process->pid, this->trdid,
278                      local_cxy, this->core->lid, hal_get_cycles() );
279    }
280
281    // release TXT0 lock
282    remote_busylock_release( lock_xp );
283
284}   // end printk()
285
286/////////////////////////////////////////
287void nolock_printk( char * format , ... )
288{
289    char          buffer[CONFIG_PRINTK_BUF_SIZE];
290    va_list       args;
291    int32_t       length;
292
293    // build args va_list
294    va_start( args , format );
295
296    // build a string from format
297    length = format_to_string( buffer,
298                               CONFIG_PRINTK_BUF_SIZE,
299                               format,
300                               &args );
301    va_end( args );
302
303    if( length > 0  )        // call TXT driver to display formated string on TXT0
304    {
305        dev_txt_sync_write( buffer , length );
306    }
307    else if( length == -2 )  // illegal format => display a warning on TXT0
308    {
309        thread_t * this = CURRENT_THREAD;
310
311        nolock_printk("\n[PANIC] from print : illegal format\n"
312                      "thread[%x,%x] on core[%x,%d] at cycle %l\n",
313                      this->process->pid, this->trdid,
314                      local_cxy, this->core->lid, hal_get_cycles() );
315    }
316    else                  // buffer too small => display a warning on TXT0
317    {
318        thread_t * this = CURRENT_THREAD;
319
320        nolock_printk("\n[PANIC] from printk : formated string too long\n"
321                      "thread[%x,%x] on core[%x,%d] at cycle %l\n",
322                      this->process->pid, this->trdid,
323                      local_cxy, this->core->lid, hal_get_cycles() );
324    }
325
326}   // end nolock_printk()
327
328//////////////////////////////////////
329void assert( const char   * func_name,
330             bool_t         expr,
331             char         * format , ... )
332{
333    if( expr == false )
334    {
335        thread_t * this  = CURRENT_THREAD;
336        trdid_t    trdid = this->trdid;
337        pid_t      pid   = this->process->pid;
338        uint32_t   lid   = this->core->lid;
339        uint32_t   cycle = (uint32_t)hal_get_cycles();
340
341        char       buffer[CONFIG_PRINTK_BUF_SIZE];
342        va_list    args;
343
344        va_start( args , format );
345
346        // build a string from format
347        int32_t   length = format_to_string( buffer,
348                                             CONFIG_PRINTK_BUF_SIZE,
349                                             format,
350                                             &args );
351        va_end( args );
352
353        if( length > 0  )  // display panic message on TXT0, including formated string
354        {
355            printk("\n[ASSERT] in %s / core[%x,%d] / thread[%x,%x] / cycle %d\n   <%s>\n",
356            func_name, local_cxy, lid, pid, trdid, cycle, buffer );
357        }
358        else              // display minimal panic message on TXT0
359        {
360            printk("\n[ASSERT] in %s / core[%x,%d] / thread[%x,%x] / cycle %d\n",
361            func_name, local_cxy, lid, pid, trdid, cycle );
362        }
363    }
364}   // end assert( __FUNCTION__,)
365   
366//////////////////////////////////////
367int32_t snprintk( char       * buffer,
368                  uint32_t     size,
369                  char       * format, ... )
370{
371    va_list       args;
372    int32_t       length;
373
374    // build args va_list
375    va_start( args , format );
376
377    // build a string from format
378    length = format_to_string( buffer , size , format , &args );
379
380    // release args list
381    va_end( args );
382
383    if( length < 0 )   return -1;
384    else               return length;
385
386}   // end snprintk()
387
388////////////////////////////////
389void puts( const char * string ) 
390{
391    uint32_t   n = 0;
392
393    // compute string length
394    while ( string[n] > 0 ) n++;
395
396    // get pointers on TXT0 chdev
397    xptr_t    txt0_xp  = chdev_dir.txt_tx[0];
398    cxy_t     txt0_cxy = GET_CXY( txt0_xp );
399    chdev_t * txt0_ptr = GET_PTR( txt0_xp );
400
401    if( txt0_xp != XPTR_NULL )
402    {
403        // get extended pointer on remote TXT0 lock
404        xptr_t  lock_xp = XPTR( txt0_cxy , &txt0_ptr->wait_lock );
405
406        // display string on TTY0
407        remote_busylock_acquire( lock_xp );
408        dev_txt_sync_write( string , n );
409        remote_busylock_release( lock_xp );
410    }
411}   // end puts()
412
413///////////////////////////////////////
414void nolock_puts( const char * string ) 
415{
416    uint32_t   n = 0;
417
418    // compute string length
419    while ( string[n] > 0 ) n++;
420
421    // display string on TTY0
422    dev_txt_sync_write( string , n );
423 
424}   // end nolock_puts()
425
426
427
428/////////////////////////
429void putx( uint32_t val )
430{
431    static const char HexaTab[] = "0123456789ABCDEF";
432
433    char      buf[10];
434    uint32_t  c;
435
436    buf[0] = '0';
437    buf[1] = 'x';
438
439    // build buffer
440    for (c = 0; c < 8; c++) 
441    { 
442        buf[9 - c] = HexaTab[val & 0xF];
443        val = val >> 4;
444    }
445
446    // get pointers on TXT0 chdev
447    xptr_t    txt0_xp  = chdev_dir.txt_tx[0];
448    cxy_t     txt0_cxy = GET_CXY( txt0_xp );
449    chdev_t * txt0_ptr = GET_PTR( txt0_xp );
450
451    if( txt0_xp != XPTR_NULL )
452    {
453        // get extended pointer on remote TXT0 chdev lock
454        xptr_t  lock_xp = XPTR( txt0_cxy , &txt0_ptr->wait_lock );
455
456        // display buf on TTY0
457        remote_busylock_acquire( lock_xp );
458        dev_txt_sync_write( buf , 10 );
459        remote_busylock_release( lock_xp );
460    }
461}   // end putx()
462
463////////////////////////////////
464void nolock_putx( uint32_t val )
465{
466    static const char HexaTab[] = "0123456789ABCDEF";
467
468    char      buf[10];
469    uint32_t  c;
470
471    buf[0] = '0';
472    buf[1] = 'x';
473
474    // build buffer
475    for (c = 0; c < 8; c++) 
476    { 
477        buf[9 - c] = HexaTab[val & 0xF];
478        val = val >> 4;
479    }
480
481    // display buf on TTY0
482    dev_txt_sync_write( buf , 10 );
483
484}   // end nilock_putx()
485
486////////////////////////
487void putd( int32_t val )
488{
489    static const char HexaTab[] = "0123456789ABCDEF";
490
491    char      buf[10];
492    uint32_t  i;
493
494    // get pointers on TXT0 chdev
495    xptr_t    txt0_xp  = chdev_dir.txt_tx[0];
496    cxy_t     txt0_cxy = GET_CXY( txt0_xp );
497    chdev_t * txt0_ptr = GET_PTR( txt0_xp );
498
499    // get extended pointer on remote TXT0 chdev lock
500    xptr_t  lock_xp = XPTR( txt0_cxy , &txt0_ptr->wait_lock );
501
502    if( txt0_xp != XPTR_NULL )
503    {
504        // get TXT0 lock
505        remote_busylock_acquire( lock_xp );
506
507        if (val < 0) 
508        {
509            val = -val;
510            dev_txt_sync_write( "-" , 1 );
511        }
512
513        for(i = 0; i < 10 ; i++) 
514        {
515            buf[9 - i] = HexaTab[val % 10];
516            if (!(val /= 10)) break;
517        }
518
519        // display buf on TTY0
520        dev_txt_sync_write( &buf[9-i] , i+1 );
521
522        // release TXT0 lock
523        remote_busylock_release( lock_xp );
524    }
525}   // end putd()
526
527///////////////////////////////
528void nolock_putd( int32_t val )
529{
530    static const char HexaTab[] = "0123456789ABCDEF";
531
532    char      buf[10];
533    uint32_t  i;
534
535    if (val < 0) 
536    {
537        val = -val;
538        dev_txt_sync_write( "-" , 1 );
539    }
540
541    for(i = 0; i < 10 ; i++) 
542    {
543        buf[9 - i] = HexaTab[val % 10];
544        if (!(val /= 10)) break;
545    }
546
547    // display buf on TTY0
548    dev_txt_sync_write( &buf[9-i] , i+1 );
549
550}   // end nolock_putd()
551
552/////////////////////////
553void putl( uint64_t val )
554{
555    static const char HexaTab[] = "0123456789ABCDEF";
556
557    char      buf[18];
558    uint32_t  c;
559
560    buf[0] = '0';
561    buf[1] = 'x';
562
563    // build buffer
564    for (c = 0; c < 16; c++) 
565    { 
566        buf[17 - c] = HexaTab[(unsigned int)val & 0xF];
567        val = val >> 4;
568    }
569
570    // get pointers on TXT0 chdev
571    xptr_t    txt0_xp  = chdev_dir.txt_tx[0];
572    cxy_t     txt0_cxy = GET_CXY( txt0_xp );
573    chdev_t * txt0_ptr = GET_PTR( txt0_xp );
574
575    if( txt0_xp != XPTR_NULL )
576    {
577        // get extended pointer on remote TXT0 chdev lock
578        xptr_t  lock_xp = XPTR( txt0_cxy , &txt0_ptr->wait_lock );
579
580        // display string on TTY0
581        remote_busylock_acquire( lock_xp );
582        dev_txt_sync_write( buf , 18 );
583        remote_busylock_release( lock_xp );
584    }
585}   // end putl()
586
587////////////////////////////////
588void nolock_putl( uint64_t val )
589{
590    static const char HexaTab[] = "0123456789ABCDEF";
591
592    char      buf[18];
593    uint32_t  c;
594
595    buf[0] = '0';
596    buf[1] = 'x';
597
598    // build buffer
599    for (c = 0; c < 16; c++) 
600    { 
601        buf[17 - c] = HexaTab[(unsigned int)val & 0xF];
602        val = val >> 4;
603    }
604
605    // display string on TTY0
606    dev_txt_sync_write( buf , 18 );
607
608}   // end nolock_putl()
609
610/////////////////////////////
611void putb( char     * string,
612           uint8_t  * buffer,
613           uint32_t   size )
614{
615    uint32_t line;
616    uint32_t byte;
617    uint32_t nlines;
618
619    nlines = size >> 4;
620    if( size & 0xF ) nlines++;
621
622    // get pointers on TXT0 chdev
623    xptr_t    txt0_xp  = chdev_dir.txt_tx[0];
624    cxy_t     txt0_cxy = GET_CXY( txt0_xp );
625    chdev_t * txt0_ptr = GET_PTR( txt0_xp );
626
627    // get extended pointer on remote TXT0 chdev lock
628    xptr_t  lock_xp = XPTR( txt0_cxy , &txt0_ptr->wait_lock );
629
630    if( txt0_xp != XPTR_NULL )
631    {
632        // get TXT0 lock
633        remote_busylock_acquire( lock_xp );
634
635        // display string on TTY0
636        nolock_printk("\n***** %s *****\n", string );
637
638        for ( line = 0 , byte = 0 ; line < nlines ; line++ )
639        {
640            nolock_printk(" %X | %b %b %b %b | %b %b %b %b | %b %b %b %b | %b %b %b %b |\n",
641            buffer + byte,
642            buffer[byte+ 0],buffer[byte+ 1],buffer[byte+ 2],buffer[byte+ 3],
643            buffer[byte+ 4],buffer[byte+ 5],buffer[byte+ 6],buffer[byte+ 7],
644            buffer[byte+ 8],buffer[byte+ 9],buffer[byte+10],buffer[byte+11],
645            buffer[byte+12],buffer[byte+13],buffer[byte+14],buffer[byte+15] );
646
647            byte += 16;
648        }
649
650        // release TXT0 lock
651        remote_busylock_release( lock_xp );
652    }
653}   // end putb()
654
655
656
657// Local Variables:
658// tab-width: 4
659// c-basic-offset: 4
660// c-file-offsets:((innamespace . 0)(inline-open . 0))
661// indent-tabs-mode: nil
662// End:
663// vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
664
Note: See TracBrowser for help on using the repository browser.