/* * printk.c - Kernel Log & debug messages API implementation. * * authors Alain Greiner (2016,2017,2018,2019,2020) * * 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 #include #include /////////////////////////////////////////////////////////////////////////////////// // Extern /////////////////////////////////////////////////////////////////////////////////// extern chdev_directory_t chdev_dir; // defined in chdev.h / allocated in kernel_init.c ////////////////////////////////////////////////////////////////////////////////////// // This static function is called by printk(), nolock_printk(), and snprintk(), // functions to build a string from a printf-like , and stores it // in the buffer defined by the and arguments. // The itself is supposed to be a NUL terminated string. The // buffer must be large enough to contains also the NUL terminating character. // If success, it returns the number of bytes actually copied in the buffer, // but this length does NOT include the terminating NUL character. // It returns -2 in case of illegal format, it returns -1 if the formated string // exceeds the argument. ////////////////////////////////////////////////////////////////////////////////////// // @ string : buffer allocated by caller. // @ size : buffer size in bytes // @ format : printf like format. // @ args : va_list of arguments. // @ return string length if success / -1 if buffer too small / -2 if illegal format. ////////////////////////////////////////////////////////////////////////////////////// static int32_t format_to_string( char * string, uint32_t size, const char * format, va_list * args ) { #define TO_STRING(x) do { string[ps] = (x); ps++; if(ps==size) return -1; } while(0); uint32_t ps = 0; // index in string buffer format_to_string_text: // handle one character per iteration while ( *format != 0 ) { if (*format == '%') // copy argument to string { format++; goto format_to_string_arguments; } else // copy one char of format to string { TO_STRING( *format ); format++; } } TO_STRING( 0 ); // NUL character written in buffer return (ps - 1); // but not counted in length format_to_string_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; switch (*format) { case ('c'): // one printable character { buf[0] = (char)va_arg( *args , uint32_t ); pbuf = buf; len = 1; break; } case ('b'): // one ASCII code value (2 hexadecimal digits) { uint8_t val = (uint8_t)va_arg( *args , uint32_t ); buf[1] = HexaTab[val & 0xF]; buf[0] = HexaTab[(val >> 4) & 0xF]; pbuf = buf; len = 2; break; } case ('d'): // one int32_t (up to 10 decimal digits after sign) { int32_t val = va_arg( *args , int32_t ); if (val < 0) { TO_STRING( '-' ); 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'): // one uint32_t (up to 10 decimal digits) { 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'): // one uint32_t (up to 8 hexa digits after "0x") { uint32_t val = va_arg( *args , uint32_t ); TO_STRING( '0' ); TO_STRING( 'x' ); for(i = 0 ; i < 8 ; i++) { buf[7 - i] = HexaTab[val & 0xF]; val = val >> 4; if(val == 0) break; } len = i + 1; pbuf = &buf[7 - i]; break; } case ('X'): // one uint32_t (exactly 8 hexa digits after "0x") { uint32_t val = va_arg( *args , uint32_t ); TO_STRING( '0' ); TO_STRING( 'x' ); for(i = 0 ; i < 8 ; i++) { buf[7 - i] = (val != 0) ? HexaTab[val & 0xF] : '0'; val = val >> 4; } len = 8; pbuf = &buf[0]; break; } case ('l'): // one uint64_t (up to 16 digits hexa after "0x") { uint64_t val = (((uint64_t)va_arg( *args, uint32_t)) << 32) | ((uint64_t)va_arg( *args, uint32_t)); TO_STRING( '0' ); TO_STRING( 'x' ); for(i = 0 ; i < 16 ; i++) { buf[15 - i] = HexaTab[val & 0xF]; val = val >> 4; if( val == 0) break; } len = i + 1; pbuf = &buf[15 - i]; break; } case ('L'): // one uint64_t (exactly 16 digits hexa after "0x") { uint64_t val = (((uint64_t)va_arg( *args, uint32_t)) << 32) | ((uint64_t)va_arg( *args, uint32_t)); TO_STRING( '0' ); TO_STRING( 'x' ); for(i = 0 ; i < 16 ; i++) { buf[15 - i] = (val != 0) ? HexaTab[val & 0xF] : '0'; val = val >> 4; } len = 16; pbuf = &buf[0]; break; } case ('s'): /* one characters string */ { char* str = va_arg( *args , char* ); while (str[len]) { len++; } pbuf = str; break; } default: // unsupported argument type { return -2; } } // end switch on argument type format++; // copy argument sub-string to the string buffer for( i = 0 ; i < len ; i++ ) { TO_STRING( pbuf[i] ); } goto format_to_string_text; } } // end format_to_string() ////////////////////////////////// void printk( char * format , ... ) { char buffer[CONFIG_PRINTK_BUF_SIZE]; va_list args; int32_t length; // build args va_list va_start( args , format ); // 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 lock xptr_t lock_xp = XPTR( txt0_cxy , &txt0_ptr->wait_lock ); // get TXT0 lock remote_busylock_acquire( lock_xp ); // build a string from format length = format_to_string( buffer, CONFIG_PRINTK_BUF_SIZE, format, &args ); va_end( args ); if( length > 0 ) // call TXT driver to display formated string on TXT0 { dev_txt_sync_write( buffer , length ); } else if( length == -2 ) // illegal format => display a warning on TXT0 { thread_t * this = CURRENT_THREAD; nolock_printk("\n[PANIC] from printk : illegal format\n" "thread[%x,%x] on core[%x,%d] at cycle %l\n", this->process->pid, this->trdid, local_cxy, this->core->lid, hal_get_cycles() ); } else // format too long => display a warning on TXT0 { thread_t * this = CURRENT_THREAD; nolock_printk("\n[PANIC] from printk : formated string too long\n" "thread[%x,%x] on core[%x,%d] at cycle %l\n", this->process->pid, this->trdid, local_cxy, this->core->lid, hal_get_cycles() ); } // release TXT0 lock remote_busylock_release( lock_xp ); } // end printk() ///////////////////////////////////////// void nolock_printk( char * format , ... ) { char buffer[CONFIG_PRINTK_BUF_SIZE]; va_list args; int32_t length; // build args va_list va_start( args , format ); // build a string from format length = format_to_string( buffer, CONFIG_PRINTK_BUF_SIZE, format, &args ); va_end( args ); if( length > 0 ) // call TXT driver to display formated string on TXT0 { dev_txt_sync_write( buffer , length ); } else if( length == -2 ) // illegal format => display a warning on TXT0 { thread_t * this = CURRENT_THREAD; nolock_printk("\n[PANIC] from print : illegal format\n" "thread[%x,%x] on core[%x,%d] at cycle %l\n", this->process->pid, this->trdid, local_cxy, this->core->lid, hal_get_cycles() ); } else // buffer too small => display a warning on TXT0 { thread_t * this = CURRENT_THREAD; nolock_printk("\n[PANIC] from printk : formated string too long\n" "thread[%x,%x] on core[%x,%d] at cycle %l\n", this->process->pid, this->trdid, local_cxy, this->core->lid, hal_get_cycles() ); } } // end nolock_printk() ////////////////////////////////////// void assert( const char * func_name, bool_t expr, char * format , ... ) { if( expr == false ) { thread_t * this = CURRENT_THREAD; trdid_t trdid = this->trdid; pid_t pid = this->process->pid; uint32_t lid = this->core->lid; uint32_t cycle = (uint32_t)hal_get_cycles(); char buffer[CONFIG_PRINTK_BUF_SIZE]; va_list args; va_start( args , format ); // build a string from format int32_t length = format_to_string( buffer, CONFIG_PRINTK_BUF_SIZE, format, &args ); va_end( args ); if( length > 0 ) // display panic message on TXT0, including formated string { printk("\n[ASSERT] in %s / core[%x,%d] / thread[%x,%x] / cycle %d\n <%s>\n", func_name, local_cxy, lid, pid, trdid, cycle, buffer ); } else // display minimal panic message on TXT0 { printk("\n[ASSERT] in %s / core[%x,%d] / thread[%x,%x] / cycle %d\n", func_name, local_cxy, lid, pid, trdid, cycle ); } } } // end assert( __FUNCTION__,) ////////////////////////////////////// int32_t snprintk( char * buffer, uint32_t size, char * format, ... ) { va_list args; int32_t length; // build args va_list va_start( args , format ); // build a string from format length = format_to_string( buffer , size , format , &args ); // release args list va_end( args ); if( length < 0 ) return -1; else return length; } // end snprintk() //////////////////////////////// void puts( const char * string ) { 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 ); if( txt0_xp != XPTR_NULL ) { // get extended pointer on remote TXT0 lock xptr_t lock_xp = XPTR( txt0_cxy , &txt0_ptr->wait_lock ); // display string on TTY0 remote_busylock_acquire( lock_xp ); dev_txt_sync_write( string , n ); remote_busylock_release( lock_xp ); } } // end puts() /////////////////////////////////////// void nolock_puts( const char * string ) { uint32_t n = 0; // compute string length while ( string[n] > 0 ) n++; // display string on TTY0 dev_txt_sync_write( string , n ); } // end nolock_puts() ///////////////////////// void putx( uint32_t val ) { static const char HexaTab[] = "0123456789ABCDEF"; char buf[10]; uint32_t c; 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 ); if( txt0_xp != XPTR_NULL ) { // get extended pointer on remote TXT0 chdev lock xptr_t lock_xp = XPTR( txt0_cxy , &txt0_ptr->wait_lock ); // display buf on TTY0 remote_busylock_acquire( lock_xp ); dev_txt_sync_write( buf , 10 ); remote_busylock_release( lock_xp ); } } // end putx() //////////////////////////////// void nolock_putx( uint32_t val ) { static const char HexaTab[] = "0123456789ABCDEF"; char buf[10]; uint32_t c; buf[0] = '0'; buf[1] = 'x'; // build buffer for (c = 0; c < 8; c++) { buf[9 - c] = HexaTab[val & 0xF]; val = val >> 4; } // display buf on TTY0 dev_txt_sync_write( buf , 10 ); } // end nilock_putx() //////////////////////// void putd( int32_t val ) { static const char HexaTab[] = "0123456789ABCDEF"; char buf[10]; uint32_t i; // 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 ); if( txt0_xp != XPTR_NULL ) { // get TXT0 lock remote_busylock_acquire( lock_xp ); 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; } // display buf on TTY0 dev_txt_sync_write( &buf[9-i] , i+1 ); // release TXT0 lock remote_busylock_release( lock_xp ); } } // end putd() /////////////////////////////// void nolock_putd( int32_t val ) { static const char HexaTab[] = "0123456789ABCDEF"; char buf[10]; uint32_t i; 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; } // display buf on TTY0 dev_txt_sync_write( &buf[9-i] , i+1 ); } // end nolock_putd() ///////////////////////// void putl( uint64_t val ) { static const char HexaTab[] = "0123456789ABCDEF"; char buf[18]; uint32_t c; 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 ); if( txt0_xp != XPTR_NULL ) { // get extended pointer on remote TXT0 chdev lock xptr_t lock_xp = XPTR( txt0_cxy , &txt0_ptr->wait_lock ); // display string on TTY0 remote_busylock_acquire( lock_xp ); dev_txt_sync_write( buf , 18 ); remote_busylock_release( lock_xp ); } } // end putl() //////////////////////////////// void nolock_putl( uint64_t val ) { static const char HexaTab[] = "0123456789ABCDEF"; char buf[18]; uint32_t c; 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; } // display string on TTY0 dev_txt_sync_write( buf , 18 ); } // end nolock_putl() ///////////////////////////// void putb( char * string, uint8_t * buffer, uint32_t size ) { uint32_t line; uint32_t byte; uint32_t nlines; nlines = size >> 4; if( size & 0xF ) nlines++; // 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 ); if( txt0_xp != XPTR_NULL ) { // get TXT0 lock remote_busylock_acquire( lock_xp ); // display string on TTY0 nolock_printk("\n***** %s *****\n", string ); for ( line = 0 , byte = 0 ; line < nlines ; line++ ) { nolock_printk(" %X | %b %b %b %b | %b %b %b %b | %b %b %b %b | %b %b %b %b |\n", buffer + byte, buffer[byte+ 0],buffer[byte+ 1],buffer[byte+ 2],buffer[byte+ 3], buffer[byte+ 4],buffer[byte+ 5],buffer[byte+ 6],buffer[byte+ 7], buffer[byte+ 8],buffer[byte+ 9],buffer[byte+10],buffer[byte+11], buffer[byte+12],buffer[byte+13],buffer[byte+14],buffer[byte+15] ); byte += 16; } // release TXT0 lock remote_busylock_release( lock_xp ); } } // end putb() // 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