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

Last change on this file since 177 was 50, checked in by alain, 9 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.