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

Last change on this file since 72 was 50, checked in by alain, 7 years ago

bloup

File size: 19.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
141    devfs_dmsg("\n[INFO] %s : create dentry for %s\n", __FUNCTION__ , 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    if ( error )
149    {
150        printk("\n[PANIC] in %s : cannot create dentry for %s in cluster %x/n",
151               __FUNCTION__ , name , local_cxy );
152        hal_core_sleep();
153    }
154
155    devfs_dmsg("\n[INFO] %s : create inode for %s\n", __FUNCTION__ , name );
156   
157    // create vfs_inode in local cluster
158    uint32_t  attr   = 0;
159    uint32_t  rights = 0;
160    uid_t     uid    = 0;
161    gid_t     gid    = 0;
162    error = vfs_inode_create( new_dentry_xp,
163                              FS_TYPE_DEVFS,
164                              INODE_TYPE_DEV,
165                              attr,
166                              rights,
167                              uid,
168                              gid,
169                              &new_inode_xp );
170    if( error )
171    {
172        printk("\n[PANIC] in %s : cannot create inode for %s in cluster %x/n",
173               __FUNCTION__ , name , local_cxy );
174        hal_core_sleep();
175    }
176
177    // return extended pointer on chdev inode
178    *inode_xp = new_inode_xp;
179   
180}  // end devfs_register_chdev()
181
182
183
184///////////////////////////////////////////////////////////////////////////////////////
185// Generic API : the following functions are called by the VFS,
186//               and must be defined by all supported file systems.
187///////////////////////////////////////////////////////////////////////////////////////
188
189////////////////////////////////////////////
190
191////////////////////////////////////////////
192error_t devfs_mount( xptr_t   parent_inode_xp,
193                     char   * devfs_root_name )
194{
195    assert( (CURRENT_CORE->lid == 0) , __FUNCTION__ , "only CP0 should do it" );
196
197    vfs_inode_t * parent_inode_ptr;
198    cxy_t         parent_inode_cxy;
199    vfs_ctx_t   * vfs_ctx;
200
201    char          node_name[16];
202    uint32_t      channel;
203
204    xptr_t        root_inode_xp;
205    xptr_t        external_inode_xp;
206    xptr_t        internal_inode_xp;
207    xptr_t        chdev_inode_xp;
208
209    chdev_t     * chdev_ptr;
210
211    // get number of kernel instances and extended pointer on global barrier
212    cluster_t * cluster     = LOCAL_CLUSTER;
213    uint32_t    nb_clusters = cluster->x_size * cluster->y_size;
214    xptr_t      barrier_xp  = XPTR( cluster->io_cxy , &global_barrier );
215
216    // get VFS root inode cluster and local pointer
217    parent_inode_cxy = GET_CXY( parent_inode_xp );
218    parent_inode_ptr = (vfs_inode_t *)GET_PTR( parent_inode_xp );
219
220    // get local pointer on VFS context for DEVFS
221    vfs_ctx = &fs_context[FS_TYPE_DEVFS];
222
223    ///// step 1 : all clusters initialize local DEVFS context  /////
224
225    devfs_ctx_init( vfs_ctx , parent_inode_xp );
226
227    ///// step 2 : cluster_0 creates DEVFS root    /////
228
229    if( local_cxy == 0 )
230    {
231        devfs_create_directory( devfs_root_name,
232                                parent_inode_xp,
233                                &root_inode_xp );
234    }
235
236    // synchronize all clusters
237    remote_barrier( barrier_xp , nb_clusters );
238
239    ///// step 3 : all clusters create "internal" directory and chdevs  /////
240
241    // TODO check device existence : (chdev_xp != XPTR_NULL) in chdev_dir
242
243    snprintf( node_name , 16 , "internal_%x" , local_cxy );
244
245    devfs_create_directory( node_name,
246                            root_inode_xp,
247                            &internal_inode_xp );
248
249    // create ICU chdev inode
250    chdev_ptr = (chdev_t *)GET_PTR( chdev_dir.icu[local_cxy] );
251    devfs_register_chdev( chdev_ptr,
252                          "icu",
253                          (vfs_inode_t *)GET_PTR( internal_inode_xp ),
254                          &chdev_inode_xp );
255
256    // create MMC chdev inode
257    chdev_ptr = (chdev_t *)GET_PTR( chdev_dir.mmc[local_cxy] );
258    devfs_register_chdev( chdev_ptr,
259                          "mmc", 
260                          (vfs_inode_t *)GET_PTR( internal_inode_xp ),
261                          &chdev_inode_xp );
262
263    // create DMA chdev inodes (one DMA channel per core)
264    for( channel = 0 ; channel < cluster->cores_nr ; channel++ )
265    {
266        chdev_ptr = (chdev_t *)GET_PTR( chdev_dir.dma[channel] );
267        snprintf( node_name , 16 , "dma_%d" , channel );
268        devfs_register_chdev( chdev_ptr,
269                              node_name,
270                              (vfs_inode_t *)GET_PTR( internal_inode_xp ),
271                              &chdev_inode_xp );
272    }
273
274    ///// step 4 : cluster_io creates "external" directory and chdevs /////
275
276    // TODO check device existence : (chdev_xp != XPTR_NULL) in chdev_dir
277
278    if( local_cxy == cluster->io_cxy )
279    {
280        devfs_create_directory( "external",
281                                root_inode_xp,
282                                &external_inode_xp );
283
284        // create IOB chdev inode
285        chdev_ptr = (chdev_t *)GET_PTR( chdev_dir.iob );
286        devfs_register_chdev( chdev_ptr,
287                              "iob",
288                              (vfs_inode_t *)GET_PTR( external_inode_xp ),
289                              &chdev_inode_xp );
290       
291        // create PIC chdev inode
292        chdev_ptr = (chdev_t *)GET_PTR( chdev_dir.pic );
293        devfs_register_chdev( chdev_ptr,
294                              "pic",
295                              (vfs_inode_t *)GET_PTR( external_inode_xp ),
296                              &chdev_inode_xp );
297
298        // create TXT chdev inodes
299        for( channel = 0 ; channel < CONFIG_MAX_TXT_CHANNELS ; channel++ )
300        {
301            chdev_ptr = (chdev_t *)GET_PTR( chdev_dir.txt[channel] );
302            snprintf( node_name , 16 , "txt_%d" , channel );
303            devfs_register_chdev( chdev_ptr,
304                                  node_name,
305                                  (vfs_inode_t *)GET_PTR( external_inode_xp ),
306                                  &chdev_inode_xp );
307        }
308
309        // create IOC chdev inodes
310        for( channel = 0 ; channel < CONFIG_MAX_IOC_CHANNELS ; channel++ )
311        {
312            chdev_ptr = (chdev_t *)GET_PTR( chdev_dir.ioc[channel] );
313            snprintf( node_name , 16 , "ioc_%d" , channel );
314            devfs_register_chdev( chdev_ptr,
315                                  node_name,
316                                  (vfs_inode_t *)GET_PTR( external_inode_xp ),
317                                  &chdev_inode_xp );
318        }
319
320        // create FBF chdev inodes
321        for( channel = 0 ; channel < CONFIG_MAX_IOC_CHANNELS ; channel++ )
322        {
323            chdev_ptr = (chdev_t *)GET_PTR( chdev_dir.ioc[channel] );
324            snprintf( node_name , 16 , "fbf_%d" , channel );
325            devfs_register_chdev( chdev_ptr,
326                                  node_name,
327                                  (vfs_inode_t *)GET_PTR( external_inode_xp ),
328                                  &chdev_inode_xp );
329        }
330
331        // create NIC_RX chdevs
332        for( channel = 0 ; channel < CONFIG_MAX_NIC_CHANNELS ; channel++ )
333        {
334            chdev_ptr = (chdev_t *)GET_PTR( chdev_dir.nic_rx[channel] );
335            snprintf( node_name , 16 , "nic_rx_%d" , channel );
336            devfs_register_chdev( chdev_ptr,
337                                  node_name,
338                                  (vfs_inode_t *)GET_PTR( external_inode_xp ),
339                                  &chdev_inode_xp );
340        }
341
342        // create NIC_TX chdev inodes
343        for( channel = 0 ; channel < CONFIG_MAX_NIC_CHANNELS ; channel++ )
344        {
345            chdev_ptr = (chdev_t *)GET_PTR( chdev_dir.nic_tx[channel] );
346            snprintf( node_name , 16 , "nic_tx_%d" , channel );
347            devfs_register_chdev( chdev_ptr,
348                                  node_name,
349                                  (vfs_inode_t *)GET_PTR( external_inode_xp ),
350                                  &chdev_inode_xp );
351        }
352    }
353
354    // synchronize all clusters
355    remote_barrier( barrier_xp , nb_clusters );
356
357    return 0;
358
359}  // end devfs_init()
360
361
362////////////////////////////////////////////
363error_t devfs_ctx_init( vfs_ctx_t * vfs_ctx,
364                        xptr_t      root_inode_xp )
365{
366    vfs_ctx->type    = FS_TYPE_DEVFS;
367    vfs_ctx->attr    = 0;                // not READ_ONLY / not SYNC
368    vfs_ctx->count   = 0;                // unused for DEVFS
369    vfs_ctx->blksize = 0;                // unused for DEVFS
370    vfs_ctx->root_xp = root_inode_xp;
371    vfs_ctx->extend  = NULL;             // unused for DEVFS
372
373    spinlock_init( &vfs_ctx->lock );
374
375    bitmap_init( vfs_ctx->bitmap , CONFIG_VFS_MAX_INODES );
376
377    return 0;
378}
379
380
381////////////////////////////////////////////////////
382error_t devfs_inode_create( vfs_inode_t * vfs_inode,
383                            chdev_t     * chdev )
384{
385    kmem_req_t      req;
386    devfs_inode_t * devfs_inode;
387
388    // allocate memory for FATFS inode extension
389        req.type    = KMEM_DEVFS_INODE;
390        req.size    = sizeof(devfs_inode_t);
391    req.flags   = AF_KERNEL | AF_ZERO;
392        devfs_inode = (devfs_inode_t *)kmem_alloc( &req );
393
394    if( devfs_inode == NULL ) return ENOMEM;
395
396    // link DEVFS inode to VFS inode
397    vfs_inode->extend = devfs_inode;
398
399    // initialise DEVFS inode 
400    devfs_inode->chdev = chdev;
401 
402    return 0;
403}
404
405///////////////////////////////////////////////////
406void devfs_inode_destroy( vfs_inode_t * vfs_inode )
407{
408    kmem_req_t      req;
409    devfs_inode_t * devfs_inode;
410
411    // get pointer on DEVFS inode
412    devfs_inode = (devfs_inode_t *)vfs_inode->extend;
413
414    req.type = KMEM_DEVFS_INODE;
415    req.ptr  = devfs_inode;
416    kmem_free( &req );
417
418        vfs_inode->extend = NULL;
419}
420
421
422/* deprecated [AG]
423
424error_t devfs_open_file( vfs_file_t * file,
425                         void       * extend );
426{
427        error_t err;
428        register struct devfs_context_s *ctx;
429        register struct devfs_file_s *info;
430        chdev_t       * chdev;
431        vfs_inode_t   * inode;
432        dev_request_t   rq;
433        kmem_req_t      req;
434
435        inode = file->inode;
436
437        info = file->fr_pv;
438        ctx  = (struct devfs_context_s *)&inode->i_ctx->ctx_devfs;
439
440        if(!(inode->i_attr & VFS_DIR))
441        {
442                dev = (struct device_s*)inode->i_pv;
443   
444                if(dev->type == DEV_INTERNAL)
445                        return EPERM;
446
447                if(dev->type == DEV_BLK)
448                        VFS_SET(inode->i_attr,VFS_DEV_BLK);
449                else
450                        VFS_SET(inode->i_attr,VFS_DEV_CHR);
451 
452                if(dev->op.dev.open != NULL)
453                {
454                        rq.fremote = file;
455                        if((err=dev->op.dev.open(dev, &rq)))
456                                return err;
457                }
458
459                priv->dev = (void*)dev;
460
461                return 0;
462        }
463
464        if(info == NULL)
465        {
466                req.type  = KMEM_DEVFS_FILE;
467                req.size  = sizeof(*info);
468                req.flags = AF_KERNEL;
469                info      = kmem_alloc(&req);
470        }
471
472        if(info == NULL) return ENOMEM;
473
474        metafs_iter_init(&devfs_db.root, &info->iter);
475        info->ctx  = ctx;
476        file->fr_pv = info;
477 
478        metafs_print(&devfs_db.root);
479        return 0;
480}
481
482#define TMP_BUFF_SZ 512
483
484//FIXME:
485//add a "while" loop for the case where the
486//buffer TMP_BUFF_SZ is smaller than
487//buffer->size
488//////////////////////////////
489devfs_read( vfs_file_t * file,
490            char       * buffer )
491{
492        chdev_t       * chdev;
493        dev_request_t   rq;
494        uint32_t        count;
495    uint8_t         buff[TMP_BUFF_SZ];
496
497    // get pointer on chdev
498        chdev = (chdev_t *)file->extend;
499
500    if( chdev->func == DEV_FUNC_TXT )
501    {
502    }
503    if( chdev->func == DEV_FUNC_IOC )
504    {
505    }
506    else
507    {
508        printk("\n[PANIC] in %s : illegal device functionnal type
509
510        rq.dst   = &buff[0];
511        rq.count = TMP_BUFF_SZ;
512        rq.flags = 0;
513        rq.file  = file;
514
515        if((count = dev->op.dev.read(dev, &rq)) < 0)
516                return count;
517
518        buffer->scpy_to_buff(buffer, &buff[0], count);
519        return count;
520}
521
522//FIXME: To improve this an avoid the extra copy,
523//we could set along with the buffer(src and dest)
524//the functions to manipulate them, such as in
525//do_exec.c
526///////////////////////////////
527devfs_write( vfs_file_t * file,
528             char       * buffer )
529{
530        register struct device_s *dev;
531        uint8_t buff[TMP_BUFF_SZ];
532        dev_request_t rq;
533       
534        dev = (struct device_s*)file->f_private.dev;
535       
536        //FIXME avoid the extra copy ?
537        buffer->scpy_from_buff(buffer, (void*)&buff[0], TMP_BUFF_SZ);
538        rq.src   = (void*)&buff[0];
539        rq.count = buffer->size;
540        rq.flags = 0;
541        rq.file  = file;
542 
543        return dev->op.dev.write(dev, &rq);
544}
545
546VFS_LSEEK_FILE(devfs_lseek)
547{
548        register struct device_s *dev;
549        dev_request_t rq;
550
551        dev = (struct device_s*)file->fr_inode->i_pv;
552
553        if(dev->op.dev.lseek == NULL)
554                return VFS_ENOTUSED;
555 
556        rq.fremote = file;
557        return dev->op.dev.lseek(dev, &rq);
558}
559
560VFS_CLOSE_FILE(devfs_close)
561{
562        register struct device_s *dev;
563        dev_request_t rq;
564
565        if(file->fr_inode->i_attr & VFS_DIR)
566                return 0;
567
568        dev = (struct device_s*)file->fr_inode->i_pv;
569
570        if(dev->op.dev.close == NULL)
571                return 0;
572 
573        rq.fremote = file;
574        return dev->op.dev.close(dev, &rq);
575}
576
577VFS_RELEASE_FILE(devfs_release)
578
579        kmem_req_t req;
580
581        if(file->fr_pv == NULL)
582                return 0;
583 
584        req.type = KMEM_DEVFS_FILE;
585        req.ptr  = file->fr_pv;
586        kmem_free(&req);
587
588        file->fr_pv = NULL;
589        return 0;
590}
591
592VFS_READ_DIR(devfs_readdir)
593{
594        register struct devfs_file_s *info;
595        register struct metafs_s *current;
596        register struct device_s *current_dev;
597 
598        info = file->fr_pv;
599 
600        if(file->fr_pv == NULL)
601                return ENOTDIR;
602
603        if((current = metafs_lookup_next(&devfs_db.root, &info->iter)) == NULL)
604                return EEODIR;
605
606        current_dev    = metafs_container(current, struct device_s, node);
607        dirent->u_attr = (current_dev->type == DEV_BLK) ? VFS_DEV_BLK : VFS_DEV_CHR;
608
609        strcpy((char*)dirent->u_name, metafs_get_name(current));
610
611        dirent->u_ino = (uint_t) current_dev->base_paddr;
612
613        return 0;
614}
615
616VFS_MMAP_FILE(devfs_mmap)
617{
618        register struct device_s *dev;
619        dev_request_t rq;
620 
621        dev = (struct device_s*)file->f_private.dev;
622
623        if(dev->op.dev.mmap == NULL)
624                return ENODEV;
625
626        rq.flags  = 0;
627        rq.file   = file;
628        rq.region = region;
629
630        return dev->op.dev.mmap(dev, &rq);
631}
632
633VFS_MMAP_FILE(devfs_munmap)
634{
635        register struct device_s *dev;
636        dev_request_t rq;
637
638        dev = (struct device_s*)file->f_private.dev;
639
640        if(dev->op.dev.munmap == NULL)
641                return ENODEV;
642
643        rq.flags  = 0;
644        rq.file   = file;
645        rq.region = region;
646
647        return dev->op.dev.munmap(dev, &rq);
648}
649
650
651*/
652
653
Note: See TracBrowser for help on using the repository browser.