/* * sys_display.c - display the current state of a kernel structure on TXT0 * * Author Alain Greiner (2016,2017,2018, 2019) * * 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 #include #include #include #include ///////////////////////////////////////////////////////////////////////////////// // This static function returns a printable string for the type of display. ///////////////////////////////////////////////////////////////////////////////// #if DEBUG_SYS_DISPLAY static char* display_type_str( uint32_t type ) { if ( type == DISPLAY_STRING ) return "STRING"; else if( type == DISPLAY_VMM ) return "VMM"; else if( type == DISPLAY_SCHED ) return "SCHED"; else if( type == DISPLAY_CLUSTER_PROCESSES ) return "CLUSTER_PROCESSES"; else if( type == DISPLAY_VFS ) return "VFS"; else if( type == DISPLAY_CHDEV ) return "CHDEV"; else if( type == DISPLAY_TXT_PROCESSES ) return "TXT_PROCESSES"; else if( type == DISPLAY_DQDT ) return "DQDT"; else if( type == DISPLAY_BUSYLOCKS ) return "BUSYLOCKS"; else if( type == DISPLAY_MAPPER ) return "MAPPER"; else if( type == DISPLAY_BARRIER ) return "BARRIER"; else return "undefined"; } #endif ///////////////////////////// int sys_display( reg_t type, reg_t arg0, reg_t arg1, reg_t arg2 ) { error_t error; vseg_t * vseg; thread_t * this = CURRENT_THREAD; process_t * process = this->process; #if (DEBUG_SYS_DISPLAY || CONFIG_INSTRUMENTATION_SYSCALLS) uint64_t tm_start = hal_get_cycles(); #endif #if DEBUG_SYS_DISPLAY tm_start = hal_get_cycles(); if( DEBUG_SYS_DISPLAY < tm_start ) printk("\n[%s] thread[%x,%x] enter / type %s / cycle = %d\n", __FUNCTION__, process->pid, this->trdid, display_type_str(type), (uint32_t)tm_start ); #endif switch( type ) { //////////////////// case DISPLAY_STRING: { char kbuf[512]; uint32_t length; char * string = (char *)arg0; // check string in user space error = vmm_get_vseg( process , (intptr_t)arg0 , &vseg ); if( error ) { #if DEBUG_SYSCALLS_ERROR printk("\n[ERROR] in %s for STRING : string buffer %x unmapped\n", __FUNCTION__ , (intptr_t)arg0 ); #endif this->errno = EINVAL; return -1; } // ckeck string length length = hal_strlen_from_uspace( string ); if( length >= 512 ) { #if DEBUG_SYSCALLS_ERROR printk("\n[ERROR] in %s for STRING : string length %d too large\n", __FUNCTION__ , length ); #endif this->errno = EINVAL; return -1; } // copy string to kernel space hal_strcpy_from_uspace( kbuf , string , 512 ); // print message on TXT0 kernel terminal printk("\n%s / cycle %d\n", kbuf, (uint32_t)hal_get_cycles() ); break; } ///////////////// case DISPLAY_VMM: { cxy_t cxy = (cxy_t)arg0; pid_t pid = (pid_t)arg1; // check cxy argument if( cluster_is_undefined( cxy ) ) { #if DEBUG_SYSCALLS_ERROR printk("\n[ERROR] in %s for VMM : process %x in cluster %x not found\n", __FUNCTION__ , pid , cxy ); #endif this->errno = EINVAL; return -1; } // get extended pointer on process PID in cluster CXY xptr_t process_xp = cluster_get_process_from_pid_in_cxy( cxy , pid ); if( process_xp == XPTR_NULL ) { #if DEBUG_SYSCALLS_ERROR printk("\n[ERROR] in %s for VMM : process %x in cluster %x not found\n", __FUNCTION__ , pid , cxy ); #endif this->errno = EINVAL; return -1; } // get local pointer on process process_t * process = (process_t *)GET_PTR( process_xp ); // call kernel function if( cxy == local_cxy ) { hal_vmm_display( process , true ); } else { rpc_hal_vmm_display_client( cxy , process , true ); } break; } /////////////////// case DISPLAY_SCHED: { cxy_t cxy = (cxy_t)arg0; lid_t lid = (lid_t)arg1; // check cxy argument if( cluster_is_undefined( cxy ) ) { #if DEBUG_SYSCALLS_ERROR printk("\n[ERROR] in %s for SCHED : illegal cxy argument %x\n", __FUNCTION__ , cxy ); #endif this->errno = EINVAL; return -1; } // check lid argument if( lid >= LOCAL_CLUSTER->cores_nr ) { #if DEBUG_SYSCALLS_ERROR printk("\n[ERROR] in %s for SCHED : illegal lid argument %x\n", __FUNCTION__ , lid ); #endif this->errno = EINVAL; return -1; } if( cxy == local_cxy ) { sched_display( lid ); } else { sched_remote_display( cxy , lid ); } break; } /////////////////////////////// case DISPLAY_CLUSTER_PROCESSES: { cxy_t cxy = (cxy_t)arg0; bool_t owned = (bool_t)arg1; // check cxy argument if( cluster_is_undefined( cxy ) ) { #if DEBUG_SYSCALLS_ERROR printk("\n[ERROR] in %s for CLUSTER_PROCESSES : illegal cxy argument %x\n", __FUNCTION__ , cxy ); #endif this->errno = EINVAL; return -1; } cluster_processes_display( cxy , owned ); break; } ///////////////// case DISPLAY_VFS: { vfs_display( process->vfs_root_xp ); break; } /////////////////// case DISPLAY_CHDEV: { chdev_dir_display(); break; } /////////////////////////// case DISPLAY_TXT_PROCESSES: { uint32_t txt_id = (uint32_t)arg0; // check argument if( txt_id >= LOCAL_CLUSTER->nb_txt_channels ) { #if DEBUG_SYSCALLS_ERROR printk("\n[ERROR] in %s for TXT_PROCESSES : illegal txt_id argument %d\n", __FUNCTION__ , txt_id ); #endif this->errno = EINVAL; return -1; } process_txt_display( txt_id ); break; } ////////////////// case DISPLAY_DQDT: { dqdt_display(); break; } /////////////////////// case DISPLAY_BUSYLOCKS: { pid_t pid = (pid_t)arg0; trdid_t trdid = (trdid_t)arg1; // get extended pointer on target thread xptr_t thread_xp = thread_get_xptr( pid , trdid ); if( thread_xp == XPTR_NULL ) { #if DEBUG_SYSCALLS_ERROR printk("\n[ERROR] in %s for BUSYLOCKS : thread[%x,%x] not found\n", __FUNCTION__ , pid, trdid ); #endif this->errno = EINVAL; return -1; } thread_display_busylocks( thread_xp , __FUNCTION__ ); break; } //////////////////// case DISPLAY_MAPPER: { xptr_t root_inode_xp; xptr_t inode_xp; cxy_t inode_cxy; vfs_inode_t * inode_ptr; xptr_t mapper_xp; mapper_t * mapper_ptr; char kbuf[CONFIG_VFS_MAX_PATH_LENGTH]; char * path = (char *)arg0; uint32_t page_id = (uint32_t)arg1; uint32_t nbytes = (uint32_t)arg2; // check pathname length if( hal_strlen_from_uspace( path ) >= CONFIG_VFS_MAX_PATH_LENGTH ) { #if DEBUG_SYSCALLS_ERROR printk("\n[ERROR] in %s for MAPPER : pathname too long\n", __FUNCTION__ ); #endif this->errno = ENFILE; return -1; } // copy pathname in kernel space hal_strcpy_from_uspace( kbuf , path , CONFIG_VFS_MAX_PATH_LENGTH ); // compute root inode for pathname if( kbuf[0] == '/' ) // absolute path { // use extended pointer on VFS root inode root_inode_xp = process->vfs_root_xp; } else // relative path { // get cluster and local pointer on reference process xptr_t ref_xp = process->ref_xp; process_t * ref_ptr = (process_t *)GET_PTR( ref_xp ); cxy_t ref_cxy = GET_CXY( ref_xp ); // get extended pointer on CWD inode root_inode_xp = hal_remote_l64( XPTR( ref_cxy , &ref_ptr->cwd_xp ) ); } // get extended pointer on target inode error = vfs_lookup( root_inode_xp, kbuf, 0, &inode_xp, NULL ); if( error ) { #if DEBUG_SYSCALLS_ERROR printk("\n[ERROR] in %s for MAPPER : cannot found inode <%s>\n", __FUNCTION__ , kbuf ); #endif this->errno = ENFILE; return -1; } // get target inode cluster and local pointer inode_cxy = GET_CXY( inode_xp ); inode_ptr = GET_PTR( inode_xp ); // get extended pointer on target mapper mapper_ptr = hal_remote_lpt( XPTR( inode_cxy , &inode_ptr->mapper ) ); mapper_xp = XPTR( inode_cxy , mapper_ptr ); // display mapper error = mapper_display_page( mapper_xp , page_id , nbytes ); if( error ) { #if DEBUG_SYSCALLS_ERROR printk("\n[ERROR] in %s for MAPPER : cannot display page %d\n", __FUNCTION__ , page_id ); #endif this->errno = ENFILE; return -1; } break; } ///////////////////// case DISPLAY_BARRIER: { // get target process PID pid_t pid = (pid_t)arg0; // get pointers on owner process xptr_t process_xp = cluster_get_reference_process_from_pid( pid ); process_t * process_ptr = GET_PTR( process_xp ); cxy_t process_cxy = GET_CXY( process_xp ); if( process_xp == XPTR_NULL ) { #if DEBUG_SYSCALLS_ERROR printk("\n[ERROR] in %s for BARRIER : process %x not found\n", __FUNCTION__ , pid ); #endif this->errno = EINVAL; return -1; } // get extended pointer on root of list of barriers xptr_t root_xp = XPTR( process_cxy , &process_ptr->barrier_root ); if( xlist_is_empty( root_xp ) ) { #if DEBUG_SYSCALLS_ERROR printk("\n[ERROR] in %s for BARRIER : no registered barrier in process %x\n", __FUNCTION__ , pid ); #endif this->errno = EINVAL; return -1; } // get extended pointer on first registered generic barrier descriptor xptr_t gen_barrier_xp = XLIST_FIRST( root_xp , generic_barrier_t , list ); // display barrier state generic_barrier_display( gen_barrier_xp ); break; } //////// default: { #if DEBUG_SYSCALLS_ERROR printk("\n[ERROR] in %s : undefined display type %d\n", __FUNCTION__ , type ); #endif this->errno = EINVAL; return -1; } } // end switch on type #if (DEBUG_SYS_DISPLAY || CONFIG_INSTRUMENTATION_SYSCALLS) uint64_t tm_end = hal_get_cycles(); #endif #if DEBUG_SYS_DISPLAY if( DEBUG_SYS_DISPLAY < tm_end ) printk("\n[%s] thread[%x,%x] exit / cycle %d\n", __FUNCTION__, process->pid, this->trdid, (uint32_t)tm_end ); #endif #if CONFIG_INSTRUMENTATION_SYSCALLS hal_atomic_add( &syscalls_cumul_cost[SYS_DISPLAY] , tm_end - tm_start ); hal_atomic_add( &syscalls_occurences[SYS_DISPLAY] , 1 ); #endif return 0; } // end sys_display()