/* * hal_uspace.c - implementation of Generic User Space Access API for MIPS32 * * Author Mohamed Karaoui (2015) * Alain Greiner (2016) * * 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 /////////////////////////////////////////// void hal_copy_from_uspace( void * k_dst, void * u_src, uint32_t size ) { uint32_t save_sr; uint32_t i; uint32_t wsize; // number of words uint32_t src = (uint32_t)u_src; uint32_t dst = (uint32_t)k_dst; if( (dst & 0x3) || (src & 0x3) ) wsize = 0; // do it all in bytes else wsize = size >> 2; hal_disable_irq( &save_sr ); for( i = 0 ; i < wsize ; i++ ) // transfer one word per iteration { asm volatile( "mfc2 $15, $1 \n" /* save MMU_MODE */ "ori $14, $0, 0x7 \n" "mtc2 $14, $1 \n" /* MMU_MODE <= DTLB ON */ "lw $13, 0(%0) \n" /* read data from user space */ "mtc2 $15, $1 \n" /* restore MMU_MODE */ "sw $13, 0(%1) \n" /* store data to kernel space */ : : "r"( src ) , "r"( dst ) : "$13","$14","$15", "memory" ); src += 4; dst += 4; } for( i = wsize << 2 ; i < size ; i++ ) // transfer one byte per iteration { asm volatile( "mfc2 $15, $1 \n" /* save MMU_MODE */ "ori $14, $0, 0x7 \n" "mtc2 $14, $1 \n" /* MMU_MODE <= DTLB ON */ "lb $13, 0(%0) \n" /* read data from user space */ "mtc2 $15, $1 \n" /* restore MMU_MODE */ "sb $13, 0(%1) \n" /* store data to kernel space */ : : "r"( src ) , "r"( dst ) : "$13","$14","$15", "memory" ); src += 1; dst += 1; } hal_restore_irq( save_sr ); } // end hal_copy_from_uspace() /////////////////////////////////////////// void hal_copy_to_uspace( void * u_dst, void * k_src, uint32_t size ) { uint32_t save_sr; uint32_t i; uint32_t wsize; // number of words if aligned uint32_t src = (uint32_t)k_src; uint32_t dst = (uint32_t)u_dst; if( (dst & 0x3) || (src & 0x3) ) wsize = 0; // not aligned else wsize = size >> 2; hal_disable_irq( &save_sr ); for( i = 0 ; i < wsize ; i++ ) // transfer one word per iteration { asm volatile( "mfc2 $15, $1 \n" /* save MMU_MODE */ "lw $13, 0(%0) \n" /* read data from kernel space */ "ori $14, $0, 0x7 \n" "mtc2 $14, $1 \n" /* MMU_MODE <= DTLB ON */ "sw $13, 0(%1) \n" /* store data to user space */ "mtc2 $15, $1 \n" /* restore MMU_MODE */ : : "r"( src ) , "r"( dst ) : "$13","$14","$15", "memory" ); src += 4; dst += 4; } for( i = wsize << 2 ; i < size ; i++ ) // transfer one byte per iteration { asm volatile( "mfc2 $15, $1 \n" /* save MMU_MODE */ "lw $13, 0(%0) \n" /* read data from kernel space */ "ori $14, $0, 0x7 \n" "mtc2 $14, $1 \n" /* MMU_MODE <= DTLB ON */ "sb $13, 0(%1) \n" /* store data to user space */ "mtc2 $15, $1 \n" /* restore MMU_MODE */ : : "r"( src ) , "r"( dst ) : "$13","$14","$15", "memory" ); src += 1; dst += 1; } hal_restore_irq( save_sr ); } // end hal_copy_to_uspace() ////////////////////////////////////////// void hal_strcpy_from_uspace( char * k_dst, char * u_src ) { uint32_t save_sr; uint32_t src = (uint32_t)u_src; uint32_t dst = (uint32_t)k_dst; hal_disable_irq( &save_sr ); // loop on characters while non NUL asm volatile( "mfc2 $15, $1 \n" /* save current MMU_MODE */ "1: \n" /* loop entry */ "ori $14, $0, 0x7 \n" "mtc2 $14, $1 \n" /* MMU_MODE <= DTLB ON */ "lb $13, 0(%0) \n" /* read char from user space */ "mtc2 $15, $1 \n" /* restore MMU_MODE */ "sb $13, 0(%1) \n" /* store char to kernel space */ "addi %0, %0, 1 \n" /* increment SRC pointer */ "addi %1, %1, 1 \n" /* increment DST pointer */ "bne $13, $0, 1b \n" /* test NUL */ "nop \n" : : "r"( src ) , "r"( dst ) : "$13","$14","$15", "memory" ); hal_restore_irq( save_sr ); } // hal_strcpy_from_uspace() ////////////////////////////////////////// void hal_strcpy_to_uspace( char * u_dst, char * k_src ) { uint32_t save_sr; uint32_t src = (uint32_t)k_src; uint32_t dst = (uint32_t)u_dst; hal_disable_irq( &save_sr ); // loop on characters while non NUL asm volatile( "mfc2 $15, $1 \n" /* save current MMU_MODE */ "1: \n" /* loop entry */ "lb $13, 0(%0) \n" /* read char from kernel space */ "ori $14, $0, 0x7 \n" "mtc2 $14, $1 \n" /* MMU_MODE <= DTLB ON */ "sb $13, 0(%1) \n" /* store char to user space */ "mtc2 $15, $1 \n" /* restore MMU_MODE */ "addi %0, %0, 1 \n" /* increment SRC pointer */ "addi %1, %1, 1 \n" /* increment DST pointer */ "bne $13, $0, 1b \n" /* test NUL */ "nop \n" : : "r"( src ) , "r"( dst ) : "$13","$14","$15", "memory" ); hal_restore_irq( save_sr ); } // hal_strcpy_from_uspace() /////////////////////////////////////////////// uint32_t hal_strlen_from_uspace( char * u_str ) { uint32_t save_sr; uint32_t str = (uint32_t)u_str; uint32_t count = 0; hal_disable_irq( &save_sr ); asm volatile( "ori $15, %0, 0 \n" /* $15 <= count */ "ori $13, %1, 0 \n" /* $13 <= str */ "mfc2 $15, $1 \n" /* save MMU_MODE */ "ori $14, $0, 0x7 \n" /* $14 <= mode DTLB on */ "mtc2 $14, $1 \n" /* MMU_MODE <= DTLB ON */ "1: \n" "lb $13, 0(%0) \n" /* read char from kernel space */ "addi $13, $13, 1 \n" /* increment address */ "bne $13, $0, 1b \n" /* loop until NUL found */ "addi $15, $15, 1 \n" /* increment counter */ "mtc2 $14, $1 \n" /* restore MMU_MODE */ : "+r"(count) : "r"(str) : "$13","$14","$15" ); hal_restore_irq( save_sr ); return count; }