/* * 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 /////////////////////////////////////////// error_t remote_buf_create( xptr_t buf_xp, uint32_t size ) { kmem_req_t req; uint8_t * data; remote_buf_t * buf_ptr = GET_PTR( buf_xp ); cxy_t buf_cxy = GET_CXY( buf_xp ); // allocate the data buffer if( size >= CONFIG_PPM_PAGE_SIZE ) { req.type = KMEM_PPM; req.order = bits_log2( size >> CONFIG_PPM_PAGE_SHIFT ); req.flags = AF_NONE; data = kmem_remote_alloc( buf_cxy , &req ); } else { req.type = KMEM_KCM; req.order = bits_log2( size ); req.flags = AF_NONE; data = kmem_remote_alloc( buf_cxy , &req ); } if( data == NULL ) return -1; // initialize buffer descriptor hal_remote_s32( XPTR( buf_cxy , &buf_ptr->size ) , size ); hal_remote_s32( XPTR( buf_cxy , &buf_ptr->ptw ) , 0 ); hal_remote_s32( XPTR( buf_cxy , &buf_ptr->ptr ) , 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_create() ///////////////////////////////////////// void remote_buf_destroy( xptr_t buf_xp ) { kmem_req_t req; remote_buf_t * buf_ptr = GET_PTR( buf_xp ); cxy_t buf_cxy = GET_CXY( buf_xp ); // release memory allocated to data buffer if( buf_ptr->size >= CONFIG_PPM_PAGE_SIZE ) { req.type = KMEM_PPM; req.ptr = hal_remote_lpt( XPTR( buf_cxy , &buf_ptr->data ) ); kmem_remote_free( buf_cxy , &req ); } else { req.type = KMEM_KCM; req.ptr = hal_remote_lpt( XPTR( buf_cxy , &buf_ptr->data ) ); kmem_remote_free( buf_cxy , &req ); } } ///////////////////////////////////////// void remote_buf_reset( xptr_t buf_xp ) { 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->ptw ) , 0 ); hal_remote_s32( XPTR( buf_cxy , &buf_ptr->ptr ) , 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 ) { 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 ptr_xp = XPTR( buf_cxy , &buf_ptr->ptr ); xptr_t size_xp = XPTR( buf_cxy , &buf_ptr->size ); 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 ptr = hal_remote_l32( ptr_xp ); uint32_t size = hal_remote_l32( size_xp ); uint8_t * data = hal_remote_lpt( data_xp ); // check enough bytes in buffer if( nbytes > sts ) return -1; // move nbytes if( (ptr + nbytes) <= size) // no wrap around => one move { hal_copy_to_uspace( u_buf, XPTR( buf_cxy , data + ptr ), nbytes ); } else // wrap around => two moves { uint32_t bytes_1 = size - ptr; uint32_t bytes_2 = nbytes - bytes_1; hal_copy_to_uspace( u_buf, XPTR( buf_cxy , data + ptr ), bytes_1 ); hal_copy_to_uspace( u_buf + bytes_1, XPTR( buf_cxy , data ), bytes_2 ); } // update ptr in buffer descriptor hal_remote_s32( ptr_xp , (ptr + nbytes) % size ); // 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 ) { 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 ptr_xp = XPTR( buf_cxy , &buf_ptr->ptr ); xptr_t size_xp = XPTR( buf_cxy , &buf_ptr->size ); 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 ptr = hal_remote_l32( ptr_xp ); uint32_t size = hal_remote_l32( size_xp ); uint8_t * data = hal_remote_lpt( data_xp ); // check enough bytes in buffer if( nbytes > sts ) return -1; // move nbytes if( (ptr + nbytes) <= size) // no wrap around => one move { hal_remote_memcpy( XPTR( local_cxy , k_buf ), XPTR( buf_cxy , data + ptr ), nbytes ); } else // wrap around => two moves { uint32_t bytes_1 = size - ptr; uint32_t bytes_2 = nbytes - bytes_1; hal_remote_memcpy( XPTR( local_cxy , k_buf ), XPTR( buf_cxy , data + ptr ), bytes_1 ); hal_remote_memcpy( XPTR( local_cxy , k_buf + bytes_1 ), XPTR( buf_cxy , data ), bytes_2 ); } // update ptr in buffer descriptor hal_remote_s32( ptr_xp , (ptr + nbytes) % size ); // atomically update sts hal_remote_atomic_add( sts_xp , -nbytes ); return 0; } // end remote_buf_get_to_user() /////////////////////////////////////////////////// error_t remote_buf_put_from_user( xptr_t buf_xp, uint8_t * u_buf, uint32_t nbytes ) { 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 ptw_xp = XPTR( buf_cxy , &buf_ptr->ptw ); xptr_t size_xp = XPTR( buf_cxy , &buf_ptr->size ); 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 ptw = hal_remote_l32( ptw_xp ); uint32_t size = hal_remote_l32( size_xp ); uint8_t * data = hal_remote_lpt( data_xp ); // check enough space in buffer if( nbytes > (size - sts) ) return -1; // move nbytes if( (ptw + nbytes) <= size) // no wrap around => one move { hal_copy_from_uspace( XPTR( buf_cxy , data + ptw ), u_buf, nbytes ); } else // wrap around => two moves { uint32_t bytes_1 = size - ptw; uint32_t bytes_2 = nbytes - bytes_1; hal_copy_from_uspace( XPTR( buf_cxy , data + ptw ), u_buf, bytes_1 ); hal_copy_from_uspace( XPTR( buf_cxy , data ), u_buf + bytes_1, bytes_2 ); } // update ptw in buffer descriptor hal_remote_s32( ptw_xp , (ptw + nbytes) % size ); // 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 ) { 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 ptw_xp = XPTR( buf_cxy , &buf_ptr->ptw ); xptr_t size_xp = XPTR( buf_cxy , &buf_ptr->size ); 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 ptw = hal_remote_l32( ptw_xp ); uint32_t size = hal_remote_l32( size_xp ); uint8_t * data = hal_remote_lpt( data_xp ); // check enough space in buffer if( nbytes > (size - sts) ) return -1; // move nbytes if( (ptw + nbytes) <= size) // no wrap around => one move { hal_remote_memcpy( XPTR( buf_cxy , data + ptw ), XPTR( local_cxy , k_buf ), nbytes ); } else // wrap around => two moves { uint32_t bytes_1 = size - ptw; uint32_t bytes_2 = nbytes - bytes_1; hal_remote_memcpy( XPTR( buf_cxy , data + ptw ), XPTR( local_cxy , k_buf ), bytes_1 ); hal_remote_memcpy( XPTR( buf_cxy , data ), XPTR( local_cxy , k_buf + bytes_1 ), bytes_2 ); } // update ptw in buffer descriptor hal_remote_s32( ptw_xp , (ptw + nbytes) % size ); // 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()