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

Last change on this file since 658 was 658, checked in by alain, 4 years ago

Improve the TSAR NIC driver.

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