source: trunk/kernel/kern/printk.c @ 370

Last change on this file since 370 was 337, checked in by alain, 7 years ago

Introduce the delayed context switch if current thread has a lock.

File size: 14.1 KB
Line 
1/*
2 * printk.c - Kernel Log & debug messages API implementation.
3 *
4 * authors  Alain Greiner (2016)
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_types.h>
25#include <hal_irqmask.h>
26#include <hal_special.h>
27#include <dev_txt.h>
28#include <remote_spinlock.h>
29#include <cluster.h>
30#include <chdev.h>
31#include <printk.h>
32
33///////////////////////////////////////////////////////////////////////////////////
34//      Extern variables
35///////////////////////////////////////////////////////////////////////////////////
36
37extern chdev_directory_t  chdev_dir;  // defined in chdev.h / allocated in kernel_init.c
38
39/////////////////////////////////////
40uint32_t snprintf( char     * string,
41                   uint32_t   length,
42                   char     * format, ... )
43{
44
45#define TO_STREAM(x) do { string[ps] = (x); ps++; if(ps==length) return -1; } while(0);
46
47    va_list    args;      // printf arguments
48    uint32_t   ps;        // write pointer to the string buffer
49
50    ps = 0;   
51    va_start( args , format );
52
53xprintf_text:
54
55    while ( *format != 0 ) 
56    {
57
58        if (*format == '%')   // copy argument to string
59        {
60            format++;
61            goto xprintf_arguments;
62        }
63        else                  // copy one char to string
64        {
65            TO_STREAM( *format );
66            format++;
67        }
68    }
69
70    va_end( args );
71   
72    // add terminating NUL chracter
73    TO_STREAM( 0 );
74    return ps;
75
76xprintf_arguments:
77
78    {
79        char              buf[30];    // buffer to display one number
80        char *            pbuf;       // pointer on first char to display
81        uint32_t          len = 0;    // number of char to display
82        static const char HexaTab[] = "0123456789ABCDEF";
83        uint32_t          i;
84       
85        // Ignore fields width and precision
86        for ( ; (*format >= '0' && *format <= '9') || (*format == '.') ; format++ );
87
88        switch (*format) 
89        {
90            case ('c'):             // char conversion
91            {
92                int val = va_arg( args, int );
93                buf[0] = val;
94                pbuf   = buf;
95                len    = 1;
96                break;
97            }
98            case ('d'):             // decimal signed integer
99            {
100                int val = va_arg( args, int );
101                if (val < 0) 
102                {
103                    TO_STREAM( '-' );
104                    val = -val;
105                }
106                for(i = 0; i < 10; i++) 
107                {
108
109                    buf[9 - i] = HexaTab[val % 10];
110                    if (!(val /= 10)) break;
111                }
112                len =  i + 1;
113                pbuf = &buf[9 - i];
114                break;
115            }
116            case ('u'):             // decimal unsigned integer
117            {
118                uint32_t val = va_arg( args, uint32_t );
119                for(i = 0; i < 10; i++) 
120                {
121                    buf[9 - i] = HexaTab[val % 10];
122                    if (!(val /= 10)) break;
123                }
124                len =  i + 1;
125                pbuf = &buf[9 - i];
126                break;
127            }
128            case ('x'):             // 32 bits hexadecimal
129            case ('l'):             // 64 bits hexadecimal
130            {
131                uint32_t imax;
132                uint64_t val;
133               
134                if ( *format == 'l' )   // 64 bits
135                {
136                    val = va_arg( args, uint64_t);
137                    imax = 16;
138                }
139                else                    // 32 bits
140                {
141                    val = va_arg( args, uint32_t);
142                    imax = 8;
143                }
144               
145                TO_STREAM( '0' );
146                TO_STREAM( 'x' );
147               
148                for(i = 0; i < imax; i++) 
149                {
150                    buf[(imax-1) - i] = HexaTab[val % 16];
151                    if (!(val /= 16))  break;
152                }
153                len =  i + 1;
154                pbuf = &buf[(imax-1) - i];
155                break;
156            }
157            case ('X'):             // 32 bits hexadecimal on 8 characters
158            {
159                uint32_t val = va_arg( args , uint32_t );
160                for(i = 0; i < 8; i++) 
161                {
162                    buf[7 - i] = HexaTab[val % 16];
163                    val = (val>>4);
164                }
165                len =  8;
166                pbuf = buf;
167                break;
168            }
169            case ('s'):             /* string */
170            {
171                char* str = va_arg( args, char* );
172                while (str[len]) { len++; }
173                pbuf = str;
174                break;
175            }
176            default:       // unsupported argument type
177            {
178                return -1;
179            }
180        }  // end switch on  argument type
181
182        format++;
183
184        // copy argument to string
185        for( i = 0 ; i < len ; i++ )
186        {
187            TO_STREAM( pbuf[i] );
188        }
189       
190        goto xprintf_text;
191    }
192} // end xprintf()
193
194///////////////////////////////////////////////////////////////////////////////////
195// This static function is called by kernel_printf() to display a string on the
196// TXT channel defined by the <channel> argument.
197// The access mode is defined by the <busy> argument:
198// - if <busy> is true, it uses the dev_txt_sync_write() function, that takes the
199//   TXT lock, and call directly the relevant TXT driver, without descheduling.
200// - if <busy is false, it uses the dev_txt_write() function, that register the
201//   write buffer in the relevant TXT chdev queue, and uses a descheduling policy.
202///////////////////////////////////////////////////////////////////////////////////
203// @ channel  : TXT channel.
204// @ busy     : TXT device acces mode (busy waiting if non zero).
205// @ buf      : buffer containing the characters.
206// @ nc       : number of characters.
207// return 0 if success / return -1 if TTY0 busy after 10000 retries.
208///////////////////////////////////////////////////////////////////////////////////
209static error_t txt_write( uint32_t  channel,
210                          uint32_t  busy,
211                          char    * buffer,
212                          uint32_t  count )
213{
214    if( busy ) return dev_txt_sync_write( channel , buffer , count );
215    else       return dev_txt_write( channel , buffer , count );
216} 
217
218//////////////////////////////////////////////////////////////////////////////////////
219// This static function is called by printk(), assert() and nolock_printk() to build
220// a formated string.
221//////////////////////////////////////////////////////////////////////////////////////
222// @ channel   : channel index.
223// @ busy      : TXT device access mode (busy waiting if non zero).
224// @ format    : printf like format.
225// @ args      : format arguments.
226//////////////////////////////////////////////////////////////////////////////////////
227static void kernel_printf( uint32_t   channel,
228                           uint32_t   busy,
229                           char     * format, 
230                           va_list  * args ) 
231{
232
233printf_text:
234
235    while (*format) 
236    {
237        uint32_t i;
238        for (i = 0 ; format[i] && (format[i] != '%') ; i++);
239        if (i) 
240        {
241            txt_write( channel, busy, format, i );
242            format += i;
243        }
244        if (*format == '%') 
245        {
246            format++;
247            goto printf_arguments;
248        }
249    }
250
251    return;
252
253printf_arguments:
254
255    {
256        char      buf[20];
257        char    * pbuf = NULL;
258        uint32_t  len  = 0;
259        static const char HexaTab[] = "0123456789ABCDEF";
260        uint32_t i;
261
262        switch (*format++) 
263        {
264            case ('c'):             /* char conversion */
265            {
266                int val = va_arg( *args , int );
267                len = 1;
268                buf[0] = val;
269                pbuf = &buf[0];
270                break;
271            }
272            case ('d'):             /* 32 bits decimal signed  */
273            {
274                int val = va_arg( *args , int );
275                if (val < 0) 
276                {
277                    val = -val;
278                    txt_write( channel, busy, "-" , 1 );
279                }
280                for(i = 0; i < 10; i++) 
281                {
282                    buf[9 - i] = HexaTab[val % 10];
283                    if (!(val /= 10)) break;
284                }
285                len =  i + 1;
286                pbuf = &buf[9 - i];
287                break;
288            }
289            case ('u'):             /* 32 bits decimal unsigned  */
290            {
291                uint32_t val = va_arg( *args , uint32_t );
292                for(i = 0; i < 10; i++) 
293                {
294                    buf[9 - i] = HexaTab[val % 10];
295                    if (!(val /= 10)) break;
296                }
297                len =  i + 1;
298                pbuf = &buf[9 - i];
299                break;
300            }
301            case ('x'):             /* 32 bits hexadecimal unsigned */
302            {
303                uint32_t val = va_arg( *args , uint32_t );
304                txt_write( channel, busy, "0x" , 2 );
305                for(i = 0; i < 8; i++) 
306                {
307                    buf[7 - i] = HexaTab[val & 0xF];
308                    if (!(val = (val>>4)))  break;
309                }
310                len =  i + 1;
311                pbuf = &buf[7 - i];
312                break;
313            }
314            case ('X'):             /* 32 bits hexadecimal unsigned  on 10 char */
315            {
316                uint32_t val = va_arg( *args , uint32_t );
317                txt_write( channel, busy, "0x" , 2 );
318                for(i = 0; i < 8; i++) 
319                {
320                    buf[7 - i] = HexaTab[val & 0xF];
321                    val = (val>>4);
322                }
323                len =  8;
324                pbuf = buf;
325                break;
326            }
327            case ('l'):            /* 64 bits hexadecimal unsigned */
328            {
329                uint64_t val = va_arg( *args , uint64_t );
330                txt_write( channel, busy, "0x" , 2 );
331                for(i = 0; i < 16; i++) 
332                {
333                    buf[15 - i] = HexaTab[val & 0xF];
334                    if (!(val = (val>>4)))  break;
335                }
336                len =  i + 1;
337                pbuf = &buf[15 - i];
338                break;
339            }
340            case ('L'):           /* 64 bits hexadecimal unsigned on 18 char */ 
341            {
342                uint64_t val = va_arg( *args , uint64_t );
343                txt_write( channel, busy, "0x" , 2 );
344                for(i = 0; i < 16; i++) 
345                {
346                    buf[15 - i] = HexaTab[val & 0xF];
347                    val = (val>>4);
348                }
349                len =  16;
350                pbuf = buf;
351                break;
352            }
353            case ('s'):             /* string */
354            {
355                char* str = va_arg( *args , char* );
356                while (str[len]) 
357                {
358                    len++;
359                }
360                pbuf = str;
361                break;
362            }
363            default:
364            {
365                txt_write( channel , busy,
366                           "\n[PANIC] in kernel_printf() : illegal format\n", 45 );
367            }
368        }
369
370        if( pbuf != NULL ) txt_write( channel, busy, pbuf, len );
371       
372        goto printf_text;
373    }
374
375}  // end kernel_printf()
376
377//////////////////////////////////
378void printk( char * format , ... )
379{
380    va_list       args;
381    uint32_t      save_sr;
382
383    // get pointers on TXT0 chdev
384    xptr_t    txt0_xp  = chdev_dir.txt[0];
385    cxy_t     txt0_cxy = GET_CXY( txt0_xp );
386    chdev_t * txt0_ptr = GET_PTR( txt0_xp );
387
388    // get extended pointer on remote TXT0 chdev lock
389    xptr_t  lock_xp = XPTR( txt0_cxy , &txt0_ptr->wait_lock );
390
391    // get TXT0 lock in busy waiting mode
392    remote_spinlock_lock_busy( lock_xp , &save_sr );
393
394    // call kernel_printf on TXT0, in busy waiting mode
395    va_start( args , format );
396    kernel_printf( 0 , 1 , format , &args );
397    va_end( args );
398
399    // release lock
400    remote_spinlock_unlock_busy( lock_xp , save_sr );
401}
402
403/////////////////////////////////////////
404void nolock_printk( char * format , ... )
405{
406    va_list       args;
407
408    // call kernel_printf on TXT0, in busy waiting mode
409    va_start( args , format );
410    kernel_printf( 0 , 1 , format , &args );
411    va_end( args );
412}
413
414////////////////////////////////////
415void assert( bool_t       condition,
416             const char * function_name,
417             char       * format, ... )
418{
419    va_list       args;
420    uint32_t      save_sr;
421
422    if( condition == false )
423    {
424        // get pointers on TXT0 chdev
425        xptr_t    txt0_xp  = chdev_dir.txt[0];
426        cxy_t     txt0_cxy = GET_CXY( txt0_xp );
427        chdev_t * txt0_ptr = GET_PTR( txt0_xp );
428
429        // get extended pointer on remote TXT0 chdev lock
430        xptr_t  lock_xp = XPTR( txt0_cxy , &txt0_ptr->wait_lock );
431
432        // get TXT0 lock in busy waiting mode
433        remote_spinlock_lock_busy( lock_xp , &save_sr );
434
435        // call nolock_printk to print function_name
436        nolock_printk("\n[PANIC] in %s : " , function_name );
437
438        // call kernel_printf on TXT0, in busy waiting to print format
439        va_start( args , format );
440        kernel_printf( 0 , 1 , format , &args );
441        va_end( args );
442
443        // release TXT0 lock
444        remote_spinlock_unlock_busy( lock_xp , save_sr );
445
446        // suicide
447        hal_core_sleep();
448    }
449}
450
451
452// Local Variables:
453// tab-width: 4
454// c-basic-offset: 4
455// c-file-offsets:((innamespace . 0)(inline-open . 0))
456// indent-tabs-mode: nil
457// End:
458// vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
459
Note: See TracBrowser for help on using the repository browser.