/* * remote_buf.c Remotely accessible, circular buffer 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 ///////////////////////////////////////////// remote_buf_t * remote_buf_alloc( cxy_t cxy ) { return kmem_remote_alloc( cxy, bits_log2(sizeof(remote_buf_t)), AF_ZERO ); } ///////////////////////////////////////// error_t remote_buf_init( xptr_t buf_xp, uint32_t order ) { assert( __FUNCTION__ , (buf_xp != XPTR_NULL) , "buf_xp cannot be NULL" ); assert( __FUNCTION__ , (order < 32) , "order cannot be larger than 31" ); uint8_t * data; remote_buf_t * buf_ptr = GET_PTR( buf_xp ); cxy_t buf_cxy = GET_CXY( buf_xp ); // allocate the data buffer data = kmem_remote_alloc( buf_cxy , order , AF_NONE ); if( data == NULL ) return -1; // initialize buffer descriptor hal_remote_s32( XPTR( buf_cxy , &buf_ptr->order ) , order ); hal_remote_s32( XPTR( buf_cxy , &buf_ptr->wid ) , 0 ); hal_remote_s32( XPTR( buf_cxy , &buf_ptr->rid ) , 0 ); hal_remote_s32( XPTR( buf_cxy , &buf_ptr->sts ) , 0 ); hal_remote_spt( XPTR( buf_cxy , &buf_ptr->data ) , data ); return 0; } // end remote_buf_init() ////////////////////////////////////////////// void remote_buf_release_data( xptr_t buf_xp ) { assert( __FUNCTION__ , (buf_xp != XPTR_NULL) , "buf_xp cannot be NULL" ); remote_buf_t * buf_ptr = GET_PTR( buf_xp ); cxy_t buf_cxy = GET_CXY( buf_xp ); // gets data buffer local pointer and order uint32_t order = hal_remote_l32( XPTR( buf_cxy , &buf_ptr->order )); char * data_ptr = hal_remote_lpt( XPTR( buf_cxy , &buf_ptr->data )); // release memory allocated for data buffer if required if( data_ptr != NULL ) kmem_remote_free( buf_cxy , data_ptr , order ); } // end remote_buf_release_data() ///////////////////////////////////////// void remote_buf_destroy( xptr_t buf_xp ) { assert( __FUNCTION__ , (buf_xp != XPTR_NULL) , "buf_xp cannot be NULL" ); remote_buf_t * buf_ptr = GET_PTR( buf_xp ); cxy_t buf_cxy = GET_CXY( buf_xp ); // release data buffer remote_buf_release_data( buf_xp ); // release remote_buf descriptor kmem_remote_free( buf_cxy , buf_ptr , bits_log2(sizeof(remote_buf_t)) ); } // end remote_buf_destroy() ///////////////////////////////////////// void remote_buf_reset( xptr_t buf_xp ) { assert( __FUNCTION__ , (buf_xp != XPTR_NULL) , "buf_xp cannot be NULL" ); remote_buf_t * buf_ptr = GET_PTR( buf_xp ); cxy_t buf_cxy = GET_CXY( buf_xp ); hal_remote_s32( XPTR( buf_cxy , &buf_ptr->wid ) , 0 ); hal_remote_s32( XPTR( buf_cxy , &buf_ptr->rid ) , 0 ); hal_remote_s32( XPTR( buf_cxy , &buf_ptr->sts ) , 0 ); } ///////////////////////////////////////////////// error_t remote_buf_get_to_user( xptr_t buf_xp, uint8_t * u_buf, uint32_t nbytes ) { assert( __FUNCTION__ , (buf_xp != XPTR_NULL) , "buf_xp cannot be NULL" ); remote_buf_t * buf_ptr = GET_PTR( buf_xp ); cxy_t buf_cxy = GET_CXY( buf_xp ); // build relevant extended pointers xptr_t sts_xp = XPTR( buf_cxy , &buf_ptr->sts ); xptr_t rid_xp = XPTR( buf_cxy , &buf_ptr->rid ); xptr_t order_xp = XPTR( buf_cxy , &buf_ptr->order ); xptr_t data_xp = XPTR( buf_cxy , &buf_ptr->data ); // get relevant infos from remote buffer descriptor uint32_t sts = hal_remote_l32( sts_xp ); uint32_t rid = hal_remote_l32( rid_xp ); uint32_t order = hal_remote_l32( order_xp ); uint8_t * data = hal_remote_lpt( data_xp ); uint32_t size = 1 << order; uint32_t mask = size - 1; // check enough bytes in buffer if( nbytes > sts ) return -1; // move nbytes if( (rid + nbytes) <= size) // no wrap around => one move { hal_copy_to_uspace( u_buf, XPTR( buf_cxy , data + rid ), nbytes ); } else // wrap around => two moves { uint32_t bytes_1 = size - rid; uint32_t bytes_2 = nbytes - bytes_1; hal_copy_to_uspace( u_buf, XPTR( buf_cxy , data + rid ), bytes_1 ); hal_copy_to_uspace( u_buf + bytes_1, XPTR( buf_cxy , data ), bytes_2 ); } // update rid in buffer descriptor hal_remote_s32( rid_xp , (rid + nbytes) & mask ); // atomically update sts hal_remote_atomic_add( sts_xp , -nbytes ); return 0; } // end remote_buf_get_to_user() /////////////////////////////////////////////////// error_t remote_buf_get_to_kernel( xptr_t buf_xp, uint8_t * k_buf, uint32_t nbytes ) { assert( __FUNCTION__ , (buf_xp != XPTR_NULL) , "buf_xp cannot be NULL" ); remote_buf_t * buf_ptr = GET_PTR( buf_xp ); cxy_t buf_cxy = GET_CXY( buf_xp ); // build relevant extended pointers xptr_t sts_xp = XPTR( buf_cxy , &buf_ptr->sts ); xptr_t rid_xp = XPTR( buf_cxy , &buf_ptr->rid ); xptr_t order_xp = XPTR( buf_cxy , &buf_ptr->order ); xptr_t data_xp = XPTR( buf_cxy , &buf_ptr->data ); // get relevant infos from remote buffer descriptor uint32_t sts = hal_remote_l32( sts_xp ); uint32_t rid = hal_remote_l32( rid_xp ); uint32_t order = hal_remote_l32( order_xp ); uint8_t * data = hal_remote_lpt( data_xp ); uint32_t size = 1 << order; uint32_t mask = size - 1; // check enough bytes in buffer if( nbytes > sts ) return -1; // move nbytes if( (rid + nbytes) <= size) // no wrap around => one move { hal_remote_memcpy( XPTR( local_cxy , k_buf ), XPTR( buf_cxy , data + rid ), nbytes ); } else // wrap around => two moves { uint32_t bytes_1 = size - rid; uint32_t bytes_2 = nbytes - bytes_1; hal_remote_memcpy( XPTR( local_cxy , k_buf ), XPTR( buf_cxy , data + rid ), bytes_1 ); hal_remote_memcpy( XPTR( local_cxy , k_buf + bytes_1 ), XPTR( buf_cxy , data ), bytes_2 ); } // update rid in buffer descriptor hal_remote_s32( rid_xp , (rid + nbytes) & mask ); // atomically update sts hal_remote_atomic_add( sts_xp , -nbytes ); return 0; } // end remote_buf_get_to_kernel() /////////////////////////////////////////////////// error_t remote_buf_put_from_user( xptr_t buf_xp, uint8_t * u_buf, uint32_t nbytes ) { assert( __FUNCTION__ , (buf_xp != XPTR_NULL) , "buf_xp cannot be NULL" ); remote_buf_t * buf_ptr = GET_PTR( buf_xp ); cxy_t buf_cxy = GET_CXY( buf_xp ); // build relevant extended pointers xptr_t sts_xp = XPTR( buf_cxy , &buf_ptr->sts ); xptr_t wid_xp = XPTR( buf_cxy , &buf_ptr->wid ); xptr_t order_xp = XPTR( buf_cxy , &buf_ptr->order ); xptr_t data_xp = XPTR( buf_cxy , &buf_ptr->data ); // get relevant infos from remote buffer descriptor uint32_t sts = hal_remote_l32( sts_xp ); uint32_t wid = hal_remote_l32( wid_xp ); uint32_t order = hal_remote_l32( order_xp ); uint8_t * data = hal_remote_lpt( data_xp ); uint32_t size = 1 << order; uint32_t mask = size - 1; // check enough space in buffer if( nbytes > (size - sts) ) return -1; // move nbytes if( (wid + nbytes) <= size) // no wrap around => one move { hal_copy_from_uspace( XPTR( buf_cxy , data + wid ), u_buf, nbytes ); } else // wrap around => two moves { uint32_t bytes_1 = size - wid; uint32_t bytes_2 = nbytes - bytes_1; hal_copy_from_uspace( XPTR( buf_cxy , data + wid ), u_buf, bytes_1 ); hal_copy_from_uspace( XPTR( buf_cxy , data ), u_buf + bytes_1, bytes_2 ); } // update wid in buffer descriptor hal_remote_s32( wid_xp , (wid + nbytes) & mask ); // atomically update sts hal_remote_atomic_add( sts_xp , nbytes ); return 0; } // end remote_buf_put_from_user() ///////////////////////////////////////////////////// error_t remote_buf_put_from_kernel( xptr_t buf_xp, uint8_t * k_buf, uint32_t nbytes ) { assert( __FUNCTION__ , (buf_xp != XPTR_NULL) , "buf_xp cannot be NULL" ); remote_buf_t * buf_ptr = GET_PTR( buf_xp ); cxy_t buf_cxy = GET_CXY( buf_xp ); // build relevant extended pointers xptr_t sts_xp = XPTR( buf_cxy , &buf_ptr->sts ); xptr_t wid_xp = XPTR( buf_cxy , &buf_ptr->wid ); xptr_t order_xp = XPTR( buf_cxy , &buf_ptr->order ); xptr_t data_xp = XPTR( buf_cxy , &buf_ptr->data ); // get relevant infos from remote buffer descriptor uint32_t sts = hal_remote_l32( sts_xp ); uint32_t wid = hal_remote_l32( wid_xp ); uint32_t order = hal_remote_l32( order_xp ); uint8_t * data = hal_remote_lpt( data_xp ); uint32_t size = 1 << order; uint32_t mask = size - 1; // check enough space in buffer if( nbytes > (size - sts) ) return -1; // move nbytes if( (wid + nbytes) <= size) // no wrap around => one move { hal_remote_memcpy( XPTR( buf_cxy , data + wid ), XPTR( local_cxy , k_buf ), nbytes ); } else // wrap around => two moves { uint32_t bytes_1 = size - wid; uint32_t bytes_2 = nbytes - bytes_1; hal_remote_memcpy( XPTR( buf_cxy , data + wid ), XPTR( local_cxy , k_buf ), bytes_1 ); hal_remote_memcpy( XPTR( buf_cxy , data ), XPTR( local_cxy , k_buf + bytes_1 ), bytes_2 ); } // update wid in buffer descriptor hal_remote_s32( wid_xp , (wid + nbytes) & mask ); // atomically update sts hal_remote_atomic_add( sts_xp , nbytes ); return 0; } // end remote_buf_put_from_kernel() //////////////////////////////////////////// uint32_t remote_buf_status( xptr_t buf_xp ) { remote_buf_t * buf_ptr = GET_PTR( buf_xp ); cxy_t buf_cxy = GET_CXY( buf_xp ); return hal_remote_l32( XPTR( buf_cxy , &buf_ptr->sts ) ); } // end remote_buf_status() /////////////////////////////////////////////// void remote_buf_display( const char * func_str, xptr_t buf_xp, uint32_t nbytes, uint32_t offset ) { if( nbytes > 256 ) { printk("\n[WARNING] in %s : no more than 256 bytes\n", __FUNCTION__ ); nbytes = 256; } uint8_t string[128]; // for header uint8_t local_data[256]; // local data buffer cxy_t cxy = GET_CXY( buf_xp ); remote_buf_t * ptr = GET_PTR( buf_xp ); uint32_t order = hal_remote_l32( XPTR( cxy , &ptr->order )); uint32_t rid = hal_remote_l32( XPTR( cxy , &ptr->rid )); uint32_t wid = hal_remote_l32( XPTR( cxy , &ptr->wid )); uint32_t sts = hal_remote_l32( XPTR( cxy , &ptr->sts )); uint8_t * data = hal_remote_lpt( XPTR( cxy , &ptr->data )); // make a local copy of data buffer hal_remote_memcpy( XPTR( local_cxy , local_data ), XPTR( cxy , data + offset ), nbytes ); // build header snprintk( (char*)string , 128 , "in %s remote buffer [%x,%x] : size %d / rid %d / wid %d / sts %d ", func_str , cxy , ptr , 1<