/* * rpc.c - RPC related operations implementation. * * Author Alain Greiner (2016,2017) * * 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 #include #include #include #include #include ///////////////////////////////////////////////////////////////////////////////////////// // array of function pointers (must be consistent with enum in rpc.h) ///////////////////////////////////////////////////////////////////////////////////////// rpc_server_t * rpc_server[RPC_MAX_INDEX] = { &rpc_pmem_get_pages_server, // 0 &rpc_process_pid_alloc_server, // 1 &rpc_process_exec_server, // 2 &rpc_process_kill_server, // 3 &rpc_thread_user_create_server, // 4 &rpc_thread_kernel_create_server, // 5 &rpc_signal_rise_server, // 6 &rpc_undefined, // 7 &rpc_undefined, // 8 &rpc_undefined, // 9 &rpc_vfs_inode_create_server, // 10 &rpc_vfs_inode_destroy_server, // 11 &rpc_vfs_dentry_create_server, // 12 &rpc_vfs_dentry_destroy_server, // 13 &rpc_vfs_file_create_server, // 14 &rpc_vfs_file_destroy_server, // 15 &rpc_vfs_inode_load_server, // 16 &rpc_vfs_mapper_load_all_server, // 17 &rpc_fatfs_get_cluster_server, // 18 &rpc_undefined, // 19 &rpc_vmm_get_ref_vseg_server, // 20 &rpc_vmm_get_pte_server, // 21 &rpc_kcm_alloc_server, // 22 &rpc_kcm_free_server, // 23 &rpc_mapper_move_buffer_server, // 24 &rpc_mapper_get_page_server, // 25 &rpc_undefined, // 26 &rpc_undefined, // 27 &rpc_undefined, // 28 &rpc_undefined, // 29 }; ////////////////////////////////////////////// void __attribute__((noinline)) rpc_undefined() { printk("\n[PANIC] ‰s called in cluster %x\n", __FUNCTION__ , local_cxy ); hal_core_sleep(); } ///////////////////////////////////////////////////////////////////////////////////////// // [0] Marshaling functions attached to RPC_PMEM_GET_PAGES ///////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////// void rpc_pmem_get_pages_client( cxy_t cxy, uint32_t order, // in page_t ** page ) // out { rpc_dmsg("\n[INFO] %s : enter at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); assert( (cxy != local_cxy) , __FUNCTION__ , "target cluster is not remote\n"); // initialise RPC descriptor header rpc_desc_t rpc; rpc.index = RPC_PMEM_GET_PAGES; rpc.response = 1; // set input arguments in RPC descriptor rpc.args[0] = (uint64_t)order; // register RPC request in remote RPC fifo (blocking function) rpc_send_sync( cxy , &rpc ); // get output arguments from RPC descriptor *page = (page_t *)(intptr_t)rpc.args[1]; rpc_dmsg("\n[INFO] %s : completed at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); } /////////////////////////////////////////// void rpc_pmem_get_pages_server( xptr_t xp ) { rpc_dmsg("\n[INFO] %s : enter at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); // get client cluster identifier and pointer on RPC descriptor cxy_t cxy = (cxy_t)GET_CXY( xp ); rpc_desc_t * desc = (rpc_desc_t *)GET_PTR( xp ); // get input arguments from client RPC descriptor uint32_t order = hal_remote_lw( XPTR( cxy , &desc->args[0] ) ); // call local pmem allocator page_t * page = ppm_alloc_pages( order ); // set output arguments into client RPC descriptor hal_remote_swd( XPTR( cxy , &desc->args[1] ) , (uint64_t)(intptr_t)page ); rpc_dmsg("\n[INFO] %s : completed at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); } ///////////////////////////////////////////////////////////////////////////////////////// // [1] Marshaling functions attached to RPC_PROCESS_PID_ALLOC ///////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////// void rpc_process_pid_alloc_client( cxy_t cxy, process_t * process, // in error_t * error, // out pid_t * pid ) // out { rpc_dmsg("\n[INFO] %s : enter at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); assert( (cxy != local_cxy) , __FUNCTION__ , "target cluster is not remote\n"); // initialise RPC descriptor header rpc_desc_t rpc; rpc.index = RPC_PROCESS_PID_ALLOC; rpc.response = 1; // set input arguments in RPC descriptor rpc.args[0] = (uint64_t)(intptr_t)process; // register RPC request in remote RPC fifo (blocking function) rpc_send_sync( cxy , &rpc ); // get output arguments RPC descriptor *pid = (pid_t)rpc.args[1]; *error = (error_t)rpc.args[2]; rpc_dmsg("\n[INFO] %s : completed at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); } ////////////////////////////////////////////// void rpc_process_pid_alloc_server( xptr_t xp ) { process_t * process; // input : client process descriptor error_t error; // output : error status pid_t pid; // output : process identifier rpc_dmsg("\n[INFO] %s : enter at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); // get client cluster identifier and pointer on RPC descriptor cxy_t client_cxy = (cxy_t)GET_CXY( xp ); rpc_desc_t * desc = (rpc_desc_t *)GET_PTR( xp ); // get input argument from client RPC descriptor process = (process_t*)(intptr_t)hal_remote_lwd( XPTR( client_cxy , &desc->args[0] ) ); // call local pid allocator xptr_t xp_process = XPTR( client_cxy , process ); error = cluster_pid_alloc( xp_process , &pid ); // set output arguments into client RPC descriptor hal_remote_sw( XPTR( client_cxy , &desc->args[0] ) , (uint64_t)error ); hal_remote_sw( XPTR( client_cxy , &desc->args[1] ) , (uint64_t)pid ); rpc_dmsg("\n[INFO] %s : completed at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); } ///////////////////////////////////////////////////////////////////////////////////////// // [2] Marshaling functions attached to RPC_PROCESS_EXEC ///////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////// void rpc_process_exec_client( cxy_t cxy, exec_info_t * info, // in error_t * error ) // out { rpc_dmsg("\n[INFO] %s : enter at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); assert( (cxy != local_cxy) , __FUNCTION__ , "target cluster is not remote\n"); // initialise RPC descriptor header rpc_desc_t rpc; rpc.index = RPC_PROCESS_EXEC; rpc.response = 1; // set input arguments in RPC descriptor rpc.args[0] = (uint64_t)(intptr_t)info; // register RPC request in remote RPC fifo (blocking function) rpc_send_sync( cxy , &rpc ); // get output arguments from RPC descriptor *error = (error_t)rpc.args[1]; rpc_dmsg("\n[INFO] %s : completed at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); } ///////////////////////////////////////// void rpc_process_exec_server( xptr_t xp ) { exec_info_t * ptr; // local pointer on remote exec_info structure exec_info_t info; // local copy of exec_info structure error_t error; // local error error status rpc_dmsg("\n[INFO] %s : enter at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); // get client cluster identifier and pointer on RPC descriptor cxy_t client_cxy = (cxy_t)GET_CXY( xp ); rpc_desc_t * desc = (rpc_desc_t *)GET_PTR( xp ); // get pointer on exec_info structure in client cluster from RPC descriptor ptr = (exec_info_t*)(intptr_t)hal_remote_lwd( XPTR( client_cxy , &desc->args[0] ) ); // copy exec_info structure from client buffer to server buffer hal_remote_memcpy( XPTR( client_cxy , ptr ), XPTR( local_cxy , &info ), sizeof(exec_info_t) ); // call local kernel function error = process_make_exec( &info ); // set output argument into client RPC descriptor hal_remote_swd( XPTR( client_cxy , &desc->args[1] ) , (uint64_t)error ); rpc_dmsg("\n[INFO] %s : completed at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); } ///////////////////////////////////////////////////////////////////////////////////////// // [3] Marshaling functions attached to RPC_PROCESS_KILL ///////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////// void rpc_process_kill_client( process_t * process ) { rpc_dmsg("\n[INFO] %s : enter at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); // only reference cluster can send this RPC assert( (GET_CXY( process->ref_xp ) == local_cxy) , __FUNCTION__ , "caller must be reference process cluster\n"); // get local process index in reference cluster lpid_t lpid = LPID_FROM_PID( process->pid ); // get local process manager pointer pmgr_t * pmgr = &LOCAL_CLUSTER->pmgr; // get number of copies uint32_t copies = pmgr->copies_nr[lpid]; // initialise RPC descriptor rpc_desc_t rpc; rpc.index = RPC_PROCESS_KILL; rpc.response = copies; rpc.args[0] = (uint64_t)process->pid; // loop on list of copies to send RPC xptr_t iter; XLIST_FOREACH( XPTR( local_cxy , &pmgr->copies_root[lpid] ) , iter ) { // get cluster_identifier for current copy cxy_t target_cxy = GET_CXY( iter ); // register RPC request in remote RPC fifo ... but the reference if( target_cxy != local_cxy ) rpc_send_sync( target_cxy , &rpc ); } rpc_dmsg("\n[INFO] %s : completed at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); } ///////////////////////////////////////// void rpc_process_kill_server( xptr_t xp ) { pid_t pid; process_t * process; rpc_dmsg("\n[INFO] %s : enter at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); // get client cluster identifier and pointer on RPC descriptor cxy_t client_cxy = (cxy_t)GET_CXY( xp ); rpc_desc_t * desc = (rpc_desc_t *)GET_PTR( xp ); // get pid argument from RPC descriptor pid = (pid_t)hal_remote_lwd( XPTR( client_cxy , &desc->args[0] ) ); // get process pointer to call local kernel function process = cluster_get_local_process_from_pid( pid ); if( process == NULL ) // process not found => do nothing { printk("\n[WARNING] in %s : process %x not found in cluster %x\n", __FUNCTION__ , pid , local_cxy ); } else // destroy process { process_kill( process ); } rpc_dmsg("\n[INFO] %s : completed at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); } ///////////////////////////////////////////////////////////////////////////////////////// // [4] Marshaling functions attached to RPC_THREAD_USER_CREATE ///////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////// void rpc_thread_user_create_client( cxy_t cxy, pid_t pid, // in void * start_func, // in void * start_arg, // in pthread_attr_t * attr, // in xptr_t * thread_xp, // out error_t * error ) // out { rpc_dmsg("\n[INFO] %s : enter at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); assert( (cxy != local_cxy) , __FUNCTION__ , "target cluster is not remote\n"); // initialise RPC descriptor header rpc_desc_t rpc; rpc.index = RPC_THREAD_USER_CREATE; rpc.response = 1; // set input arguments in RPC descriptor rpc.args[0] = (uint64_t)pid; rpc.args[1] = (uint64_t)(intptr_t)start_func; rpc.args[2] = (uint64_t)(intptr_t)start_arg; rpc.args[3] = (uint64_t)(intptr_t)attr; // register RPC request in remote RPC fifo rpc_send_sync( cxy , &rpc ); // get output arguments from RPC descriptor *thread_xp = (xptr_t)rpc.args[4]; *error = (error_t)rpc.args[5]; rpc_dmsg("\n[INFO] %s : completed at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); } /////////////////////////////////////////////// void rpc_thread_user_create_server( xptr_t xp ) { pthread_attr_t * attr_ptr; // pointer on attributes structure in client cluster pthread_attr_t attr_copy; // attributes structure copy in server cluster thread_t * thread_ptr; // local pointer on thread descriptor xptr_t thread_xp; // extended pointer on thread descriptor pid_t pid; // process identifier void * start_func; void * start_arg; error_t error; rpc_dmsg("\n[INFO] %s : enter at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); // get client cluster identifier and pointer on RPC descriptor cxy_t client_cxy = (cxy_t)GET_CXY( xp ); rpc_desc_t * desc = (rpc_desc_t *)GET_PTR( xp ); // get pointer on attributes structure in client cluster from RPC descriptor // get input arguments from RPC descriptor pid = (pid_t) hal_remote_lwd(XPTR(client_cxy , &desc->args[0])); start_func = (void *)(intptr_t) hal_remote_lwd(XPTR(client_cxy , &desc->args[1])); start_arg = (void *)(intptr_t) hal_remote_lwd(XPTR(client_cxy , &desc->args[2])); attr_ptr = (pthread_attr_t *)(intptr_t)hal_remote_lwd(XPTR(client_cxy , &desc->args[3])); // makes a local copy of attributes structure hal_remote_memcpy( XPTR( local_cxy , &attr_copy ), XPTR( client_cxy , attr_ptr ), sizeof(pthread_attr_t) ); assert( (attr_copy.cxy == local_cxy) , __FUNCTION__ , "bad target cluster\n" ); // call kernel function error = thread_user_create( pid, start_func, start_arg, &attr_copy, &thread_ptr ); // set output arguments thread_xp = XPTR( local_cxy , thread_ptr ); hal_remote_swd( XPTR( client_cxy , &desc->args[1] ) , (uint64_t)error ); hal_remote_swd( XPTR( client_cxy , &desc->args[2] ) , (uint64_t)thread_xp ); rpc_dmsg("\n[INFO] %s : completed at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); } ///////////////////////////////////////////////////////////////////////////////////////// // [5] Marshaling functions attached to RPC_THREAD_KERNEL_CREATE ///////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////// void rpc_thread_kernel_create_client( cxy_t cxy, uint32_t type, // in void * func, // in void * args, // in xptr_t * thread_xp, // out error_t * error ) // out { rpc_dmsg("\n[INFO] %s : enter at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); assert( (cxy != local_cxy) , __FUNCTION__ , "target cluster is not remote\n"); // initialise RPC descriptor header rpc_desc_t rpc; rpc.index = RPC_THREAD_KERNEL_CREATE; rpc.response = 1; // set input arguments in RPC descriptor rpc.args[0] = (uint64_t)type; rpc.args[1] = (uint64_t)(intptr_t)func; rpc.args[2] = (uint64_t)(intptr_t)args; // register RPC request in remote RPC fifo rpc_send_sync( cxy , &rpc ); // get output arguments from RPC descriptor *thread_xp = (xptr_t)rpc.args[3]; *error = (error_t)rpc.args[4]; rpc_dmsg("\n[INFO] %s : completed at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); } ///////////////////////////////////////////////// void rpc_thread_kernel_create_server( xptr_t xp ) { thread_t * thread_ptr; // local pointer on thread descriptor xptr_t thread_xp; // extended pointer on thread descriptor lid_t core_lid; // core local index error_t error; rpc_dmsg("\n[INFO] %s : enter at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); // get client cluster identifier and pointer on RPC descriptor cxy_t client_cxy = (cxy_t)GET_CXY( xp ); rpc_desc_t * desc = (rpc_desc_t *)GET_PTR( xp ); // get attributes from RPC descriptor uint32_t type = (uint32_t) hal_remote_lwd( XPTR( client_cxy , &desc->args[0] ) ); void * func = (void*)(intptr_t)hal_remote_lwd( XPTR( client_cxy , &desc->args[1] ) ); void * args = (void*)(intptr_t)hal_remote_lwd( XPTR( client_cxy , &desc->args[2] ) ); // select one core core_lid = cluster_select_local_core(); // call local kernel function error = thread_kernel_create( &thread_ptr , type , func , args , core_lid ); // set output arguments thread_xp = XPTR( local_cxy , thread_ptr ); hal_remote_swd( XPTR( client_cxy , &desc->args[1] ) , (uint64_t)error ); hal_remote_swd( XPTR( client_cxy , &desc->args[2] ) , (uint64_t)thread_xp ); rpc_dmsg("\n[INFO] %s : completed at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); } ///////////////////////////////////////////////////////////////////////////////////////// // [6] Marshaling functions attached to RPC_SIGNAL_RISE ///////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////// void rpc_signal_rise_client( cxy_t cxy, process_t * process, // in uint32_t sig_id ) // in { rpc_dmsg("\n[INFO] %s : enter at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); assert( (cxy != local_cxy) , __FUNCTION__ , "target cluster is not remote\n"); // initialise RPC descriptor header rpc_desc_t rpc; rpc.index = RPC_SIGNAL_RISE; rpc.response = 1; // set input arguments in RPC descriptor rpc.args[0] = (uint64_t)(intptr_t)process; rpc.args[1] = (uint64_t)sig_id; // register RPC request in remote RPC fifo rpc_send_sync( cxy , &rpc ); rpc_dmsg("\n[INFO] %s : completed at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); } //////////////////////////////////////// void rpc_signal_rise_server( xptr_t xp ) { process_t * process; // local pointer on process descriptor uint32_t sig_id; // signal index rpc_dmsg("\n[INFO] %s : enter at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); // get client cluster identifier and pointer on RPC descriptor cxy_t client_cxy = (cxy_t)GET_CXY( xp ); rpc_desc_t * desc = (rpc_desc_t *)GET_PTR( xp ); // get attributes from RPC descriptor process = (process_t *)(intptr_t)hal_remote_lwd( XPTR( client_cxy , &desc->args[0] ) ); sig_id = (uint32_t) hal_remote_lwd( XPTR( client_cxy , &desc->args[1] ) ); // call local kernel function signal_rise( process , sig_id ); rpc_dmsg("\n[INFO] %s : completed at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); } ///////////////////////////////////////////////////////////////////////////////////////// // [10] Marshaling functions attached to RPC_VFS_INODE_CREATE ///////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////// void rpc_vfs_inode_create_client( cxy_t cxy, xptr_t dentry_xp, // in uint32_t fs_type, // in uint32_t inode_type, // in void * extend, // in uint32_t attr, // in uint32_t rights, // in uint32_t uid, // in uint32_t gid, // in xptr_t * inode_xp, // out error_t * error ) // out { rpc_dmsg("\n[INFO] %s : enter at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); assert( (cxy != local_cxy) , __FUNCTION__ , "target cluster is not remote\n"); // initialise RPC descriptor header rpc_desc_t rpc; rpc.index = RPC_VFS_INODE_CREATE; rpc.response = 1; // set input arguments in RPC descriptor rpc.args[0] = (uint64_t)dentry_xp; rpc.args[1] = (uint64_t)fs_type; rpc.args[2] = (uint64_t)inode_type; rpc.args[3] = (uint64_t)(intptr_t)extend; rpc.args[4] = (uint64_t)attr; rpc.args[5] = (uint64_t)rights; rpc.args[6] = (uint64_t)uid; rpc.args[7] = (uint64_t)gid; // register RPC request in remote RPC fifo (blocking function) rpc_send_sync( cxy , &rpc ); // get output values from RPC descriptor *inode_xp = (xptr_t)rpc.args[8]; *error = (error_t)rpc.args[9]; rpc_dmsg("\n[INFO] %s : completed at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); } ///////////////////////////////////////////// void rpc_vfs_inode_create_server( xptr_t xp ) { xptr_t dentry_xp; uint32_t fs_type; uint32_t inode_type; void * extend; uint32_t attr; uint32_t rights; uint32_t uid; uint32_t gid; xptr_t inode_xp; error_t error; rpc_dmsg("\n[INFO] %s : enter at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); // get client cluster identifier and pointer on RPC descriptor cxy_t client_cxy = (cxy_t)GET_CXY( xp ); rpc_desc_t * desc = (rpc_desc_t *)GET_PTR( xp ); // get input arguments from client rpc descriptor dentry_xp = (xptr_t) hal_remote_lwd( XPTR( client_cxy , &desc->args[0] ) ); fs_type = (uint32_t) hal_remote_lwd( XPTR( client_cxy , &desc->args[1] ) ); inode_type = (uint32_t) hal_remote_lwd( XPTR( client_cxy , &desc->args[2] ) ); extend = (void *)(intptr_t)hal_remote_lwd( XPTR( client_cxy , &desc->args[3] ) ); attr = (uint32_t) hal_remote_lwd( XPTR( client_cxy , &desc->args[4] ) ); rights = (uint32_t) hal_remote_lwd( XPTR( client_cxy , &desc->args[5] ) ); uid = (uid_t) hal_remote_lwd( XPTR( client_cxy , &desc->args[6] ) ); gid = (gid_t) hal_remote_lwd( XPTR( client_cxy , &desc->args[7] ) ); // call local kernel function error = vfs_inode_create( dentry_xp, fs_type, inode_type, extend, attr, rights, uid, gid, &inode_xp ); // set output arguments hal_remote_swd( XPTR( client_cxy , &desc->args[8] ) , (uint64_t)inode_xp ); hal_remote_swd( XPTR( client_cxy , &desc->args[9] ) , (uint64_t)error ); rpc_dmsg("\n[INFO] %s : completed at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); } ///////////////////////////////////////////////////////////////////////////////////////// // [11] Marshaling functions attached to RPC_VFS_INODE_DESTROY ///////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////// void rpc_vfs_inode_destroy_client( cxy_t cxy, struct vfs_inode_s * inode ) { rpc_dmsg("\n[INFO] %s : enter at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); assert( (cxy != local_cxy) , __FUNCTION__ , "target cluster is not remote\n"); // initialise RPC descriptor header rpc_desc_t rpc; rpc.index = RPC_VFS_INODE_DESTROY; rpc.response = 1; // set input arguments in RPC descriptor rpc.args[0] = (uint64_t)(intptr_t)inode; // register RPC request in remote RPC fifo (blocking function) rpc_send_sync( cxy , &rpc ); rpc_dmsg("\n[INFO] %s : completed at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); } ////////////////////////////////////////////// void rpc_vfs_inode_destroy_server( xptr_t xp ) { vfs_inode_t * inode; rpc_dmsg("\n[INFO] %s : enter at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); // get client cluster identifier and pointer on RPC descriptor cxy_t client_cxy = (cxy_t)GET_CXY( xp ); rpc_desc_t * desc = (rpc_desc_t *)GET_PTR( xp ); // get arguments "inode" from client RPC descriptor inode = (vfs_inode_t *)(intptr_t)hal_remote_lwd( XPTR( client_cxy , &desc->args[0] ) ); // call local kernel function vfs_inode_destroy( inode ); rpc_dmsg("\n[INFO] %s : completed at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); } ///////////////////////////////////////////////////////////////////////////////////////// // [12] Marshaling functions attached to RPC_VFS_DENTRY_CREATE ///////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////// void rpc_vfs_dentry_create_client( cxy_t cxy, uint32_t type, // in char * name, // in struct vfs_inode_s * parent, // in xptr_t * dentry_xp, // out error_t * error ) // out { rpc_dmsg("\n[INFO] %s : enter at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); assert( (cxy != local_cxy) , __FUNCTION__ , "target cluster is not remote\n"); // initialise RPC descriptor header rpc_desc_t rpc; rpc.index = RPC_VFS_DENTRY_CREATE; rpc.response = 1; // set input arguments in RPC descriptor rpc.args[0] = (uint64_t)type; rpc.args[1] = (uint64_t)(intptr_t)name; rpc.args[2] = (uint64_t)(intptr_t)parent; // register RPC request in remote RPC fifo (blocking function) rpc_send_sync( cxy , &rpc ); // get output values from RPC descriptor *dentry_xp = (xptr_t)rpc.args[3]; *error = (error_t)rpc.args[4]; rpc_dmsg("\n[INFO] %s : completed at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); } ////////////////////////////////////////////// void rpc_vfs_dentry_create_server( xptr_t xp ) { uint32_t type; char * name; vfs_inode_t * parent; xptr_t dentry_xp; error_t error; char name_copy[CONFIG_VFS_MAX_NAME_LENGTH]; rpc_dmsg("\n[INFO] %s : enter at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); // get client cluster identifier and pointer on RPC descriptor cxy_t client_cxy = (cxy_t)GET_CXY( xp ); rpc_desc_t * desc = (rpc_desc_t *)GET_PTR( xp ); // get arguments "name", "type", and "parent" from client RPC descriptor type = (uint32_t) hal_remote_lwd( XPTR( client_cxy , &desc->args[0] ) ); name = (char *)(intptr_t) hal_remote_lwd( XPTR( client_cxy , &desc->args[1] ) ); parent = (vfs_inode_t *)(intptr_t)hal_remote_lwd( XPTR( client_cxy , &desc->args[2] ) ); // makes a local copy of name hal_remote_strcpy( XPTR( local_cxy , name_copy ), XPTR( client_cxy , name ) ); // call local kernel function error = vfs_dentry_create( type, name_copy, parent, &dentry_xp ); // set output arguments hal_remote_swd( XPTR( client_cxy , &desc->args[3] ) , (uint64_t)dentry_xp ); hal_remote_swd( XPTR( client_cxy , &desc->args[4] ) , (uint64_t)error ); rpc_dmsg("\n[INFO] %s : completed at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); } ///////////////////////////////////////////////////////////////////////////////////////// // [13] Marshaling functions attached to RPC_VFS_DENTRY_DESTROY ///////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////// void rpc_vfs_dentry_destroy_client( cxy_t cxy, vfs_dentry_t * dentry ) { rpc_dmsg("\n[INFO] %s : enter at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); assert( (cxy != local_cxy) , __FUNCTION__ , "target cluster is not remote\n"); // initialise RPC descriptor header rpc_desc_t rpc; rpc.index = RPC_VFS_DENTRY_DESTROY; rpc.response = 1; // set input arguments in RPC descriptor rpc.args[0] = (uint64_t)(intptr_t)dentry; // register RPC request in remote RPC fifo (blocking function) rpc_send_sync( cxy , &rpc ); rpc_dmsg("\n[INFO] %s : completed at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); } /////////////////////////////////////////////// void rpc_vfs_dentry_destroy_server( xptr_t xp ) { vfs_dentry_t * dentry; rpc_dmsg("\n[INFO] %s : enter at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); // get client cluster identifier and pointer on RPC descriptor cxy_t client_cxy = (cxy_t)GET_CXY( xp ); rpc_desc_t * desc = (rpc_desc_t *)GET_PTR( xp ); // get arguments "dentry" from client RPC descriptor dentry = (vfs_dentry_t *)(intptr_t)hal_remote_lwd( XPTR( client_cxy , &desc->args[0] ) ); // call local kernel function vfs_dentry_destroy( dentry ); rpc_dmsg("\n[INFO] %s : completed at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); } ///////////////////////////////////////////////////////////////////////////////////////// // [14] Marshaling functions attached to RPC_VFS_FILE_CREATE ///////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////// void rpc_vfs_file_create_client( cxy_t cxy, struct vfs_inode_s * inode, // in uint32_t file_attr, // in xptr_t * file_xp, // out error_t * error ) // out { rpc_dmsg("\n[INFO] %s : enter at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); assert( (cxy != local_cxy) , __FUNCTION__ , "target cluster is not remote\n"); // initialise RPC descriptor header rpc_desc_t rpc; rpc.index = RPC_VFS_FILE_CREATE; rpc.response = 1; // set input arguments in RPC descriptor rpc.args[0] = (uint64_t)(intptr_t)inode; rpc.args[1] = (uint64_t)file_attr; // register RPC request in remote RPC fifo (blocking function) rpc_send_sync( cxy , &rpc ); // get output values from RPC descriptor *file_xp = (xptr_t)rpc.args[2]; *error = (error_t)rpc.args[3]; rpc_dmsg("\n[INFO] %s : completed at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); } //////////////////////////////////////////// void rpc_vfs_file_create_server( xptr_t xp ) { uint32_t file_attr; vfs_inode_t * inode; xptr_t file_xp; error_t error; rpc_dmsg("\n[INFO] %s : enter at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); // get client cluster identifier and pointer on RPC descriptor cxy_t client_cxy = (cxy_t)GET_CXY( xp ); rpc_desc_t * desc = (rpc_desc_t *)GET_PTR( xp ); // get arguments "file_attr" and "inode" from client RPC descriptor inode = (vfs_inode_t *)(intptr_t)hal_remote_lwd( XPTR( client_cxy , &desc->args[0] ) ); file_attr = (uint32_t) hal_remote_lwd( XPTR( client_cxy , &desc->args[1] ) ); // call local kernel function error = vfs_file_create( inode, file_attr, &file_xp ); // set output arguments hal_remote_swd( XPTR( client_cxy , &desc->args[2] ) , (uint64_t)file_xp ); hal_remote_swd( XPTR( client_cxy , &desc->args[3] ) , (uint64_t)error ); rpc_dmsg("\n[INFO] %s : completed at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); } ///////////////////////////////////////////////////////////////////////////////////////// // [15] Marshaling functions attached to RPC_VFS_FILE_DESTROY ///////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////// void rpc_vfs_file_destroy_client( cxy_t cxy, vfs_file_t * file ) { rpc_dmsg("\n[INFO] %s : enter at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); assert( (cxy != local_cxy) , __FUNCTION__ , "target cluster is not remote\n"); // initialise RPC descriptor header rpc_desc_t rpc; rpc.index = RPC_VFS_FILE_DESTROY; rpc.response = 1; // set input arguments in RPC descriptor rpc.args[0] = (uint64_t)(intptr_t)file; // register RPC request in remote RPC fifo (blocking function) rpc_send_sync( cxy , &rpc ); rpc_dmsg("\n[INFO] %s : completed at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); } ///////////////////////////////////////////// void rpc_vfs_file_destroy_server( xptr_t xp ) { vfs_file_t * file; rpc_dmsg("\n[INFO] %s : enter at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); // get client cluster identifier and pointer on RPC descriptor cxy_t client_cxy = (cxy_t)GET_CXY( xp ); rpc_desc_t * desc = (rpc_desc_t *)GET_PTR( xp ); // get arguments "dentry" from client RPC descriptor file = (vfs_file_t *)(intptr_t)hal_remote_lwd( XPTR( client_cxy , &desc->args[0] ) ); // call local kernel function vfs_file_destroy( file ); rpc_dmsg("\n[INFO] %s : completed at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); } ///////////////////////////////////////////////////////////////////////////////////////// // [16] Marshaling functions attached to RPC_VFS_INODE_LOAD ///////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////// void rpc_vfs_inode_load_client( cxy_t cxy, vfs_inode_t * parent_inode, // in char * name, // in xptr_t child_inode_xp, // in error_t * error ) // out { rpc_dmsg("\n[INFO] %s : enter at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); assert( (cxy != local_cxy) , __FUNCTION__ , "target cluster is not remote\n"); // initialise RPC descriptor header rpc_desc_t rpc; rpc.index = RPC_VFS_INODE_LOAD; rpc.response = 1; // set input arguments in RPC descriptor rpc.args[0] = (uint64_t)(intptr_t)parent_inode; rpc.args[1] = (uint64_t)(intptr_t)name; rpc.args[2] = (uint64_t)child_inode_xp; // register RPC request in remote RPC fifo (blocking function) rpc_send_sync( cxy , &rpc ); // get output values from RPC descriptor *error = (error_t)rpc.args[3]; rpc_dmsg("\n[INFO] %s : completed at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); } /////////////////////////////////////////// void rpc_vfs_inode_load_server( xptr_t xp ) { error_t error; vfs_inode_t * parent; xptr_t child_xp; char * name; char name_copy[CONFIG_VFS_MAX_NAME_LENGTH]; rpc_dmsg("\n[INFO] %s : enter at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); // get client cluster identifier and pointer on RPC descriptor cxy_t client_cxy = (cxy_t)GET_CXY( xp ); rpc_desc_t * desc = (rpc_desc_t *)GET_PTR( xp ); // get arguments "parent", "name", and "child_xp" parent = (vfs_inode_t*)(intptr_t)hal_remote_lwd(XPTR(client_cxy , &desc->args[0])); name = (char*)(intptr_t) hal_remote_lwd(XPTR(client_cxy , &desc->args[1])); child_xp = (xptr_t) hal_remote_lwd(XPTR(client_cxy , &desc->args[2])); // get name local copy hal_remote_strcpy( XPTR( local_cxy , name_copy ) , XPTR( client_cxy , name ) ); // call the kernel function error = vfs_inode_load( parent , name_copy , child_xp ); // set output argument hal_remote_swd( XPTR( client_cxy , &desc->args[3] ) , (uint64_t)error ); rpc_dmsg("\n[INFO] %s : completed at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); } ///////////////////////////////////////////////////////////////////////////////////////// // [17] Marshaling functions attached to RPC_VFS_MAPPER_LOAD_ALL ///////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////// void rpc_vfs_mapper_load_all_client( cxy_t cxy, vfs_inode_t * inode, // in error_t * error ) // out { rpc_dmsg("\n[INFO] %s : enter at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); assert( (cxy != local_cxy) , __FUNCTION__ , "target cluster is not remote\n"); // initialise RPC descriptor header rpc_desc_t rpc; rpc.index = RPC_VFS_INODE_LOAD; rpc.response = 1; // set input arguments in RPC descriptor rpc.args[0] = (uint64_t)(intptr_t)inode; // register RPC request in remote RPC fifo (blocking function) rpc_send_sync( cxy , &rpc ); // get output values from RPC descriptor *error = (error_t)rpc.args[1]; rpc_dmsg("\n[INFO] %s : completed at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); } //////////////////////////////////////////////// void rpc_vfs_mapper_load_all_server( xptr_t xp ) { error_t error; vfs_inode_t * inode; rpc_dmsg("\n[INFO] %s : enter at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); // get client cluster identifier and pointer on RPC descriptor cxy_t client_cxy = (cxy_t)GET_CXY( xp ); rpc_desc_t * desc = (rpc_desc_t *)GET_PTR( xp ); // get arguments "parent", "name", and "child_xp" inode = (vfs_inode_t*)(intptr_t)hal_remote_lwd(XPTR(client_cxy , &desc->args[0])); // call the kernel function error = vfs_mapper_load_all( inode ); // set output argument hal_remote_swd( XPTR( client_cxy , &desc->args[3] ) , (uint64_t)error ); rpc_dmsg("\n[INFO] %s : completed at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); } ///////////////////////////////////////////////////////////////////////////////////////// // [18] Marshaling functions attached to RPC_FATFS_GET_CLUSTER ///////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////// void rpc_fatfs_get_cluster_client( cxy_t cxy, mapper_t * mapper, // in uint32_t first, // in uint32_t page, // in uint32_t * cluster, // out error_t * error ) // out { rpc_dmsg("\n[INFO] %s : enter at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); assert( (cxy != local_cxy) , __FUNCTION__ , "target cluster is not remote\n"); // initialise RPC descriptor header rpc_desc_t rpc; rpc.index = RPC_FATFS_GET_CLUSTER; rpc.response = 1; // set input arguments in RPC descriptor rpc.args[0] = (uint64_t)(intptr_t)mapper; rpc.args[1] = (uint64_t)first; rpc.args[2] = (uint64_t)page; // register RPC request in remote RPC fifo rpc_send_sync( cxy , &rpc ); // get output argument from rpc descriptor *cluster = (uint32_t)rpc.args[3]; *error = (error_t)rpc.args[4]; rpc_dmsg("\n[INFO] %s : completed at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); } ////////////////////////////////////////////// void rpc_fatfs_get_cluster_server( xptr_t xp ) { mapper_t * mapper; uint32_t first; uint32_t page; uint32_t cluster; error_t error; rpc_dmsg("\n[INFO] %s : enter at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); // get client cluster identifier and pointer on RPC descriptor cxy_t client_cxy = (cxy_t)GET_CXY( xp ); rpc_desc_t * desc = (rpc_desc_t *)GET_PTR( xp ); // get input arguments mapper = (mapper_t *)(intptr_t)hal_remote_lpt( XPTR( client_cxy , &desc->args[0] ) ); first = (uint32_t) hal_remote_lw ( XPTR( client_cxy , &desc->args[1] ) ); page = (uint32_t) hal_remote_lw ( XPTR( client_cxy , &desc->args[2] ) ); // call the kernel function error = fatfs_get_cluster( mapper , first , page , &cluster ); // set output argument hal_remote_swd( XPTR( client_cxy , &desc->args[3] ) , (uint64_t)cluster ); hal_remote_swd( XPTR( client_cxy , &desc->args[4] ) , (uint64_t)error ); rpc_dmsg("\n[INFO] %s : completed at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); } ///////////////////////////////////////////////////////////////////////////////////////// // [20] Marshaling functions attached to RPC_VMM_GET_REF_VSEG ///////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////// void rpc_vmm_get_ref_vseg_client( cxy_t cxy, process_t * process, // in intptr_t vaddr, // in xptr_t * vseg_xp ) // out { rpc_dmsg("\n[INFO] %s : enter at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); assert( (cxy != local_cxy) , __FUNCTION__ , "target cluster is not remote\n"); // initialise RPC descriptor header rpc_desc_t rpc; rpc.index = RPC_VMM_GET_REF_VSEG; rpc.response = 1; // set input arguments in RPC descriptor rpc.args[0] = (uint64_t)(intptr_t)process; rpc.args[1] = (uint64_t)vaddr; // register RPC request in remote RPC fifo (blocking function) rpc_send_sync( cxy , &rpc ); // get output argument from rpc descriptor *vseg_xp = rpc.args[2]; rpc_dmsg("\n[INFO] %s : completed at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); } ///////////////////////////////////////////// void rpc_vmm_get_ref_vseg_server( xptr_t xp ) { process_t * process; intptr_t vaddr; vseg_t * vseg_ptr; xptr_t vseg_xp; rpc_dmsg("\n[INFO] %s : enter at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); // get client cluster identifier and pointer on RPC descriptor cxy_t client_cxy = (cxy_t)GET_CXY( xp ); rpc_desc_t * desc = (rpc_desc_t *)GET_PTR( xp ); // get input argument from client RPC descriptor process = (process_t *)(intptr_t)hal_remote_lwd( XPTR( client_cxy , &desc->args[0] ) ); vaddr = (intptr_t)hal_remote_lwd( XPTR( client_cxy , &desc->args[1] ) ); // call local kernel function vseg_ptr = vmm_get_vseg( process , vaddr ); // set output argument to client RPC descriptor if( vseg_ptr == NULL ) vseg_xp = XPTR_NULL; else vseg_xp = XPTR( local_cxy , vseg_ptr ); hal_remote_swd( XPTR( client_cxy , &desc->args[2] ) , (uint64_t)vseg_xp ); rpc_dmsg("\n[INFO] %s : completed at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); } ///////////////////////////////////////////////////////////////////////////////////////// // [21] Marshaling functions attached to RPC_VMM_GET_PTE ///////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////// void rpc_vmm_get_pte_client( cxy_t cxy, process_t * process, // in vpn_t vpn, // in uint32_t * attr, // out ppn_t * ppn, // out error_t * error ) // out { rpc_dmsg("\n[INFO] %s : enter at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); assert( (cxy != local_cxy) , __FUNCTION__ , "target cluster is not remote\n"); // initialise RPC descriptor header rpc_desc_t rpc; rpc.index = RPC_VMM_GET_PTE; rpc.response = 1; // set input arguments in RPC descriptor rpc.args[0] = (uint64_t)(intptr_t)process; rpc.args[1] = (uint64_t)vpn; // register RPC request in remote RPC fifo (blocking function) rpc_send_sync( cxy , &rpc ); // get output argument from rpc descriptor *attr = (uint32_t)rpc.args[2]; *ppn = (ppn_t)rpc.args[3]; *error = (error_t)rpc.args[4]; rpc_dmsg("\n[INFO] %s : completed at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); } //////////////////////////////////////// void rpc_vmm_get_pte_server( xptr_t xp ) { process_t * process; vpn_t vpn; uint32_t attr; ppn_t ppn; error_t error; rpc_dmsg("\n[INFO] %s : enter at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); // get client cluster identifier and pointer on RPC descriptor cxy_t client_cxy = (cxy_t)GET_CXY( xp ); rpc_desc_t * desc = (rpc_desc_t *)GET_PTR( xp ); // get input argument "process" & "vpn" from client RPC descriptor process = (process_t *)(intptr_t)hal_remote_lwd( XPTR( client_cxy , &desc->args[0] ) ); vpn = (vpn_t) hal_remote_lwd( XPTR( client_cxy , &desc->args[1] ) ); // call local kernel function error = vmm_get_pte( process , vpn , &attr , &ppn ); // set output argument "attr" & "ppn" to client RPC descriptor hal_remote_swd( XPTR( client_cxy , &desc->args[2] ) , (uint64_t)attr ); hal_remote_swd( XPTR( client_cxy , &desc->args[3] ) , (uint64_t)ppn ); hal_remote_swd( XPTR( client_cxy , &desc->args[4] ) , (uint64_t)error ); rpc_dmsg("\n[INFO] %s : completed at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); } ///////////////////////////////////////////////////////////////////////////////////////// // [22] Marshaling functions attached to RPC_KCM_ALLOC ///////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////// void rpc_kcm_alloc_client( cxy_t cxy, uint32_t kmem_type, // in xptr_t * buf_xp ) // out { rpc_dmsg("\n[INFO] %s : enter at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); assert( (cxy != local_cxy) , __FUNCTION__ , "target cluster is not remote\n"); // initialise RPC descriptor header rpc_desc_t rpc; rpc.index = RPC_THREAD_USER_CREATE; rpc.response = 1; // set input arguments in RPC descriptor rpc.args[0] = (uint64_t)kmem_type; // register RPC request in remote RPC fifo rpc_send_sync( cxy , &rpc ); // get output arguments from RPC descriptor *buf_xp = (xptr_t)rpc.args[1]; rpc_dmsg("\n[INFO] %s : completed at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); } ////////////////////////////////////// void rpc_kcm_alloc_server( xptr_t xp ) { rpc_dmsg("\n[INFO] %s : enter at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); // get client cluster identifier and pointer on RPC descriptor cxy_t client_cxy = (cxy_t)GET_CXY( xp ); rpc_desc_t * desc = (rpc_desc_t *)GET_PTR( xp ); // get input argument "kmem_type" from client RPC descriptor uint32_t kmem_type = (uint32_t)hal_remote_lwd( XPTR( client_cxy , &desc->args[0] ) ); // allocates memory for kcm kmem_req_t req; req.type = kmem_type; req.flags = AF_ZERO; void * buf_ptr = kmem_alloc( &req ); // set output argument xptr_t buf_xp = XPTR( local_cxy , buf_ptr ); hal_remote_swd( XPTR( client_cxy , &desc->args[1] ) , (uint64_t)buf_xp ); rpc_dmsg("\n[INFO] %s : completed at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); } ///////////////////////////////////////////////////////////////////////////////////////// // [23] Marshaling functions attached to RPC_KCM_FREE ///////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////// void rpc_kcm_free_client( cxy_t cxy, void * buf, // in uint32_t kmem_type ) // in { rpc_dmsg("\n[INFO] %s : enter at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); assert( (cxy != local_cxy) , __FUNCTION__ , "target cluster is not remote\n"); // initialise RPC descriptor header rpc_desc_t rpc; rpc.index = RPC_THREAD_USER_CREATE; rpc.response = 1; // set input arguments in RPC descriptor rpc.args[0] = (uint64_t)(intptr_t)buf; rpc.args[1] = (uint64_t)kmem_type; // register RPC request in remote RPC fifo rpc_send_sync( cxy , &rpc ); rpc_dmsg("\n[INFO] %s : completed at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); } ///////////////////////////////////// void rpc_kcm_free_server( xptr_t xp ) { rpc_dmsg("\n[INFO] %s : enter at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); // get client cluster identifier and pointer on RPC descriptor cxy_t client_cxy = (cxy_t)GET_CXY( xp ); rpc_desc_t * desc = (rpc_desc_t *)GET_PTR( xp ); // get input arguments "buf" and "kmem_type" from client RPC descriptor void * buf = (void *)(intptr_t)hal_remote_lwd( XPTR( client_cxy , &desc->args[0] ) ); uint32_t kmem_type = (uint32_t)hal_remote_lwd( XPTR( client_cxy , &desc->args[1] ) ); // releases memory kmem_req_t req; req.type = kmem_type; req.ptr = buf; kmem_free( &req ); rpc_dmsg("\n[INFO] %s : completed at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); } ///////////////////////////////////////////////////////////////////////////////////////// // [24] Marshaling functions attached to RPC_MAPPER_MOVE_BUFFER ///////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////// void rpc_mapper_move_buffer_client( cxy_t cxy, mapper_t * mapper, // in bool_t to_buffer, // in bool_t is_user, // in uint32_t file_offset, // in uint64_t buffer, // in uint32_t size, // in error_t * error ) // out { rpc_dmsg("\n[INFO] %s : enter at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); assert( (cxy != local_cxy) , __FUNCTION__ , "target cluster is not remote\n"); // initialise RPC descriptor header rpc_desc_t rpc; rpc.index = RPC_MAPPER_MOVE_BUFFER; rpc.response = 1; // set input arguments in RPC descriptor rpc.args[0] = (uint64_t)(intptr_t)mapper; rpc.args[1] = (uint64_t)to_buffer; rpc.args[2] = (uint64_t)is_user; rpc.args[3] = (uint64_t)file_offset; rpc.args[4] = (uint64_t)buffer; rpc.args[5] = (uint64_t)size; // register RPC request in remote RPC fifo (blocking function) rpc_send_sync( cxy , &rpc ); // get output values from RPC descriptor *error = (error_t)rpc.args[6]; rpc_dmsg("\n[INFO] %s : completed at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); } /////////////////////////////////////////////// void rpc_mapper_move_buffer_server( xptr_t xp ) { mapper_t * mapper; bool_t to_buffer; bool_t is_user; uint32_t file_offset; void * user_buffer; xptr_t kern_buffer; uint32_t size; error_t error; rpc_dmsg("\n[INFO] %s : enter at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); // get client cluster identifier and pointer on RPC descriptor cxy_t client_cxy = (cxy_t)GET_CXY( xp ); rpc_desc_t * desc = (rpc_desc_t *)GET_PTR( xp ); // get arguments from client RPC descriptor mapper = (mapper_t *)(intptr_t)hal_remote_lwd( XPTR( client_cxy , &desc->args[0] ) ); to_buffer = hal_remote_lwd( XPTR( client_cxy , &desc->args[1] ) ); is_user = hal_remote_lwd( XPTR( client_cxy , &desc->args[2] ) ); file_offset = hal_remote_lwd( XPTR( client_cxy , &desc->args[3] ) ); size = hal_remote_lwd( XPTR( client_cxy , &desc->args[5] ) ); // call local kernel function if( is_user ) { user_buffer = (void *)(intptr_t)hal_remote_lwd( XPTR( client_cxy , &desc->args[4] ) ); error = mapper_move_user_buffer( mapper, to_buffer, file_offset, user_buffer, size ); } else { kern_buffer = (xptr_t)hal_remote_lwd( XPTR( client_cxy , &desc->args[4] ) ); error = mapper_move_user_buffer( mapper, to_buffer, file_offset, kern_buffer, size ); } // set output argument to client RPC descriptor hal_remote_swd( XPTR( client_cxy , &desc->args[6] ) , (uint64_t)error ); rpc_dmsg("\n[INFO] %s : completed at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); } ///////////////////////////////////////////////////////////////////////////////////////// // [25] Marshaling functions attached to RPC_MAPPER_GET_PAGE ///////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////// void rpc_mapper_get_page_client( cxy_t cxy, struct mapper_s * mapper, // in uint32_t index, // in page_t ** page ) // out { rpc_dmsg("\n[INFO] %s : enter at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); assert( (cxy != local_cxy) , __FUNCTION__ , "target cluster is not remote\n"); // initialise RPC descriptor header rpc_desc_t rpc; rpc.index = RPC_MAPPER_GET_PAGE; rpc.response = 1; // set input arguments in RPC descriptor rpc.args[0] = (uint64_t)(intptr_t)mapper; rpc.args[1] = (uint64_t)index; // register RPC request in remote RPC fifo (blocking function) rpc_send_sync( cxy , &rpc ); // get output values from RPC descriptor *page = (page_t *)(intptr_t)rpc.args[2]; rpc_dmsg("\n[INFO] %s : completed at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); } //////////////////////////////////////////// void rpc_mapper_get_page_server( xptr_t xp ) { rpc_dmsg("\n[INFO] %s : enter at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); // get client cluster identifier and pointer on RPC descriptor cxy_t cxy = (cxy_t)GET_CXY( xp ); rpc_desc_t * desc = (rpc_desc_t *)GET_PTR( xp ); // get input arguments from client RPC descriptor mapper_t * mapper = (mapper_t *)(intptr_t)hal_remote_lwd( XPTR( cxy , &desc->args[0] ) ); uint32_t index = (uint32_t) hal_remote_lwd( XPTR( cxy , &desc->args[1] ) ); // call local pmem allocator page_t * page = mapper_get_page( mapper , index ); // set output arguments into client RPC descriptor hal_remote_swd( XPTR( cxy , &desc->args[1] ) , (uint64_t)(intptr_t)page ); rpc_dmsg("\n[INFO] %s : completed at cycle %d\n", __FUNCTION__ , hal_time_stamp() ); } /***************************************************************************************/ /************ Generic functions supporting RPCs : client side **************************/ /***************************************************************************************/ //////////////////////////////////////////// void rpc_send_sync( cxy_t server_cxy, rpc_desc_t * rpc ) { uint32_t cores; error_t error; bool_t first; reg_t sr_save; thread_t * this = CURRENT_THREAD; rpc_dmsg("\n[INFO] %s : enter / client_cxy = %x / server_cxy = %x / cycle %d\n", __FUNCTION__ , local_cxy , server_cxy , hal_time_stamp() ); // allocate and initialise an extended pointer on the RPC descriptor xptr_t desc_xp = XPTR( local_cxy , rpc ); // get local pointer on rpc_fifo in remote cluster, with the // assumption that rpc_fifo pddresses are identical in all clusters rpc_fifo_t * rf = &LOCAL_CLUSTER->rpc_fifo; // try to post an item in remote fifo // deschedule and retry if remote fifo full do { error = remote_fifo_put_item( XPTR( server_cxy , &rf->fifo ), (uint64_t )desc_xp, &first ); if ( error ) { printk("\n[WARNING] %s : cluster %x cannot post RPC to cluster %x\n", __FUNCTION__ , local_cxy , server_cxy ); if( thread_can_yield() ) sched_yield( NULL ); } } while( error ); rpc_dmsg("\n[INFO] %s : RPC %l registered / server_cxy = %x / cycle %d\n", __FUNCTION__ , desc_xp , server_cxy , hal_time_stamp() ); // send IPI to remote CP0, if this is the first RPC in remote FIFO, // and there is no CPU is in kernel mode in server cluster. if( first ) { // get number of cores in kernel mode in server cluster cores = hal_remote_lw( XPTR( server_cxy , &LOCAL_CLUSTER->cores_in_kernel ) ); if( cores == 0 ) // no core in kernel mode in server { dev_pic_send_ipi( server_cxy , 0 ); rpc_dmsg("\n[INFO] %s : IPI sent / client_cxy = %x / server_cxy = %x\n", __FUNCTION__, local_cxy , server_cxy ); } } // enable IRQs to allow incoming RPC and avoid deadlock if( this->type == THREAD_RPC ) hal_enable_irq( &sr_save ); // the server thread poll the response slot until RPC completed // TODO this could be replaced by a descheduling policy... [AG] while( 1 ) { if( rpc->response == 0 ) break; } // restore IRQs if( this->type == THREAD_RPC ) hal_restore_irq( sr_save ); rpc_dmsg("\n[INFO] %s : completed / client_cxy = %x / server_cxy = %x / cycle %d\n", __FUNCTION__ , local_cxy , server_cxy , hal_time_stamp() ); } // end rpc_send_sync() /***************************************************************************************/ /************ Generic functions supporting RPCs : server side **************************/ /***************************************************************************************/ /////////////////////////////////////////// void rpc_fifo_init( rpc_fifo_t * rpc_fifo ) { rpc_fifo->count = 0; rpc_fifo->owner = 0; local_fifo_init( &rpc_fifo->fifo ); } ///////////////////////////////////////////// void rpc_execute_all( rpc_fifo_t * rpc_fifo ) { xptr_t xp; // extended pointer on RPC descriptor uint32_t count; // handled RPC request counter thread_t * this; // pointer on this RPC thread core_t * core; // pointer on core running this thread rpc_desc_t * desc; // pointer on RPC descriptor uint32_t index; // RPC index cxy_t client_cxy; // client cluster identifier error_t error; this = CURRENT_THREAD; core = this->core; count = 0; rpc_dmsg("\n[INFO] %s : enter / thread %x on core[%x,%d] / fifo = %x / cycle %d\n", __FUNCTION__, this->trdid, local_cxy, core->lid , hal_time_stamp() ); // handle up to CONFIG_RPC_PENDING_MAX requests before exit do { error = local_fifo_get_item( &rpc_fifo->fifo, (uint64_t *)&xp ); if ( error == 0 ) // One RPC request successfully extracted from RPC_FIFO { // get client cluster identifier and pointer on RPC descriptor client_cxy = (cxy_t)GET_CXY( xp ); desc = (rpc_desc_t *)GET_PTR( xp ); // get rpc index from RPC descriptor index = hal_remote_lw( XPTR( client_cxy , &desc->index ) ); rpc_dmsg("\n[INFO] %s : thread %x on core [%x,%d] / index = %d / &rpc = %x\n", __FUNCTION__ , this->trdid , core->lid , local_cxy , index , rpc_server[index] ); // call the relevant server function rpc_server[index]( xp ); // increment handled RPC counter count++; // notify RPC completion as required hal_remote_atomic_add( XPTR(client_cxy,&desc->response) , -1 ); } // exit loop in three cases: // - fifo is empty // - look has been released (because descheduling) // - max number of RPCs has been reached if( error || (rpc_fifo->owner != this->trdid) || (count > CONFIG_RPC_PENDING_MAX) ) break; } while( 1 ); // update RPC_FIFO global counter rpc_fifo->count += count; } // end rpc_execute_all() //////////////////////////////////////////////////// error_t rpc_activate_thread( rpc_fifo_t * rpc_fifo ) { core_t * core; thread_t * thread; thread_t * this; scheduler_t * sched; error_t error; bool_t found; reg_t sr_save; this = CURRENT_THREAD; core = this->core; sched = &core->scheduler; found = false; assert( (this->trdid == rpc_fifo->owner) , __FUNCTION__ , "calling thread is not RPC_FIFO owner\n" ); // makes the calling thread not preemptable // during activation / creation of the RPC thread hal_disable_irq( &sr_save ); // search a free RPC thread (must be in THREAD_BLOCKED_IDLE state) list_entry_t * iter; LIST_FOREACH( &sched->k_root , iter ) { thread = LIST_ELEMENT( iter , thread_t , sched_list ); if( (thread->type == THREAD_RPC) && (thread->blocked == THREAD_BLOCKED_IDLE ) ) { found = true; break; } } if( found ) // activate this idle RPC thread { // unblock it thread->blocked = 0; rpc_dmsg("\n[INFO] %s : activate RPC thread %x on core [%x,%d] / cycle %d\n", __FUNCTION__ , thread , core->gid , local_cxy , hal_time_stamp() ); } else // create a new RPC thread { // create new thread error = thread_kernel_create( &thread, THREAD_RPC, &rpc_thread_func, NULL, core->lid ); if( error ) { hal_restore_irq( sr_save ); printk("\n[ERROR] in %s : no memory for new RPC thread in cluster %x\n", __FUNCTION__ , local_cxy ); return ENOMEM; } // unblock new thread thread->blocked = 0; // update core descriptor counter hal_atomic_add( &LOCAL_CLUSTER->rpc_threads , 1 ); rpc_dmsg("\n[INFO] %s : create RPC thread %x on core [%x,%d] / cycle %d\n", __FUNCTION__ , thread->trdid, local_cxy, core->lid, hal_time_stamp() ); } // update owner in rpc_fifo rpc_fifo->owner = thread->trdid; // current thread switch to RPC thread sched_yield( thread ); // restore IRQs for the calling thread hal_restore_irq( sr_save ); // return success return 0; } // end rpc_activate_thread() ////////////////// bool_t rpc_check() { thread_t * this = CURRENT_THREAD; rpc_fifo_t * rpc_fifo = &LOCAL_CLUSTER->rpc_fifo; error_t error; rpc_dmsg("\n[INFO] %s : enter in cluster %x\n", __FUNCTION__ , local_cxy ); // calling thread does nothing if light lock already taken or FIFO empty if( (rpc_fifo->owner != 0) || (local_fifo_is_empty( &rpc_fifo->fifo )) ) { rpc_dmsg("\n[INFO] %s : exit but do nothing in cluster %x\n", __FUNCTION__ , local_cxy ); return false; } // try to take the light lock, and activates an RPC thread if success if( hal_atomic_test_set( &rpc_fifo->owner , this->trdid ) ) { error = rpc_activate_thread( rpc_fifo ); if( error ) // cannot activate an RPC_THREAD { rpc_fifo->owner = 0; printk("\n[ERROR] in %s : no memory to create a RPC thread for core %d" " in cluster %x => do nothing\n", __FUNCTION__ , CURRENT_CORE->lid , local_cxy ); } rpc_dmsg("\n[INFO] %s : exit after activating an RPC thread in cluster %x\n", __FUNCTION__ , local_cxy ); return true; } else // light lock taken by another thread { rpc_dmsg("\n[INFO] %s : exit but do nothing in cluster %x\n", __FUNCTION__ , local_cxy ); return false; } } // end rpc_check() ////////////////////// void rpc_thread_func() { // makes the RPC thread not preemptable hal_disable_irq( NULL ); thread_t * this = CURRENT_THREAD; rpc_fifo_t * rpc_fifo = &LOCAL_CLUSTER->rpc_fifo; rpc_dmsg("\n[INFO] %s : enter / thread %x on core[%x,%d] / cycle %d\n", __FUNCTION__, this->trdid, local_cxy, this->core->lid, hal_time_stamp() ); // this infinite loop is not preemptable // the RPC thread deschedule only when the RPC_FIFO is empty while(1) { // check fifo ownership (ownership should be given by rpc_activate() if( this->trdid != rpc_fifo->owner ) { printk("\n[PANIC] in %s : thread %x on core[%x,%d] not owner of RPC_FIFO\n", __FUNCTION__, this->trdid, local_cxy, this->core->lid ); hal_core_sleep(); } // executes pending RPC(s) rpc_execute_all( rpc_fifo ); // release rpc_fifo ownership (can be lost during RPC execution) if( rpc_fifo->owner == this->trdid ) rpc_fifo->owner = 0; // block and deschedule or sucide if( LOCAL_CLUSTER->rpc_threads >= CONFIG_RPC_THREADS_MAX ) { rpc_dmsg("\n[INFO] thread %x on core[%x,%d] suicide / cycle %d\n", __FUNCTION__, this->trdid, local_cxy, this->core->lid, hal_time_stamp() ); // update core descriptor counter hal_atomic_add( &LOCAL_CLUSTER->rpc_threads , -1 ); // suicide thread_exit(); } else { rpc_dmsg("\n[INFO] %s : thread %x on core[%x,%d] blocks / cycle %d\n", __FUNCTION__, this->trdid, local_cxy, this->core->lid, hal_time_stamp() ); thread_block( this , THREAD_BLOCKED_IDLE ); sched_yield( NULL ); rpc_dmsg("\n[INFO] RPC thread %x wake up on core[%x,%d] / cycle %d\n", __FUNCTION__, this->trdid, local_cxy, this->core->lid, hal_time_stamp() ); } } // end while } // end rpc_thread_func()