/* * printk.c - Kernel Log & debug messages API implementation. * * authors Alain Greiner (2016,2017,2018) * * Copyright (c) UPMC Sorbonne Universites * * This file is part of ALMOS-MKH.. * * ALMOS-MKH. is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2.0 of the License. * * ALMOS-MKH. is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with ALMOS-MKH.; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include #include /////////////////////////////////////////////////////////////////////////////////// // Extern variables /////////////////////////////////////////////////////////////////////////////////// extern chdev_directory_t chdev_dir; // defined in chdev.h / allocated in kernel_init.c ///////////////////////////////////// uint32_t snprintf( char * string, uint32_t length, char * format, ... ) { #define TO_STREAM(x) do { string[ps] = (x); ps++; if(ps==length) return -1; } while(0); va_list args; // printf arguments uint32_t ps; // write pointer to the string buffer ps = 0; va_start( args , format ); xprintf_text: while ( *format != 0 ) { if (*format == '%') // copy argument to string { format++; goto xprintf_arguments; } else // copy one char to string { TO_STREAM( *format ); format++; } } va_end( args ); // add terminating NUL chracter TO_STREAM( 0 ); return ps; xprintf_arguments: { char buf[30]; // buffer to display one number char * pbuf; // pointer on first char to display uint32_t len = 0; // number of char to display static const char HexaTab[] = "0123456789ABCDEF"; uint32_t i; // Ignore fields width and precision for ( ; (*format >= '0' && *format <= '9') || (*format == '.') ; format++ ); switch (*format) { case ('c'): // char conversion { int val = va_arg( args, int ); buf[0] = val; pbuf = buf; len = 1; break; } case ('d'): // decimal signed integer { int val = va_arg( args, int ); if (val < 0) { TO_STREAM( '-' ); val = -val; } for(i = 0; i < 10; i++) { buf[9 - i] = HexaTab[val % 10]; if (!(val /= 10)) break; } len = i + 1; pbuf = &buf[9 - i]; break; } case ('u'): // decimal unsigned integer { uint32_t val = va_arg( args, uint32_t ); for(i = 0; i < 10; i++) { buf[9 - i] = HexaTab[val % 10]; if (!(val /= 10)) break; } len = i + 1; pbuf = &buf[9 - i]; break; } case ('x'): // 32 bits hexadecimal case ('l'): // 64 bits hexadecimal { uint32_t imax; uint64_t val; if ( *format == 'l' ) // 64 bits { val = va_arg( args, uint64_t); imax = 16; } else // 32 bits { val = va_arg( args, uint32_t); imax = 8; } TO_STREAM( '0' ); TO_STREAM( 'x' ); for(i = 0; i < imax; i++) { buf[(imax-1) - i] = HexaTab[val % 16]; if (!(val /= 16)) break; } len = i + 1; pbuf = &buf[(imax-1) - i]; break; } case ('X'): // 32 bits hexadecimal on 8 characters { uint32_t val = va_arg( args , uint32_t ); for(i = 0; i < 8; i++) { buf[7 - i] = HexaTab[val % 16]; val = (val>>4); } len = 8; pbuf = buf; break; } case ('s'): /* string */ { char* str = va_arg( args, char* ); while (str[len]) { len++; } pbuf = str; break; } default: // unsupported argument type { return -1; } } // end switch on argument type format++; // copy argument to string for( i = 0 ; i < len ; i++ ) { TO_STREAM( pbuf[i] ); } goto xprintf_text; } } // end snprintf() ////////////////////////////////////////////////////////////////////////////////////// // This static function is called by printk(), assert() and nolock_printk() // to display a formated string on TXT0, using a busy waiting policy. ////////////////////////////////////////////////////////////////////////////////////// // @ format : printf like format. // @ args : va_list of arguments. ////////////////////////////////////////////////////////////////////////////////////// static void kernel_printf( char * format, va_list * args ) { printf_text: while (*format) { uint32_t i; for (i = 0 ; format[i] && (format[i] != '%') ; i++); if (i) { dev_txt_sync_write( format, i ); format += i; } if (*format == '%') { format++; goto printf_arguments; } } return; printf_arguments: { char buf[20]; char * pbuf = NULL; uint32_t len = 0; static const char HexaTab[] = "0123456789ABCDEF"; uint32_t i; switch (*format++) { case ('c'): /* char conversion */ { int val = va_arg( *args , int ); len = 1; buf[0] = val; pbuf = &buf[0]; break; } case ('d'): /* 32 bits decimal signed */ { int val = va_arg( *args , int ); if (val < 0) { val = -val; dev_txt_sync_write( "-" , 1 ); } for(i = 0; i < 10; i++) { buf[9 - i] = HexaTab[val % 10]; if (!(val /= 10)) break; } len = i + 1; pbuf = &buf[9 - i]; break; } case ('u'): /* 32 bits decimal unsigned */ { uint32_t val = va_arg( *args , uint32_t ); for(i = 0; i < 10; i++) { buf[9 - i] = HexaTab[val % 10]; if (!(val /= 10)) break; } len = i + 1; pbuf = &buf[9 - i]; break; } case ('x'): /* 32 bits hexadecimal unsigned */ { uint32_t val = va_arg( *args , uint32_t ); dev_txt_sync_write( "0x" , 2 ); for(i = 0; i < 8; i++) { buf[7 - i] = HexaTab[val & 0xF]; if (!(val = (val>>4))) break; } len = i + 1; pbuf = &buf[7 - i]; break; } case ('X'): /* 32 bits hexadecimal unsigned on 10 char */ { uint32_t val = va_arg( *args , uint32_t ); dev_txt_sync_write( "0x" , 2 ); for(i = 0; i < 8; i++) { buf[7 - i] = HexaTab[val & 0xF]; val = (val>>4); } len = 8; pbuf = buf; break; } case ('l'): /* 64 bits hexadecimal unsigned */ { unsigned long long val = va_arg( *args , unsigned long long ); dev_txt_sync_write( "0x" , 2 ); for(i = 0; i < 16; i++) { buf[15 - i] = HexaTab[val & 0xF]; if (!(val = (val>>4))) break; } len = i + 1; pbuf = &buf[15 - i]; break; } case ('L'): /* 64 bits hexadecimal unsigned on 18 char */ { unsigned long long val = va_arg( *args , unsigned long long ); dev_txt_sync_write( "0x" , 2 ); for(i = 0; i < 16; i++) { buf[15 - i] = HexaTab[val & 0xF]; val = (val>>4); } len = 16; pbuf = buf; break; } case ('s'): /* string */ { char* str = va_arg( *args , char* ); while (str[len]) { len++; } pbuf = str; break; } default: { dev_txt_sync_write( "\n[PANIC] in kernel_printf() : illegal format\n", 45 ); } } if( pbuf != NULL ) dev_txt_sync_write( pbuf, len ); goto printf_text; } } // end kernel_printf() ////////////////////////////////// void printk( char * format , ... ) { va_list args; uint32_t save_sr; // get pointers on TXT0 chdev xptr_t txt0_xp = chdev_dir.txt_tx[0]; cxy_t txt0_cxy = GET_CXY( txt0_xp ); chdev_t * txt0_ptr = GET_PTR( txt0_xp ); // get extended pointer on remote TXT0 chdev lock xptr_t lock_xp = XPTR( txt0_cxy , &txt0_ptr->wait_lock ); // get TXT0 lock in busy waiting mode remote_spinlock_lock_busy( lock_xp , &save_sr ); // call kernel_printf on TXT0, in busy waiting mode va_start( args , format ); kernel_printf( format , &args ); va_end( args ); // release lock remote_spinlock_unlock_busy( lock_xp , save_sr ); } ///////////////////////////////////////// void nolock_printk( char * format , ... ) { va_list args; // call kernel_printf on TXT0, in busy waiting mode va_start( args , format ); kernel_printf( format , &args ); va_end( args ); } //////////////////////////////////// void assert( bool_t condition, const char * function_name, char * format, ... ) { va_list args; uint32_t save_sr; if( condition == false ) { // get pointers on TXT0 chdev xptr_t txt0_xp = chdev_dir.txt_tx[0]; cxy_t txt0_cxy = GET_CXY( txt0_xp ); chdev_t * txt0_ptr = GET_PTR( txt0_xp ); // get extended pointer on remote TXT0 chdev lock xptr_t lock_xp = XPTR( txt0_cxy , &txt0_ptr->wait_lock ); // get TXT0 lock in busy waiting mode remote_spinlock_lock_busy( lock_xp , &save_sr ); // call nolock_printk to print function_name nolock_printk("\n[PANIC] in %s : " , function_name ); // call kernel_printf on TXT0, in busy waiting to print format va_start( args , format ); kernel_printf( format , &args ); va_end( args ); // release TXT0 lock remote_spinlock_unlock_busy( lock_xp , save_sr ); // suicide hal_core_sleep(); } } ////////////////////////// void puts( char * string ) { uint32_t save_sr; uint32_t n = 0; // compute string length while ( string[n] > 0 ) n++; // get pointers on TXT0 chdev xptr_t txt0_xp = chdev_dir.txt_tx[0]; cxy_t txt0_cxy = GET_CXY( txt0_xp ); chdev_t * txt0_ptr = GET_PTR( txt0_xp ); // get extended pointer on remote TXT0 chdev lock xptr_t lock_xp = XPTR( txt0_cxy , &txt0_ptr->wait_lock ); // get TXT0 lock in busy waiting mode remote_spinlock_lock_busy( lock_xp , &save_sr ); // display string on TTY0 dev_txt_sync_write( string , n ); // release TXT0 lock in busy waiting mode remote_spinlock_unlock_busy( lock_xp , save_sr ); } ///////////////////////// void putx( uint32_t val ) { static const char HexaTab[] = "0123456789ABCDEF"; char buf[10]; uint32_t c; uint32_t save_sr; buf[0] = '0'; buf[1] = 'x'; // build buffer for (c = 0; c < 8; c++) { buf[9 - c] = HexaTab[val & 0xF]; val = val >> 4; } // get pointers on TXT0 chdev xptr_t txt0_xp = chdev_dir.txt_tx[0]; cxy_t txt0_cxy = GET_CXY( txt0_xp ); chdev_t * txt0_ptr = GET_PTR( txt0_xp ); // get extended pointer on remote TXT0 chdev lock xptr_t lock_xp = XPTR( txt0_cxy , &txt0_ptr->wait_lock ); // get TXT0 lock in busy waiting mode remote_spinlock_lock_busy( lock_xp , &save_sr ); // display string on TTY0 dev_txt_sync_write( buf , 10 ); // release TXT0 lock in busy waiting mode remote_spinlock_unlock_busy( lock_xp , save_sr ); } ///////////////////////// void putl( uint64_t val ) { static const char HexaTab[] = "0123456789ABCDEF"; char buf[18]; uint32_t c; uint32_t save_sr; buf[0] = '0'; buf[1] = 'x'; // build buffer for (c = 0; c < 16; c++) { buf[17 - c] = HexaTab[(unsigned int)val & 0xF]; val = val >> 4; } // get pointers on TXT0 chdev xptr_t txt0_xp = chdev_dir.txt_tx[0]; cxy_t txt0_cxy = GET_CXY( txt0_xp ); chdev_t * txt0_ptr = GET_PTR( txt0_xp ); // get extended pointer on remote TXT0 chdev lock xptr_t lock_xp = XPTR( txt0_cxy , &txt0_ptr->wait_lock ); // get TXT0 lock in busy waiting mode remote_spinlock_lock_busy( lock_xp , &save_sr ); // display string on TTY0 dev_txt_sync_write( buf , 18 ); // release TXT0 lock in busy waiting mode remote_spinlock_unlock_busy( lock_xp , save_sr ); } // Local Variables: // tab-width: 4 // c-basic-offset: 4 // c-file-offsets:((innamespace . 0)(inline-open . 0)) // indent-tabs-mode: nil // End: // vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4