source: trunk/kernel/fs/devfs.c @ 438

Last change on this file since 438 was 438, checked in by alain, 6 years ago

Fix a bug in scheduler related to RPC blocking.

File size: 15.8 KB
Line 
1/*
2 * devfs.c - DEVFS File system API implementation.
3 *
4 * Author   Mohamed Lamine Karaoui (2014,2015)
5 *          Alain Greiner (2016,2017)
6 *
7 * Copyright (c) Sorbonne Universites
8 *
9 * This file is part of ALMOS-MKH.
10 *
11 * ALMOS-MKH is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; version 2.0 of the License.
14 *
15 * ALMOS-MKH is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with ALMOS-MKH; if not, write to the Free Software Foundation,
22 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 */
24
25#include <hal_types.h>
26#include <hal_special.h>
27#include <hal_uspace.h>
28#include <printk.h>
29#include <chdev.h>
30#include <thread.h>
31#include <dev_txt.h>
32#include <cluster.h>
33#include <vfs.h>
34#include <kmem.h>
35#include <devfs.h>
36
37/////////////////////////////////////////////////////////////////////////////////////////
38//     Extern variables
39/////////////////////////////////////////////////////////////////////////////////////////
40
41extern vfs_ctx_t            fs_context[];   // allocated in kernel_init.c
42extern chdev_directory_t    chdev_dir;      // allocated in kernel_init.c
43
44#if (DEBUG_SYS_READ & 1)
45extern uint32_t  enter_devfs_read;
46extern uint32_t  exit_devfs_read;
47#endif
48
49#if (DEBUG_SYS_WRITE & 1)
50extern uint32_t  enter_devfs_write;
51extern uint32_t  exit_devfs_write;
52#endif
53
54///////////////////////////////
55devfs_ctx_t * devfs_ctx_alloc()
56{
57    kmem_req_t    req;
58
59        req.type    = KMEM_DEVFS_CTX;
60        req.size    = sizeof(devfs_ctx_t);
61    req.flags   = AF_KERNEL | AF_ZERO;
62
63        return (devfs_ctx_t *)kmem_alloc( &req );
64}
65
66/////////////////////////////////////////////
67void devfs_ctx_init( devfs_ctx_t * devfs_ctx,
68                     xptr_t        devfs_dev_inode_xp,
69                     xptr_t        devfs_external_inode_xp )
70{
71    devfs_ctx->dev_inode_xp      = devfs_dev_inode_xp;
72    devfs_ctx->external_inode_xp = devfs_external_inode_xp;
73
74    fs_context[FS_TYPE_DEVFS].extend = devfs_ctx;
75}
76
77/////////////////////////////////////////////////
78void devfs_ctx_destroy( devfs_ctx_t * devfs_ctx )
79{
80    kmem_req_t    req;
81
82    req.type = KMEM_DEVFS_CTX;
83    req.ptr  = devfs_ctx;
84    kmem_free( &req );
85}
86
87/////////////////////////////////////////////////
88void devfs_global_init( xptr_t   parent_inode_xp,
89                        xptr_t * devfs_dev_inode_xp,
90                        xptr_t * devfs_external_inode_xp )
91{
92    error_t  error;
93
94#if DEBUG_DEVFS_INIT
95uint32_t cycle = (uint32_t)hal_get_cycles();
96if( DEBUG_DEVFS_INIT < cycle )
97printk("\n[DBG] %s : thread %x enter at cycle %d\n",
98__FUNCTION__ , CURRENT_THREAD , cycle );
99#endif
100
101    // creates DEVFS "dev" inode in cluster IO
102    error = vfs_add_child_in_parent( LOCAL_CLUSTER->io_cxy,
103                                     INODE_TYPE_DIR,
104                                     FS_TYPE_DEVFS,
105                                     parent_inode_xp,
106                                     "dev",
107                                     NULL,
108                                     devfs_dev_inode_xp ); 
109
110    assert( (error == 0) , __FUNCTION__ , "cannot create <dev>\n" );
111
112#if( DEBUG_DEVFS_INIT & 1 )
113if( DEBUG_DEVFS_INIT < cycle )
114printk("\n[DBG] %s : created <dev> inode at cycle %d\n", __FUNCTION__, cycle );
115#endif
116
117    // create DEVFS "external" inode in cluster IO
118    error = vfs_add_child_in_parent( LOCAL_CLUSTER->io_cxy,
119                                     INODE_TYPE_DIR,
120                                     FS_TYPE_DEVFS,
121                                     *devfs_dev_inode_xp,
122                                     "external",
123                                     NULL,
124                                     devfs_external_inode_xp ); 
125
126    assert( (error == 0) , __FUNCTION__ , "cannot create <external>\n" );
127
128#if DEBUG_DEVFS_INIT
129cycle = (uint32_t)hal_get_cycles();
130if( DEBUG_DEVFS_INIT < cycle )
131printk("\n[DBG] %s : thread %x exit at cycle %d\n",
132__FUNCTION__ , CURRENT_THREAD , cycle );
133#endif
134
135} 
136
137///////////////////////////////////////////////////
138void devfs_local_init( xptr_t   devfs_dev_inode_xp,
139                       xptr_t   devfs_external_inode_xp,
140                       xptr_t * devfs_internal_inode_xp )
141{
142    char          node_name[16];
143    xptr_t        chdev_xp;
144    cxy_t         chdev_cxy;
145    chdev_t     * chdev_ptr;
146    xptr_t        inode_xp;
147    uint32_t      channel;
148
149#if DEBUG_DEVFS_INIT
150uint32_t cycle = (uint32_t)hal_get_cycles();
151if( DEBUG_DEVFS_INIT < cycle )
152printk("\n[DBG] %s : thread %x enter at cycle %d\n",
153__FUNCTION__ , CURRENT_THREAD , cycle );
154#endif
155
156    // create "internal" directory linked to "dev"
157    snprintf( node_name , 16 , "internal_%x" , local_cxy );
158    vfs_add_child_in_parent( local_cxy,
159                             INODE_TYPE_DIR,
160                             FS_TYPE_DEVFS,
161                             devfs_dev_inode_xp,
162                             node_name,
163                             NULL,
164                             devfs_internal_inode_xp );
165
166    // create MMC chdev inode
167    chdev_xp  = chdev_dir.mmc[local_cxy];
168    if( chdev_xp != XPTR_NULL)
169    {
170        chdev_ptr = (chdev_t *)GET_PTR( chdev_xp );
171        vfs_add_child_in_parent( local_cxy,
172                                 INODE_TYPE_DEV,
173                                 FS_TYPE_DEVFS,
174                                 *devfs_internal_inode_xp,
175                                 chdev_ptr->name,
176                                 GET_PTR( chdev_xp ),
177                                 &inode_xp );
178    }
179
180    // create DMA chdev inodes (one DMA channel per core)
181    for( channel = 0 ; channel < LOCAL_CLUSTER->cores_nr ; channel++ )
182    {
183        chdev_xp = chdev_dir.dma[channel];
184        if( chdev_xp != XPTR_NULL)
185        {
186            chdev_ptr = (chdev_t *)GET_PTR( chdev_xp );
187            vfs_add_child_in_parent( local_cxy,
188                                     INODE_TYPE_DEV,
189                                     FS_TYPE_DEVFS,
190                                     *devfs_internal_inode_xp,
191                                     chdev_ptr->name,
192                                     GET_PTR( chdev_xp ),
193                                     &inode_xp );
194        }
195    }
196
197    // create an IOB inode in cluster containing IOB chdev
198    chdev_xp = chdev_dir.iob;
199    if( chdev_xp != XPTR_NULL )
200    {
201        chdev_cxy = GET_CXY( chdev_xp );
202        chdev_ptr = (chdev_t *)GET_PTR( chdev_xp );
203        if( chdev_cxy == local_cxy )
204        {
205            vfs_add_child_in_parent( local_cxy,
206                                     INODE_TYPE_DEV,
207                                     FS_TYPE_DEVFS,
208                                     devfs_external_inode_xp,
209                                     chdev_ptr->name,
210                                     GET_PTR( chdev_xp ),
211                                     &inode_xp );
212        }
213    }
214       
215    // create a PIC inode in cluster containing PIC chdev
216    chdev_xp = chdev_dir.pic;
217    if( chdev_xp != XPTR_NULL )
218    {
219        chdev_cxy = GET_CXY( chdev_xp );
220        chdev_ptr = (chdev_t *)GET_PTR( chdev_xp );
221        if( chdev_cxy == local_cxy )
222        {
223            vfs_add_child_in_parent( local_cxy,
224                                     INODE_TYPE_DEV,
225                                     FS_TYPE_DEVFS,
226                                     devfs_external_inode_xp,
227                                     chdev_ptr->name,
228                                     GET_PTR( chdev_xp ),
229                                     &inode_xp );
230        }
231    }
232
233    // create a TXT_RX inode in each cluster containing a TXT_RX chdev
234    for( channel = 0 ; channel < CONFIG_MAX_TXT_CHANNELS ; channel++ )
235    {
236        chdev_xp = chdev_dir.txt_rx[channel];
237        if( chdev_xp != XPTR_NULL )
238        {
239            chdev_cxy = GET_CXY( chdev_xp );
240            chdev_ptr = (chdev_t *)GET_PTR( chdev_xp );
241            if( chdev_cxy == local_cxy )
242            {
243                vfs_add_child_in_parent( local_cxy,
244                                         INODE_TYPE_DEV,
245                                         FS_TYPE_DEVFS,
246                                         devfs_external_inode_xp,
247                                         chdev_ptr->name,
248                                         GET_PTR( chdev_xp ),
249                                         &inode_xp );
250            }
251        }
252    }
253
254    // create a TXT_TX inode in each cluster containing a TXT_TX chdev
255    for( channel = 0 ; channel < CONFIG_MAX_TXT_CHANNELS ; channel++ )
256    {
257        chdev_xp = chdev_dir.txt_tx[channel];
258        if( chdev_xp != XPTR_NULL )
259        {
260            chdev_cxy = GET_CXY( chdev_xp );
261            chdev_ptr = (chdev_t *)GET_PTR( chdev_xp );
262            if( chdev_cxy == local_cxy )
263            {
264                vfs_add_child_in_parent( local_cxy,
265                                         INODE_TYPE_DEV,
266                                         FS_TYPE_DEVFS,
267                                         devfs_external_inode_xp,
268                                         chdev_ptr->name,
269                                         GET_PTR( chdev_xp ),
270                                         &inode_xp );
271            }
272        }
273    }
274
275    // create an IOC inode in each cluster containing an IOC chdev
276    for( channel = 0 ; channel < CONFIG_MAX_IOC_CHANNELS ; channel++ )
277    {
278        chdev_xp = chdev_dir.ioc[channel];
279        if( chdev_xp != XPTR_NULL )
280        {
281            chdev_cxy = GET_CXY( chdev_xp );
282            chdev_ptr = (chdev_t *)GET_PTR( chdev_xp );
283            if( chdev_cxy == local_cxy )
284            {
285                vfs_add_child_in_parent( local_cxy,
286                                         INODE_TYPE_DEV,
287                                         FS_TYPE_DEVFS,
288                                         devfs_external_inode_xp,
289                                         chdev_ptr->name,
290                                         GET_PTR( chdev_xp ),
291                                         &inode_xp );
292            }
293        }
294    }
295
296    // create a FBF inode in each cluster containing a FBF chdev
297    for( channel = 0 ; channel < CONFIG_MAX_IOC_CHANNELS ; channel++ )
298    {
299        chdev_xp = chdev_dir.fbf[channel];
300        if( chdev_xp != XPTR_NULL )
301        {
302            chdev_cxy = GET_CXY( chdev_xp );
303            chdev_ptr = (chdev_t *)GET_PTR( chdev_xp );
304            if( chdev_cxy == local_cxy )
305            {
306                vfs_add_child_in_parent( local_cxy,
307                                         INODE_TYPE_DEV,
308                                         FS_TYPE_DEVFS,
309                                         devfs_external_inode_xp,
310                                         chdev_ptr->name,
311                                         GET_PTR( chdev_xp ),
312                                         &inode_xp );
313            }
314        }
315    }
316
317    // create a NIC_RX inode in each cluster containing a NIC_RX chdev
318    for( channel = 0 ; channel < CONFIG_MAX_NIC_CHANNELS ; channel++ )
319    {
320        chdev_xp = chdev_dir.nic_rx[channel];
321        if( chdev_xp != XPTR_NULL )
322        {
323            chdev_cxy = GET_CXY( chdev_xp );
324            chdev_ptr = (chdev_t *)GET_PTR( chdev_xp );
325            if( chdev_cxy == local_cxy )
326            {
327                vfs_add_child_in_parent( local_cxy,
328                                         INODE_TYPE_DEV,
329                                         FS_TYPE_DEVFS,
330                                         devfs_external_inode_xp,
331                                         chdev_ptr->name,
332                                         GET_PTR( chdev_xp ),
333                                         &inode_xp );
334            }
335        }
336    }
337
338    // create a NIC_TX inode in each cluster containing a NIC_TX chdev
339    for( channel = 0 ; channel < CONFIG_MAX_NIC_CHANNELS ; channel++ )
340    {
341        chdev_xp = chdev_dir.nic_tx[channel];
342        if( chdev_xp != XPTR_NULL )
343        {
344            chdev_cxy = GET_CXY( chdev_xp );
345            chdev_ptr = (chdev_t *)GET_PTR( chdev_xp );
346            if( chdev_cxy == local_cxy )
347            {
348                vfs_add_child_in_parent( local_cxy,
349                                         INODE_TYPE_DEV,
350                                         FS_TYPE_DEVFS,
351                                         devfs_external_inode_xp,
352                                         chdev_ptr->name,
353                                         GET_PTR( chdev_xp ),
354                                         &inode_xp );
355            }
356        }
357    }
358
359#if DEBUG_DEVFS_INIT
360cycle = (uint32_t)hal_get_cycles();
361if( DEBUG_DEVFS_INIT < cycle )
362printk("\n[DBG] %s : thread %x exit at cycle %d\n",
363__FUNCTION__ , CURRENT_THREAD , cycle );
364#endif
365
366}  // end devfs_local_init()
367
368//////////////////////////////////////////
369int devfs_user_move( bool_t     to_buffer,
370                     xptr_t     file_xp,
371                     void     * u_buf,
372                     uint32_t   size )
373{
374    assert( ( file_xp != XPTR_NULL ) , __FUNCTION__ , "file_xp == XPTR_NULL" );
375
376    assert( ( size < CONFIG_TXT_KBUF_SIZE ) , __FUNCTION__ , "string size too large" );
377
378    xptr_t             chdev_xp;
379    cxy_t              chdev_cxy;
380    chdev_t          * chdev_ptr;    // associated chdev type
381    uint32_t           func;         // chdev functionnal type
382    uint32_t           channel;      // chdev channel index
383    error_t            error;
384
385    char               k_buf[CONFIG_TXT_KBUF_SIZE];  // local kernel buffer
386
387#if (DEBUG_SYS_READ & 1)
388enter_devfs_read = hal_time_stamp();
389#endif
390
391#if (DEBUG_SYS_WRITE & 1)
392enter_devfs_write = hal_time_stamp();
393#endif
394
395#if DEBUG_DEVFS_MOVE
396uint32_t cycle = (uint32_t)hal_get_cycles();
397if( DEBUG_DEVFS_MOVE < cycle )
398printk("\n[DBG] %s : thread %x enter / to_mem %d / cycle %d\n",
399__FUNCTION__ , CURRENT_THREAD , to_buffer , cycle );
400#endif
401
402    // get extended pointer on chdev_xp
403    chdev_xp = chdev_from_file( file_xp );
404
405    // get cluster and local pointer on chdev
406    chdev_cxy  = GET_CXY( chdev_xp );
407    chdev_ptr  = (chdev_t *)GET_PTR( chdev_xp );
408
409    // get chdev functionnal type and channel
410    func    = hal_remote_lw( XPTR( chdev_cxy , &chdev_ptr->func ) );
411    channel = hal_remote_lw( XPTR( chdev_cxy , &chdev_ptr->channel ) );
412
413    // action depends on "func" and "to_buffer"
414    if( func == DEV_FUNC_TXT )
415    {
416        if( to_buffer )     // TXT read
417        { 
418            uint32_t i;
419            for( i = 0 ; i < size ; i++ )
420            {
421                error = dev_txt_read( channel , &k_buf[i] );
422
423                if( error ) 
424                {
425                    return -1;
426                }
427                else
428                {
429                    hal_strcpy_to_uspace( u_buf , k_buf , size );
430                }
431             }
432
433#if DEBUG_DEVFS_MOVE
434cycle = (uint32_t)hal_get_cycles();
435if( DEBUG_DEVFS_MOVE < cycle )
436printk("\n[DBG] %s : thread %x exit / to_mem %d / cycle %d\n",
437__FUNCTION__ , CURRENT_THREAD , to_buffer / cycle );
438#endif
439
440#if (DEBUG_SYS_READ & 1)
441exit_devfs_read = hal_time_stamp();
442#endif
443            return size;
444        } 
445        else                // TXT write 
446        {
447            hal_strcpy_from_uspace( k_buf , u_buf , size );
448
449            error = dev_txt_write( channel , k_buf , size );
450            if( error ) 
451            {
452                return -1;
453            }
454            else
455            {
456
457#if DEBUG_DEVFS_MOVE
458cycle = (uint32_t)hal_get_cycles();
459if( DEBUG_DEVFS_MOVE < cycle )
460printk("\n[DBG] %s : thread %x exit / to_mem %d / cycle %d\n",
461__FUNCTION__ , CURRENT_THREAD , to_buffer / cycle );
462#endif
463
464#if (DEBUG_SYS_WRITE & 1)
465exit_devfs_write = hal_time_stamp();
466#endif
467                return size;
468            }
469        }
470    }
471    else
472    {
473        assert( false , __FUNCTION__ ,
474        "%s does not support direct user access", chdev_func_str(func) );
475
476        return -1;
477    }
478
479}  // end devfs_user_move()
480
481
Note: See TracBrowser for help on using the repository browser.