source: trunk/kernel/vfs/devfs.c @ 27

Last change on this file since 27 was 23, checked in by alain, 7 years ago

Introduce syscalls.

File size: 20.1 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 <printk.h>
28#include <kmem.h>
29#include <string.h>
30#include <chdev.h>
31#include <core.h>
32#include <thread.h>
33#include <vfs.h>
34#include <errno.h>
35#include <devfs.h>
36#include <rpc.h>
37
38
39//////////////////////////////////////////////////////////////////////////////////////////
40//          Extern  variables         
41//////////////////////////////////////////////////////////////////////////////////////////
42
43extern vfs_ctx_t          fs_context[FS_TYPES_NR];   // allocated in vfs.c file
44
45extern remote_barrier_t   global_barrier;            // allocated in kernel_init.c
46 
47extern chdev_directory_t  chdev_dir;                 // allocated in kernel_init.c
48
49////////////////////////////////////////////////////////////////////////////////////////
50//                DEVFS private functions
51////////////////////////////////////////////////////////////////////////////////////////
52
53////////////////////////////////////////////////////////////////////////////////////////
54// This function creates in the local cluster the dentry and the associated inode,
55// for a DEVFS directory (level 0 or level 1 in DEVFS tree).
56////////////////////////////////////////////////////////////////////////////////////////
57// @ name        : directory entry name.
58// @ parent_xp   : extended pointer on parent inode.
59// @ inode_xp    : [out] buffer for extended pointer on created inode.
60////////////////////////////////////////////////////////////////////////////////////////
61static void devfs_create_directory( char        * name,
62                                    xptr_t        parent_xp,
63                                    xptr_t      * inode_xp )
64{
65    error_t       error;
66    xptr_t        new_dentry_xp;     // extended pointer on created dentry
67    xptr_t        new_inode_xp;      // extended pointer on created inode
68 
69    // get parent inode cluster and local pointer
70    cxy_t         parent_cxy = GET_CXY( parent_xp );
71    vfs_inode_t * parent_ptr = (vfs_inode_t *)GET_PTR( parent_xp );
72
73    // create vfs_dentry in cluster containing the parent inode
74    if( parent_cxy == local_cxy )
75    {
76        error = vfs_dentry_create( FS_TYPE_DEVFS,
77                                   name,
78                                   parent_ptr,
79                                   &new_dentry_xp );
80    }
81    else
82    {
83        rpc_vfs_dentry_create_client( parent_cxy,
84                                      FS_TYPE_DEVFS,
85                                      name,
86                                      parent_ptr,
87                                      &new_dentry_xp,
88                                      &error );
89    }
90
91    if ( error )
92    {
93        printk("\n[PANIC] in %s : cannot create dentry for %s in cluster %x/n",
94               __FUNCTION__ , name , local_cxy );
95        hal_core_sleep();
96    }
97
98    // create vfs_inode in local cluster TODO define the 4 arguments below [AG]
99    uint32_t  attr   = 0;
100    uint32_t  rights = 0;
101    uid_t     uid    = 0;
102    gid_t     gid    = 0;
103    error = vfs_inode_create( new_dentry_xp,
104                              FS_TYPE_DEVFS,
105                              INODE_TYPE_DIR,
106                              attr,
107                              rights,
108                              uid,
109                              gid,
110                              &new_inode_xp );
111    if( error )
112    {
113        printk("\n[PANIC] in %s : cannot create inode for %s in cluster %x/n",
114               __FUNCTION__ , name , local_cxy );
115        hal_core_sleep();
116    }
117
118    // return extended pointer on directory inode
119    *inode_xp = new_inode_xp;
120
121}  // end devfs_create_directory()
122                                   
123////////////////////////////////////////////////////////////////////////////////////////
124// This function creates in the local cluster the dentry and the associated inode,
125// for a chdev (level 2 in DEVFS tree).
126////////////////////////////////////////////////////////////////////////////////////////
127// @ chdev    : local pointer on local chdev.
128// @ name     : directory entry name.
129// @ parent   : local pointer on local parent inode.
130// @ inode_xp : [out] buffer for extended pointer on created inode.
131////////////////////////////////////////////////////////////////////////////////////////
132static void devfs_register_chdev( chdev_t     * chdev,
133                                  char        * name,
134                                  vfs_inode_t * parent,
135                                  xptr_t      * inode_xp )
136{
137    error_t  error;
138    xptr_t   new_dentry_xp;
139    xptr_t   new_inode_xp;
140
141printk("\n        @@@ devfs_chdev : 0 / name = %s\n", name );
142
143    // create vfs_dentry in local cluster
144    error = vfs_dentry_create( FS_TYPE_DEVFS,
145                               name,
146                               parent,
147                               &new_dentry_xp );
148
149printk("\n        @@@ devfs_chdev : 1 / name = %s\n", name );
150
151    if ( error )
152    {
153        printk("\n[PANIC] in %s : cannot create dentry for %s in cluster %x/n",
154               __FUNCTION__ , name , local_cxy );
155        hal_core_sleep();
156    }
157
158printk("\n        @@@ devfs_chdev : 2 / name = %s\n", name );
159
160    // create vfs_inode in local cluster
161    uint32_t  attr   = 0;
162    uint32_t  rights = 0;
163    uid_t     uid    = 0;
164    gid_t     gid    = 0;
165    error = vfs_inode_create( new_dentry_xp,
166                              FS_TYPE_DEVFS,
167                              INODE_TYPE_DEV,
168                              attr,
169                              rights,
170                              uid,
171                              gid,
172                              &new_inode_xp );
173
174printk("\n        @@@ devfs_chdev : 3 / name = %s\n", name );
175
176    if( error )
177    {
178        printk("\n[PANIC] in %s : cannot create inode for %s in cluster %x/n",
179               __FUNCTION__ , name , local_cxy );
180        hal_core_sleep();
181    }
182
183    // return extended pointer on chdev inode
184    *inode_xp = new_inode_xp;
185   
186}  // end devfs_register_chdev()
187
188
189
190///////////////////////////////////////////////////////////////////////////////////////
191// Generic API : the following functions are called by the VFS,
192//               and must be defined by all supported file systems.
193///////////////////////////////////////////////////////////////////////////////////////
194
195////////////////////////////////////////////
196
197////////////////////////////////////////////
198error_t devfs_mount( xptr_t   parent_inode_xp,
199                     char   * devfs_root_name )
200{
201    assert( (CURRENT_CORE->lid == 0) , __FUNCTION__ , "only CP0 should do it" );
202
203    vfs_inode_t * parent_inode_ptr;
204    cxy_t         parent_inode_cxy;
205    vfs_ctx_t   * vfs_ctx;
206
207    char          node_name[16];
208    uint32_t      channel;
209
210    xptr_t        root_inode_xp;
211    xptr_t        external_inode_xp;
212    xptr_t        internal_inode_xp;
213    xptr_t        chdev_inode_xp;
214
215    chdev_t     * chdev_ptr;
216
217    // get number of kernel instances and extended pointer on global barrier
218    cluster_t * cluster     = LOCAL_CLUSTER;
219    uint32_t    nb_clusters = cluster->x_size * cluster->y_size;
220    xptr_t      barrier_xp  = XPTR( cluster->io_cxy , &global_barrier );
221
222    // get VFS root inode cluster and local pointer
223    parent_inode_cxy = GET_CXY( parent_inode_xp );
224    parent_inode_ptr = (vfs_inode_t *)GET_PTR( parent_inode_xp );
225
226    // get local pointer on VFS context for DEVFS
227    vfs_ctx = &fs_context[FS_TYPE_DEVFS];
228
229    ///// step 1 : all clusters initialize local DEVFS context  /////
230
231printk("\n    @@@ devfs_mount : 0 / name = %s\n", devfs_root_name );
232
233    devfs_ctx_init( vfs_ctx , parent_inode_xp );
234
235    ///// step 2 : cluster_0 creates DEVFS root    /////
236
237printk("\n    @@@ devfs_mount : 1 / name = %s\n", devfs_root_name );
238
239    if( local_cxy == 0 )
240    {
241        devfs_create_directory( devfs_root_name,
242                                parent_inode_xp,
243                                &root_inode_xp );
244printk("\n    @@@ devfs_mount : 2\n");
245
246    }
247
248    // synchronize all clusters
249    remote_barrier( barrier_xp , nb_clusters );
250
251    ///// step 3 : all clusters create "internal" directory and chdevs  /////
252
253printk("\n    @@@ devfs_mount : 3 / name = %s\n", devfs_root_name );
254
255    snprintf( node_name , 16 , "internal_%x" , local_cxy );
256
257printk("\n    @@@ devfs_mount : 4 / name = %s\n", devfs_root_name );
258
259    devfs_create_directory( node_name,
260                            root_inode_xp,
261                            &internal_inode_xp );
262
263printk("\n    @@@ devfs_mount : 5 / name = %s\n", devfs_root_name );
264
265    // create ICU chdev inode
266    chdev_ptr = (chdev_t *)GET_PTR( chdev_dir.icu[local_cxy] );
267    devfs_register_chdev( chdev_ptr,
268                          "icu",
269                          (vfs_inode_t *)GET_PTR( internal_inode_xp ),
270                          &chdev_inode_xp );
271
272printk("\n    @@@ devfs_mount : 6 / name = %s\n", devfs_root_name );
273
274    // create MMC chdev inode
275    chdev_ptr = (chdev_t *)GET_PTR( chdev_dir.mmc[local_cxy] );
276    devfs_register_chdev( chdev_ptr,
277                          "mmc", 
278                          (vfs_inode_t *)GET_PTR( internal_inode_xp ),
279                          &chdev_inode_xp );
280
281printk("\n    @@@ devfs_mount : 7 / name = %s\n", devfs_root_name );
282
283    // create DMA chdev inodes (one DMA channel per core)
284    for( channel = 0 ; channel < cluster->cores_nr ; channel++ )
285    {
286        chdev_ptr = (chdev_t *)GET_PTR( chdev_dir.dma[channel] );
287        snprintf( node_name , 16 , "dma_%d" , channel );
288        devfs_register_chdev( chdev_ptr,
289                              node_name,
290                              (vfs_inode_t *)GET_PTR( internal_inode_xp ),
291                              &chdev_inode_xp );
292
293printk("\n    @@@ devfs_mount : 8 / name = %s\n", devfs_root_name );
294
295    }
296
297    ///// step 4 : cluster_io creates "external" directory and chdevs /////
298
299    if( local_cxy == cluster->io_cxy )
300    {
301        devfs_create_directory( "external",
302                                root_inode_xp,
303                                &external_inode_xp );
304
305printk("\n    @@@ devfs_mount : 9 / name = %s\n", devfs_root_name );
306
307        // create IOB chdev inode
308        chdev_ptr = (chdev_t *)GET_PTR( chdev_dir.iob );
309        devfs_register_chdev( chdev_ptr,
310                              "iob",
311                              (vfs_inode_t *)GET_PTR( external_inode_xp ),
312                              &chdev_inode_xp );
313       
314printk("\n    @@@ devfs_mount : 10 / name = %s\n", devfs_root_name );
315
316        // create PIC chdev inode
317        chdev_ptr = (chdev_t *)GET_PTR( chdev_dir.pic );
318        devfs_register_chdev( chdev_ptr,
319                              "pic",
320                              (vfs_inode_t *)GET_PTR( external_inode_xp ),
321                              &chdev_inode_xp );
322
323        // create TXT chdev inodes
324        for( channel = 0 ; channel < CONFIG_MAX_TXT_CHANNELS ; channel++ )
325        {
326            chdev_ptr = (chdev_t *)GET_PTR( chdev_dir.txt[channel] );
327            snprintf( node_name , 16 , "txt_%d" , channel );
328            devfs_register_chdev( chdev_ptr,
329                                  node_name,
330                                  (vfs_inode_t *)GET_PTR( external_inode_xp ),
331                                  &chdev_inode_xp );
332        }
333
334        // create IOC chdev inodes
335        for( channel = 0 ; channel < CONFIG_MAX_IOC_CHANNELS ; channel++ )
336        {
337            chdev_ptr = (chdev_t *)GET_PTR( chdev_dir.ioc[channel] );
338            snprintf( node_name , 16 , "ioc_%d" , channel );
339            devfs_register_chdev( chdev_ptr,
340                                  node_name,
341                                  (vfs_inode_t *)GET_PTR( external_inode_xp ),
342                                  &chdev_inode_xp );
343        }
344
345        // create FBF chdev inodes
346        for( channel = 0 ; channel < CONFIG_MAX_IOC_CHANNELS ; channel++ )
347        {
348            chdev_ptr = (chdev_t *)GET_PTR( chdev_dir.ioc[channel] );
349            snprintf( node_name , 16 , "fbf_%d" , channel );
350            devfs_register_chdev( chdev_ptr,
351                                  node_name,
352                                  (vfs_inode_t *)GET_PTR( external_inode_xp ),
353                                  &chdev_inode_xp );
354        }
355
356        // create NIC_RX chdevs
357        for( channel = 0 ; channel < CONFIG_MAX_NIC_CHANNELS ; channel++ )
358        {
359            chdev_ptr = (chdev_t *)GET_PTR( chdev_dir.nic_rx[channel] );
360            snprintf( node_name , 16 , "nic_rx_%d" , channel );
361            devfs_register_chdev( chdev_ptr,
362                                  node_name,
363                                  (vfs_inode_t *)GET_PTR( external_inode_xp ),
364                                  &chdev_inode_xp );
365        }
366
367        // create NIC_TX chdev inodes
368        for( channel = 0 ; channel < CONFIG_MAX_NIC_CHANNELS ; channel++ )
369        {
370            chdev_ptr = (chdev_t *)GET_PTR( chdev_dir.nic_tx[channel] );
371            snprintf( node_name , 16 , "nic_tx_%d" , channel );
372            devfs_register_chdev( chdev_ptr,
373                                  node_name,
374                                  (vfs_inode_t *)GET_PTR( external_inode_xp ),
375                                  &chdev_inode_xp );
376printk("\n    @@@ devfs_mount : 11 / name = %s\n", devfs_root_name );
377
378        }
379    }
380
381    // synchronize all clusters
382    remote_barrier( barrier_xp , nb_clusters );
383
384    return 0;
385
386}  // end devfs_init()
387
388
389////////////////////////////////////////////
390error_t devfs_ctx_init( vfs_ctx_t * vfs_ctx,
391                        xptr_t      root_inode_xp )
392{
393    vfs_ctx->type    = FS_TYPE_DEVFS;
394    vfs_ctx->attr    = 0;                // not READ_ONLY / not SYNC
395    vfs_ctx->count   = 0;                // unused for DEVFS
396    vfs_ctx->blksize = 0;                // unused for DEVFS
397    vfs_ctx->root_xp = root_inode_xp;
398    vfs_ctx->extend  = NULL;             // unused for DEVFS
399
400    spinlock_init( &vfs_ctx->lock );
401
402    bitmap_init( vfs_ctx->bitmap , CONFIG_VFS_MAX_INODES );
403
404    return 0;
405}
406
407
408////////////////////////////////////////////////////
409error_t devfs_inode_create( vfs_inode_t * vfs_inode,
410                            chdev_t     * chdev )
411{
412    kmem_req_t      req;
413    devfs_inode_t * devfs_inode;
414
415    // allocate memory for FATFS inode extension
416        req.type    = KMEM_DEVFS_INODE;
417        req.size    = sizeof(devfs_inode_t);
418    req.flags   = AF_KERNEL | AF_ZERO;
419        devfs_inode = (devfs_inode_t *)kmem_alloc( &req );
420
421    if( devfs_inode == NULL ) return ENOMEM;
422
423    // link DEVFS inode to VFS inode
424    vfs_inode->extend = devfs_inode;
425
426    // initialise DEVFS inode 
427    devfs_inode->chdev = chdev;
428 
429    return 0;
430}
431
432///////////////////////////////////////////////////
433void devfs_inode_destroy( vfs_inode_t * vfs_inode )
434{
435    kmem_req_t      req;
436    devfs_inode_t * devfs_inode;
437
438    // get pointer on DEVFS inode
439    devfs_inode = (devfs_inode_t *)vfs_inode->extend;
440
441    req.type = KMEM_DEVFS_INODE;
442    req.ptr  = devfs_inode;
443    kmem_free( &req );
444
445        vfs_inode->extend = NULL;
446}
447
448
449/* deprecated [AG]
450
451error_t devfs_open_file( vfs_file_t * file,
452                         void       * extend );
453{
454        error_t err;
455        register struct devfs_context_s *ctx;
456        register struct devfs_file_s *info;
457        chdev_t       * chdev;
458        vfs_inode_t   * inode;
459        dev_request_t   rq;
460        kmem_req_t      req;
461
462        inode = file->inode;
463
464        info = file->fr_pv;
465        ctx  = (struct devfs_context_s *)&inode->i_ctx->ctx_devfs;
466
467        if(!(inode->i_attr & VFS_DIR))
468        {
469                dev = (struct device_s*)inode->i_pv;
470   
471                if(dev->type == DEV_INTERNAL)
472                        return EPERM;
473
474                if(dev->type == DEV_BLK)
475                        VFS_SET(inode->i_attr,VFS_DEV_BLK);
476                else
477                        VFS_SET(inode->i_attr,VFS_DEV_CHR);
478 
479                if(dev->op.dev.open != NULL)
480                {
481                        rq.fremote = file;
482                        if((err=dev->op.dev.open(dev, &rq)))
483                                return err;
484                }
485
486                priv->dev = (void*)dev;
487
488                return 0;
489        }
490
491        if(info == NULL)
492        {
493                req.type  = KMEM_DEVFS_FILE;
494                req.size  = sizeof(*info);
495                req.flags = AF_KERNEL;
496                info      = kmem_alloc(&req);
497        }
498
499        if(info == NULL) return ENOMEM;
500
501        metafs_iter_init(&devfs_db.root, &info->iter);
502        info->ctx  = ctx;
503        file->fr_pv = info;
504 
505        metafs_print(&devfs_db.root);
506        return 0;
507}
508
509#define TMP_BUFF_SZ 512
510
511//FIXME:
512//add a "while" loop for the case where the
513//buffer TMP_BUFF_SZ is smaller than
514//buffer->size
515//////////////////////////////
516devfs_read( vfs_file_t * file,
517            char       * buffer )
518{
519        chdev_t       * chdev;
520        dev_request_t   rq;
521        uint32_t        count;
522    uint8_t         buff[TMP_BUFF_SZ];
523
524    // get pointer on chdev
525        chdev = (chdev_t *)file->extend;
526
527    if( chdev->func == DEV_FUNC_TXT )
528    {
529    }
530    if( chdev->func == DEV_FUNC_IOC )
531    {
532    }
533    else
534    {
535        printk("\n[PANIC] in %s : illegal device functionnal type
536
537        rq.dst   = &buff[0];
538        rq.count = TMP_BUFF_SZ;
539        rq.flags = 0;
540        rq.file  = file;
541
542        if((count = dev->op.dev.read(dev, &rq)) < 0)
543                return count;
544
545        buffer->scpy_to_buff(buffer, &buff[0], count);
546        return count;
547}
548
549//FIXME: To improve this an avoid the extra copy,
550//we could set along with the buffer(src and dest)
551//the functions to manipulate them, such as in
552//do_exec.c
553///////////////////////////////
554devfs_write( vfs_file_t * file,
555             char       * buffer )
556{
557        register struct device_s *dev;
558        uint8_t buff[TMP_BUFF_SZ];
559        dev_request_t rq;
560       
561        dev = (struct device_s*)file->f_private.dev;
562       
563        //FIXME avoid the extra copy ?
564        buffer->scpy_from_buff(buffer, (void*)&buff[0], TMP_BUFF_SZ);
565        rq.src   = (void*)&buff[0];
566        rq.count = buffer->size;
567        rq.flags = 0;
568        rq.file  = file;
569 
570        return dev->op.dev.write(dev, &rq);
571}
572
573VFS_LSEEK_FILE(devfs_lseek)
574{
575        register struct device_s *dev;
576        dev_request_t rq;
577
578        dev = (struct device_s*)file->fr_inode->i_pv;
579
580        if(dev->op.dev.lseek == NULL)
581                return VFS_ENOTUSED;
582 
583        rq.fremote = file;
584        return dev->op.dev.lseek(dev, &rq);
585}
586
587VFS_CLOSE_FILE(devfs_close)
588{
589        register struct device_s *dev;
590        dev_request_t rq;
591
592        if(file->fr_inode->i_attr & VFS_DIR)
593                return 0;
594
595        dev = (struct device_s*)file->fr_inode->i_pv;
596
597        if(dev->op.dev.close == NULL)
598                return 0;
599 
600        rq.fremote = file;
601        return dev->op.dev.close(dev, &rq);
602}
603
604VFS_RELEASE_FILE(devfs_release)
605
606        kmem_req_t req;
607
608        if(file->fr_pv == NULL)
609                return 0;
610 
611        req.type = KMEM_DEVFS_FILE;
612        req.ptr  = file->fr_pv;
613        kmem_free(&req);
614
615        file->fr_pv = NULL;
616        return 0;
617}
618
619VFS_READ_DIR(devfs_readdir)
620{
621        register struct devfs_file_s *info;
622        register struct metafs_s *current;
623        register struct device_s *current_dev;
624 
625        info = file->fr_pv;
626 
627        if(file->fr_pv == NULL)
628                return ENOTDIR;
629
630        if((current = metafs_lookup_next(&devfs_db.root, &info->iter)) == NULL)
631                return EEODIR;
632
633        current_dev    = metafs_container(current, struct device_s, node);
634        dirent->u_attr = (current_dev->type == DEV_BLK) ? VFS_DEV_BLK : VFS_DEV_CHR;
635
636        strcpy((char*)dirent->u_name, metafs_get_name(current));
637
638        dirent->u_ino = (uint_t) current_dev->base_paddr;
639
640        return 0;
641}
642
643VFS_MMAP_FILE(devfs_mmap)
644{
645        register struct device_s *dev;
646        dev_request_t rq;
647 
648        dev = (struct device_s*)file->f_private.dev;
649
650        if(dev->op.dev.mmap == NULL)
651                return ENODEV;
652
653        rq.flags  = 0;
654        rq.file   = file;
655        rq.region = region;
656
657        return dev->op.dev.mmap(dev, &rq);
658}
659
660VFS_MMAP_FILE(devfs_munmap)
661{
662        register struct device_s *dev;
663        dev_request_t rq;
664
665        dev = (struct device_s*)file->f_private.dev;
666
667        if(dev->op.dev.munmap == NULL)
668                return ENODEV;
669
670        rq.flags  = 0;
671        rq.file   = file;
672        rq.region = region;
673
674        return dev->op.dev.munmap(dev, &rq);
675}
676
677
678const struct vfs_file_op_s devfs_f_op =
679{
680        .open    = devfs_open,
681        .read    = devfs_read,
682        .write   = devfs_write,
683        .lseek   = devfs_lseek,
684        .mmap    = devfs_mmap,
685        .munmap  = devfs_munmap,
686        .readdir = devfs_readdir,
687        .close   = devfs_close,
688        .release = devfs_release
689};
690
691*/
692
693
Note: See TracBrowser for help on using the repository browser.