source: trunk/hal/tsar_mips32/core/hal_uspace.c

Last change on this file was 686, checked in by alain, 3 years ago

cosmetic

File size: 18.0 KB
RevLine 
[1]1/*
2 * hal_uspace.c - implementation of Generic User Space Access API for MIPS32
3 *
[657]4 * Author        Alain Greiner   (2016,2017,2018,2019,2020)
[1]5 *
6 * Copyright (c) UPMC Sorbonne Universites
7 *
8 * This file is part of ALMOS-MKH..
9 *
10 * ALMOS-MKH. is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; version 2.0 of the License.
13 *
14 * ALMOS-MKH. is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with ALMOS-MKH.; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
[457]24#include <hal_kernel_types.h>
[1]25#include <hal_uspace.h>
[626]26#include <hal_special.h>
[1]27#include <hal_irqmask.h>
28
[425]29#include <printk.h>
30#include <thread.h>
31
[626]32///////////////////////////////////////////////////////////////////////////////////////
[658]33// Implementation note
[637]34// It works in a critical section, as it modifies two CP2 registers:
[626]35// It activates briefly the DATA_MMU by writing into the CP2_MODE register to access the
[654]36// user buffer, and modifies the CP2_DEXT register to access the kernel buffer.
[626]37// If the two buffers are aligned on a word boundary, it moves the data word per word
38// in a first loop, and moves byte per byte the remaining bytes in a second loop.
39// If the buffers are not aligned, it moves all data byte per byte.
40///////////////////////////////////////////////////////////////////////////////////////
[637]41void hal_copy_from_uspace( xptr_t     k_dst_xp,
42                           void     * u_src_ptr,
[425]43                           uint32_t   size ) 
[1]44{
45    uint32_t save_sr;
[637]46        uint32_t words;                            // number of words (if buffers aligned)
47    uint32_t src = (uint32_t)u_src_ptr;
48    uint32_t dst = (uint32_t)GET_PTR( k_dst_xp );
49    uint32_t cxy = (uint32_t)GET_CXY( k_dst_xp );
[626]50 
[686]51assert( __FUNCTION__, (CURRENT_THREAD->process->pid > 0), 
52"must be called by an user thread" );
[658]53
[610]54#if DEBUG_HAL_USPACE
[626]55thread_t * this  = CURRENT_THREAD;
56uint32_t   cycle = (uint32_t)hal_get_cycles();
57if( cycle > DEBUG_HAL_USPACE )
58printk("\n[%s] thread[%x,%x] enter / %d bytes / u_buf(%x,%x) -> k_buf(%x,%x) / cycle %d\n", 
[637]59__FUNCTION__, this->process->pid, this->trdid, size, local_cxy, src, cxy, dst, cycle );
[610]60#endif
61
[626]62        if( (dst & 0x3) || (src & 0x3) ) words = 0;          // do it all in bytes
63    else                             words = size >> 2;
[1]64
[626]65    // enter critical section
[1]66    hal_disable_irq( &save_sr );
67
[626]68    asm volatile( ".set noreorder             \n"
69 
70                  /* initialise registers                                         */
71                  "move   $8,    %0           \n"   /* $8 <= src                  */
72                  "move   $9,    %1           \n"   /* $9 <= dst                  */
73                  "move   $10,   %2           \n"   /* $10 <= words               */
74                  "move   $11,   %3           \n"   /* $11 <= size                */
75                  "mfc2   $12,   $1           \n"   /* $12 <= old MMU_MODE        */
76                  "ori    $13,   $12,   0x4       \n"   /* $13 <= MMU_MODE with DTLB  */
[407]77
[654]78                  /* save MMU_DEXT register                                       */
79                  "mfc2   $16,   $24          \n"   /* $16 <= old MMU_DEXT        */
80                  "mtc2   %4,    $24          \n"   /* MMU_DEXT <= dst_cxy        */
[1]81
[626]82                  /* transfer one word per iteration in first loop if aligned     */
83                  "move   $15,   $10          \n"   /* $15 <= words ($15 == i)    */
84                  "1:                         \n"
85                  "beq    $15,   $0,    2f    \n"   /* exit loop if (i==0)        */
86                  "nop                        \n"
87                  "mtc2   $13,   $1                       \n"   /* MMU_MODE <= DTLB ON        */
88                  "lw     $14,   0($8)        \n"   /* word from user space       */
89                  "mtc2   $12,   $1                       \n"   /* restore old MMU_MODE       */
90                      "sw     $14,   0($9)        \n"   /* word to kernel space       */
91                  "addi   $15,   $15,   -1    \n"   /* i--                        */
92                  "addi   $8,    $8,    4     \n"   /* src += 4 bytes             */
93                  "j             1b           \n"   
94                  "addi   $9,    $9,    4     \n"   /* dst += 4 bytes             */
[1]95
[626]96                  /* transfer one byte per iteration in this second loop          */
97                  "2:                         \n"
98                  "sll    $15,   $10,   2     \n"   /* $15 <= words*4 ($15 == i)  */
99                  "3:                         \n"
100                  "beq    $15,   $11,   4f    \n"   /* exit loop if (i == size)   */
101                  "nop                        \n"
102                  "mtc2   $13,   $1                       \n"   /* MMU_MODE <= DTLB ON        */
103                  "lb     $14,   0($8)        \n"   /* byte from user space       */
104                  "mtc2   $12,   $1                       \n"   /* restore omd MMU_MODE       */
105                      "sb     $14,   0($9)        \n"   /* byte to kernel space       */
106                  "addi   $15,   $15,   1     \n"   /* i++                        */
107                  "addi   $8,    $8,    1     \n"   /* src += 1 byte              */
108                  "j             3b           \n"   
109                  "addi   $9,    $9,    1     \n"   /* dst += 1 byte              */
[1]110
[654]111                  /* restore MMU_DEXT register                                    */
[626]112                  "4:                         \n"
[654]113                  "mtc2   $16,   $24          \n"   /* MMU_DEXT <= $16            */
[626]114                  ".set reorder               \n"
115                  : 
[637]116                  : "r"(src) , "r"(dst) , "r"(words) , "r"(size) , "r"(cxy)
[626]117                  : "$8","$9","$10","$11","$12","$13","$14","$15","$16","memory" );
[1]118
[626]119    // exit critical section
[1]120    hal_restore_irq( save_sr );
121
[610]122#if DEBUG_HAL_USPACE
[626]123cycle = (uint32_t)hal_get_cycles();
124if( cycle > DEBUG_HAL_USPACE )
125printk("\n[%s] thread[%x,%x] moved %d bytes / u_buf(%x,%x) -> k_buf(%x,%x) / cycle %d\n", 
[637]126__FUNCTION__, this->process->pid, this->trdid, size, local_cxy, src, cxy, dst, cycle );
[610]127#endif
128
[87]129}  // end hal_copy_from_uspace()
130
[626]131///////////////////////////////////////////////////////////////////////////////////////
[658]132// Implementation note
[637]133// It works in a critical section, as it modifies two CP2 registers:
[626]134// It activates briefly the DATA_MMU by writing into the CP2_MODE register to access the
[654]135// user buffer, and modifies the CP2_DEXT register to access the kernel buffer.
[626]136// If the two buffers are aligned on a word boundary, it moves the data word per word
137// in a first loop, and moves byte per byte the remaining bytes in a second loop.
[647]138// If the buffers are not word aligned, it moves all data byte per byte.
[626]139///////////////////////////////////////////////////////////////////////////////////////
[637]140void hal_copy_to_uspace( void     * u_dst_ptr,
141                         xptr_t     k_src_xp,
[1]142                         uint32_t   size )
143{
144    uint32_t save_sr;
[637]145        uint32_t words;                           // number of words (if buffers aligned)
146    uint32_t dst = (uint32_t)u_dst_ptr;
147    uint32_t src = (uint32_t)GET_PTR( k_src_xp );
148    uint32_t cxy = (uint32_t)GET_CXY( k_src_xp );
[1]149
[686]150assert( __FUNCTION__, (CURRENT_THREAD->process->pid > 0), 
151"must be called by an user thread" );
[658]152
[610]153#if DEBUG_HAL_USPACE
[626]154thread_t * this  = CURRENT_THREAD;
155uint32_t   cycle = (uint32_t)hal_get_cycles();
156if( cycle > DEBUG_HAL_USPACE )
157printk("\n[%s] thread[%x,%x] enter / %d bytes / k_buf(%x,%x) -> u_buf(%x,%x) / cycle %d\n", 
[637]158__FUNCTION__, this->process->pid, this->trdid, size, cxy, src, local_cxy, dst, cycle );
[610]159#endif
160
[626]161        if( (dst & 0x3) || (src & 0x3) ) words = 0;          // not aligned
162    else                             words = size >> 2;
[1]163
[626]164    // enter critical section
[1]165    hal_disable_irq( &save_sr );
166
[626]167    asm volatile( ".set noreorder             \n"
168 
169                  /* initialise registers                                         */
170                  "move   $8,    %0           \n"   /* $8 <= k_src                */
171                  "move   $9,    %1           \n"   /* $9 <= u_dst                */
172                  "move   $10,   %2           \n"   /* $10 <= words               */
173                  "move   $11,   %3           \n"   /* $11 <= size                */
174                  "mfc2   $12,   $1           \n"   /* $12 <= old MMU_MODE        */
175                  "ori    $13,   $12,   0x4       \n"   /* $13 <= MMU_MODE with DTLB  */
[1]176
[654]177                  /* save MMU_DEXT register                                       */
178                  "mfc2   $16,   $24          \n"   /* $16 <= old MMU_DEXT        */
179                  "mtc2   %4,    $24          \n"   /* MMU_DEXT <= cxy            */
[1]180
[626]181                  /* transfer one word per iteration in first loop if aligned     */
182                  "move   $15,   $10          \n"   /* $15 <= words ($15 == i)    */
183                  "1:                         \n"
184                  "beq    $15,   $0,    2f    \n"   /* exit loop if (i==0)        */
185                  "nop                        \n"
186                  "lw     $14,   0($8)        \n"   /* load from kernel space     */
187                  "mtc2   $13,   $1                       \n"   /* MMU_MODE <= DTLB ON        */
188                      "sw     $14,   0($9)        \n"   /* store to user space        */
189                  "mtc2   $12,   $1                       \n"   /* restore old MMU_MODE       */
190                  "addi   $15,   $15,   -1    \n"   /* i--                        */
191                  "addi   $8,    $8,    4     \n"   /* src += 4 bytes             */
192                  "j             1b           \n"   
193                  "addi   $9,    $9,    4     \n"   /* dst += 4 bytes             */
[1]194
[626]195                  /* transfer one byte per iteration in this second loop          */
196                  "2:                         \n"
197                  "sll    $15,   $10,   2     \n"   /* $15 <= words*4 ($15 == i)  */
198                  "3:                         \n"
199                  "beq    $15,   $11,   4f    \n"   /* exit loop if (i == size)   */
200                  "nop                        \n"
201                  "lb     $14,   0($8)        \n"   /* byte from kernel space     */
202                  "mtc2   $13,   $1                       \n"   /* MMU_MODE <= DTLB ON        */
203                      "sb     $14,   0($9)        \n"   /* byte to user space         */
204                  "mtc2   $12,   $1                       \n"   /* restore omd MMU_MODE       */
205                  "addi   $15,   $15,   1     \n"   /* i++                        */
206                  "addi   $8,    $8,    1     \n"   /* src += 1 byte              */
207                  "j             3b           \n"   
208                  "addi   $9,    $9,    1     \n"   /* dst += 1 byte              */
[1]209
[654]210                  /* restore MMU_DEXT register                                    */
[626]211                  "4:                         \n"
[654]212                  "mtc2   $16,   $24          \n"   /* MMU_DEXT <= $16            */
[626]213                  ".set reorder               \n"
214                  : 
[637]215                  : "r"(src) , "r"(dst) , "r"(words) , "r"(size) , "r"(cxy)
[626]216                  : "$8","$9","$10","$11","$12","$13","$14","$15","$16","memory" );
217
218    // exit critical section
[1]219    hal_restore_irq( save_sr );
220
[610]221#if DEBUG_HAL_USPACE
[626]222cycle = (uint32_t)hal_get_cycles();
223if( cycle > DEBUG_HAL_USPACE )
224printk("\n[%s] thread[%x,%x] moved %d bytes / k_buf(%x,%x) -> u_buf(%x,%x) / cycle %d\n", 
[637]225__FUNCTION__, this->process->pid, this->trdid, size, cxy, src, local_cxy, dst, cycle );
[610]226#endif
227
[87]228}  // end hal_copy_to_uspace()
229
[637]230/////////////////////////////////////////////////
231void hal_strcpy_from_uspace( xptr_t     k_dst_xp,
232                             char     * u_src_ptr,
[407]233                             uint32_t   size )
[87]234{
[407]235    uint32_t save_sr;
[637]236    uint32_t src = (uint32_t)u_src_ptr;
237    uint32_t dst = (uint32_t)GET_PTR( k_dst_xp );
238    uint32_t cxy = (uint32_t)GET_CXY( k_dst_xp );
[87]239
[686]240assert( __FUNCTION__, (CURRENT_THREAD->process->pid > 0), 
241"must be called by an user thread" );
[658]242
[87]243    hal_disable_irq( &save_sr );
244
[425]245    // loop on characters while ( (character != NUL) and (count < size ) )
[637]246
[87]247    asm volatile(
[407]248        ".set noreorder             \n"
[637]249
[654]250        /* save old MMU_DEXT and set cxy in it                              */
251        "mfc2   $16,   $24          \n"   /* $16 <= old MMU_DEXT            */
252        "mtc2   %3,    $24          \n"   /* MMU_DEXT <= cxy                */
[637]253
[407]254        "move   $11,   %0           \n"   /* $11 <= count == size           */
255        "move   $12,   %1           \n"   /* $12 <= u_src                   */
256        "move   $13,   %2           \n"   /* $13 <= k_dst                   */
[637]257        "mfc2   $15,   $1           \n"   /* $15 <= MMU_MODE                */
258        "ori    $14,   $15,  0x4    \n"   /* $14 <= MMU_MODE / DTLB ON      */
259
[407]260        "1:                         \n"
[87]261        "mtc2   $14,   $1                       \n"   /* MMU_MODE <= DTLB ON            */
[407]262        "lb     $10,   0($12)       \n"   /* read char from user space      */
[637]263        "mtc2   $15,   $1                       \n"   /* MMU_MODE <= DTLB OFF           */
[407]264            "sb     $10,   0($13)       \n"   /* store char to kernel space     */
[425]265        "beq    $10,   $0,   2f     \n"   /* exit if char = 0               */
[407]266        "addi   $11,   $11, -1      \n"   /* decrement count                */
267        "addi   $12,   $12,  1      \n"   /* increment u_src pointer        */
268        "beq    $11,   $0,   2f     \n"   /* exit if count == 0             */
269        "addi   $13,   $13,  1      \n"   /* increment k_src pointer        */
270        "j                   1b     \n"   /* jump to next iteration         */
271        "2:                         \n"
[87]272        "nop                        \n"
[637]273
[654]274        /* restore old MMU_DEXT register                                    */
275        "mtc2   $16,   $24          \n"   /* MMU_DEXT <= $16                */
[637]276
[407]277        ".set reorder               \n"
278        : 
[637]279        : "r"(size) , "r"(src) , "r"(dst) , "r"(cxy)
280        : "$10","$11","$12","$13","$14","$15","$16" );
[407]281       
282    hal_restore_irq( save_sr ); 
[87]283
284} // hal_strcpy_from_uspace()
285
[637]286////////////////////////////////////////////////
287void hal_strcpy_to_uspace( char     * u_dst_ptr,
288                           xptr_t     k_src_xp,
[407]289                           uint32_t   size )
[121]290{
[407]291    uint32_t save_sr;
[637]292    uint32_t dst = (uint32_t)u_dst_ptr;
293    uint32_t src = (uint32_t)GET_PTR( k_src_xp );
294    uint32_t cxy = (uint32_t)GET_CXY( k_src_xp );
[87]295
[686]296assert( __FUNCTION__, (CURRENT_THREAD->process->pid > 0), 
297"must be called by an user thread" );
[658]298
[87]299    hal_disable_irq( &save_sr );
300
[407]301    // loop on characters while ( (character != NUL) and (count < size) )
[637]302
[87]303    asm volatile(
[407]304        ".set noreorder             \n"
[637]305
[654]306        /* save old MMU_DEXT and set cxy in it                              */
307        "mfc2   $16,   $24          \n"   /* $16 <= old MMU_DEXT            */
308        "mtc2   %3,    $24          \n"   /* MMU_DEXT <= cxy                */
[637]309
[407]310        "move   $11,   %0           \n"   /* $11 <= count == size           */
311        "move   $12,   %1           \n"   /* $12 <= k_src                   */
312        "move   $13,   %2           \n"   /* $13 <= u_dst                   */
[637]313        "mfc2   $15,   $1           \n"   /* $15 <= MMU_MODE                */
314        "ori    $14,   $15,  0x4    \n"   /* $14 <= MMU_MODE modified       */
315
[407]316        "1:                         \n"
317        "lb     $10,   0($12)       \n"   /* read char from kernel space    */
[87]318        "mtc2   $14,   $1                       \n"   /* MMU_MODE <= DTLB ON            */
[407]319            "sb     $10,   0($13)       \n"   /* store char to user space       */
[637]320        "mtc2   $15,   $1                       \n"   /* MMU_MODE <= DTLB OFF           */
[425]321        "beq    $10,   $0,   2f     \n"   /* exit if char == 0              */
[407]322        "addi   $11,   $11, -1      \n"   /* decrement count                */
323        "addi   $12,   $12,  1      \n"   /* increment k_src pointer        */
[637]324        "beq    $11,   $0,   2f     \n"   /* exit if count == 0             */
[407]325        "addi   $13,   $13,  1      \n"   /* increment u_src pointer        */
326        "j                   1b     \n"   /* jump to next iteration         */
327        "2:                         \n"
[87]328        "nop                        \n"
[637]329
[654]330        /* restore old MMU_DEXT register                                    */
331        "mtc2   $16,   $24          \n"   /* MMU_DEXT <= $16                */
[637]332
[407]333        ".set reorder               \n"
334        :
[637]335        : "r"(size) , "r"(src) , "r"(dst) , "r"(cxy)
336        : "$10","$11","$12","$13","$14","$15","$16" );
[407]337       
338    hal_restore_irq( save_sr ); 
[87]339
[299]340} // hal_strcpy_to_uspace()
[87]341
[1]342///////////////////////////////////////////////
343uint32_t hal_strlen_from_uspace( char * u_str )
344{
345    uint32_t save_sr;
[407]346    uint32_t count = 0;
[425]347    uint32_t str   = (uint32_t)u_str;
[1]348
[686]349assert( __FUNCTION__, (CURRENT_THREAD->process->pid > 0), 
350"must be called by an user thread" );
[658]351
[1]352    hal_disable_irq( &save_sr ); 
353
354        asm volatile(
[407]355        ".set noreorder             \n"
[425]356        "move   $13,   %1           \n"   /* $13 <= str                     */
[625]357        "mfc2   $15,   $1           \n"   /* $15 <= MMU_MODE (DTLB off)     */
[425]358        "ori    $14,   $15,  0x4    \n"   /* $14 <= mode DTLB on            */
[686]359        "mtc2   $14,   $1                       \n"   /* set DTLB on                    */
[1]360        "1:                         \n"
[625]361        "lb         $12,   0($13)       \n"   /* $12 <= one byte from u_space   */
[686]362        "beq    $12,   $0,   2f     \n"   /* exit loop when NUL found       */
363        "addi   $13,   $13,  1      \n"   /* increment address              */
364        "j                   1b     \n"   /* jump to next iteration         */
365        "addi   %0,    %0,   1      \n"   /* increment count if not NUL     */
366        "2:                         \n"
[425]367        "mtc2   $15,   $1                       \n"   /* set DTLB off                   */
[407]368        ".set reorder               \n"
369        : "+r"(count) 
370        : "r"(str) 
371        : "$12","$13","$14","$15" );
[1]372
373    hal_restore_irq( save_sr );
374
375    return count;
376}
377
Note: See TracBrowser for help on using the repository browser.