source: trunk/kernel/vfs/fatfs.c @ 183

Last change on this file since 183 was 101, checked in by alain, 7 years ago

euh...

File size: 18.8 KB
RevLine 
[1]1/*
2 * fatfs.c - FATFS file system API implementation.
3 *
[23]4 * Author    Mohamed Lamine Karaoui (2014,2015)
5 *           Alain Greiner (2016,2017)
[1]6 *
7 * Copyright (c) UPMC 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
26#include <hal_types.h>
27#include <hal_special.h>
28#include <printk.h>
29#include <kmem.h>
30#include <ppm.h>
31#include <vfs.h>
32#include <rpc.h>
33#include <mapper.h>
[23]34#include <cluster.h>
[1]35#include <dev_ioc.h>
36#include <fatfs.h>
37
[50]38
[23]39//////////////////////////////////////////////////////////////////////////////////////////
40//          Extern  variables         
41//////////////////////////////////////////////////////////////////////////////////////////
[1]42
[50]43extern vfs_ctx_t          fs_context[FS_TYPES_NR];   // allocated in vfs.c file
[23]44
[50]45extern remote_barrier_t   global_barrier;            // allocated in kernel_init.c
[23]46 
[1]47//////////////////////////////////////////////////////////////////////////////////////////
48// FATFS specific functions : these functions cannot be called by the VFS
49//////////////////////////////////////////////////////////////////////////////////////////
50
51//////////////////////////////////////////////////////////
52inline uint32_t fatfs_lba_from_cluster( fatfs_ctx_t * ctx,
53                                        uint32_t      cluster )
54{
[23]55    return (ctx->cluster_begin_lba + ((cluster - 2) << 3));
[1]56}
57
58/////////////////////////////////////////////
59error_t fatfs_get_cluster( mapper_t * mapper,
60                           uint32_t   first_cluster,
61                           uint32_t   searched_page,
62                           uint32_t * cluster )
63{
64    page_t   * current_page_desc;      // pointer on current page descriptor
65    uint32_t * current_page_buffer;    // pointer on current page (array of uint32_t)
66    uint32_t   current_page_index;     // index of current page in mapper
67    uint32_t   current_page_offset;    // offset of slot in current page
68    uint32_t   page_count_in_file;     // index of page in file (index in linked list)
69    uint32_t   current_cluster;        // content of current FAT slot
70
71    // compute number of FAT slots per PPM page
72    uint32_t slots_per_page = CONFIG_PPM_PAGE_SIZE >> 2;
73
74    // initialize loop variable
75    current_page_index  = first_cluster / slots_per_page;
76    current_page_offset = first_cluster % slots_per_page;
77    page_count_in_file  = 0;
78
79    // scan FAT (i.e. traverse FAT linked list)
80    while( page_count_in_file <= searched_page )
81    {
82        // get pointer on current page descriptor
83        current_page_desc = mapper_get_page( mapper , current_page_index );
84
85        if( current_page_desc == NULL ) return EIO;
86
87        // get pointer on buffer for current page
[53]88        current_page_buffer = (uint32_t *)ppm_page2vaddr( current_page_desc );
[1]89
90        // get FAT slot content
91        current_cluster = current_page_buffer[current_page_offset];
92
93        // update loop variables
94        current_page_index  = current_cluster / slots_per_page;
95        current_page_offset = current_cluster % slots_per_page;
96        page_count_in_file++;
97    }
98   
99    // return success
100    *cluster = current_cluster;
101    return 0;
102
103}  // end fatfs_get_cluster()
104
[23]105///////////////////////////////////////////////////////////////////////////////////////
106// This static function return an integer record value (one, two, or four bytes)
107// from a memory buffer, taking into account endianness.
108///////////////////////////////////////////////////////////////////////////////////////
109// @ offset        : first byte of record in buffer.
110// @ size          : record length in bytes (1/2/4).
111// @ buffer        : pointer on buffer base.
112// @ little endian : the most significant byte has the highest address when true.
113// @ return the integer value in a 32 bits word.
114///////////////////////////////////////////////////////////////////////////////////////
115static uint32_t get_record_from_buffer( uint32_t    offset,
116                                        uint32_t    size,
117                                        uint8_t   * buffer,
118                                        uint32_t    little_endian )
119{
120    uint32_t n;
121    uint32_t res  = 0;
[1]122
[23]123    if ( little_endian)
124    {
125        for( n = size ; n > 0 ; n-- ) res = (res<<8) | buffer[offset+n-1];
126    }
127    else
128    {
129        for( n = 0 ; n < size ; n++ ) res = (res<<8) | buffer[offset+n];
130    }
131    return res;
132
133}  // end get_record_from_buffer()
134
135
136
[1]137////////////////////////////////////////////////////////////////////////////////////////
138// This function returns the FATFS cluster index of a page identified by its page
139// index in the file, using the FAT mapper. It scans the FAT mapper, starting from the
140// FATFS cluster index allocated to the first page of the file, until it reaches the
141// searched page. The FAT mapper is automatically updated in case of miss.
142// This function can be called by any thread running in any cluster, as it uses the
143// RPC_FATFS_GET_CLUSTER to access the remote FAT mapper if required.
144// We use a RPC to scan the FAT because the RPC_FIFO will avoid contention
145// in the cluster containing the FAT mapper, and the RPC latency is not critical
146// compared to the device access latency.
147////////////////////////////////////////////////////////////////////////////////////////
148// @ ctx               : pointer on local FATFS context.
149// @ first_cluster : first cluster allocated to a file in FATFS.
150// @ page_index    : index of searched page in file (one page occupies one cluster).
151// @ cluster_index : [out] pointer on buffer for FATFS cluster index.
152// @ return 0 if success / return EIO if a FAT cluster miss cannot be solved.
153////////////////////////////////////////////////////////////////////////////////////////
154static error_t fatfs_cluster_from_index( fatfs_ctx_t * ctx,
155                                         uint32_t      first_cluster,
156                                         uint32_t      page_index,
157                                         uint32_t    * cluster_index )
158{
159    uint32_t searched_cluster;   // searched FATFS cluster index
160    error_t  error;
161
162    // get extended pointer on FAT mapper
163    xptr_t fat_mapper_xp = ctx->fat_mapper_xp;
164
165    // get cluster cxy and local pointer on FAT mapper
166    cxy_t      fat_mapper_cxy = GET_CXY( fat_mapper_xp );
167    mapper_t * fat_mapper_ptr = (mapper_t *)GET_PTR( fat_mapper_xp );
168
169    if( fat_mapper_cxy == local_cxy )    // FAT mapper is local
170    {
171        error = fatfs_get_cluster( fat_mapper_ptr,
172                                   first_cluster,
173                                   page_index,
174                                   &searched_cluster );
175    }
176    else                                 // FAT mapper is remote
177    {
178        rpc_fatfs_get_cluster_client( fat_mapper_cxy,
179                                      fat_mapper_ptr,
180                                      first_cluster,
181                                      page_index,
182                                      &searched_cluster,
183                                      &error );
184    }
185   
186    if( error )
187    {
188        printk("\n[ERROR] in %s : cannot access FAT\n", __FUNCTION__ );
189        return error;
190    }
191
192    // return success
193    *cluster_index = searched_cluster;
194    return 0;
195
196}  // end fatfs_cluster_from_index()
197
198
199
200
201///////////////////////////////////////////////////////////////////////////////////////
[23]202//          The following functions are called by the VFS.
[1]203///////////////////////////////////////////////////////////////////////////////////////
204
[23]205
206///////////////////
207xptr_t fatfs_init()
[1]208{
[23]209    kmem_req_t    req;
210    fatfs_ctx_t * fatfs_ctx;       // local pointer on FATFS context
211    vfs_ctx_t   * vfs_ctx;         // local pointer on VFS context
212    xptr_t        root_inode_xp;   // extended pointer on root inode
213    error_t       error;
[1]214
[23]215    // get local pointer on VFS context for FATFS
216    vfs_ctx = &fs_context[FS_TYPE_FATFS];
217
218    // get number of kernel instances and extended pointer on global barrier
219    cluster_t * cluster     = LOCAL_CLUSTER;
220    uint32_t    nb_clusters = cluster->x_size * cluster->y_size;
221    xptr_t      barrier_xp  = XPTR( cluster->io_cxy , &global_barrier );
222
223    ///// step 1 : all clusters allocate memory for FATFS context
224
225    // allocate memory for FATFS context extension
226        req.type    = KMEM_FATFS_CTX;
227        req.size    = sizeof(fatfs_ctx_t);
228    req.flags   = AF_KERNEL | AF_ZERO;
229        fatfs_ctx   = (fatfs_ctx_t *)kmem_alloc( &req );
230
231    if( fatfs_ctx == NULL ) 
232    {
233        printk("\n[PANIC] in %s : no memory for FATFS context\n", __FUNCTION__ );
234        hal_core_sleep();
235    }
236   
237    ///// step 2 : only cluster_0 access device and creates root inode
238
239    if( local_cxy == 0 )
240    {
241        // create VFS root inode
242        error = vfs_inode_create( XPTR_NULL,        // no parent dentry
243                                  FS_TYPE_FATFS,
244                                  INODE_TYPE_DIR,
245                                  0,                // attr
246                                  0,                // rights
247                                  0,                // uid
248                                  0,                // gid
249                                  &root_inode_xp );
250
251        assert( (error == 0 ) , __FUNCTION__ , "cannot create VFS root inode" );
252
253        // initialize VFS context / access device to initialize FATFS context
254        error = fatfs_ctx_init( vfs_ctx,
255                                fatfs_ctx,
256                                root_inode_xp );
257
258        // create FATFS root inode
259        error = fatfs_inode_create( GET_PTR( root_inode_xp ) , 
260                                    fatfs_ctx->root_dir_cluster );
261
262        if( error )
263        {
264            printk("\n[PANIC] in %s : cannot create FATFS root inode\n", __FUNCTION__ );
265            hal_core_sleep();
266        }
267
268    }
269
270    //////////////// synchronize all clusters
271    remote_barrier( barrier_xp , nb_clusters );
272
273    ///// step 3 : all others clusters initialize both context and extension
274
275    if( local_cxy != 0 )
276    {
277        // copy VFS context from remote cluster_0 to local cluster
278        hal_remote_memcpy( XPTR( local_cxy , vfs_ctx ), 
279                           XPTR( 0 , vfs_ctx ),
280                           sizeof(vfs_ctx_t) );
281
282        // copy FATFS context from remote cluster_0 to local cluster
283        hal_remote_memcpy( XPTR( local_cxy , fatfs_ctx ), 
284                           XPTR( 0 , vfs_ctx->extend ) ,
285                           sizeof(fatfs_ctx_t) );
286
287        // update extend field in local copy of VFS context
288        vfs_ctx->extend = fatfs_ctx;
289    }
290
291    return root_inode_xp;
292
293}  // end fatfs_init()
294
295//////////////////////////////////////////////
296error_t fatfs_ctx_init( vfs_ctx_t   * vfs_ctx,
297                        fatfs_ctx_t * fatfs_ctx,
298                        xptr_t        root_inode_xp )
299{
[50]300    error_t     error;
301    uint8_t   * buffer;
302    kmem_req_t  req;
[23]303
[50]304    // allocate a 512 bytes buffer to store the boot record
305        req.type    = KMEM_512_BYTES;
306    req.flags   = AF_KERNEL | AF_ZERO;
307        buffer      = (uint8_t *)kmem_alloc( &req );
308     
309    fatfs_dmsg("\n[INFO] %s : enters with buffer = %x\n", 
310               __FUNCTION__ , (intptr_t)buffer );
311
312    // load the boot record from device
313    // using a synchronous access to IOC device 
[23]314    error = dev_ioc_sync_read( buffer , 0 , 1 );
315
[50]316    assert( (error == 0) , __FUNCTION__ , "cannot access boot record" );
317
[68]318#if CONFIG_FATFS_DEBUG
[50]319    uint32_t   line;
320    uint32_t   byte = 0;
[101]321    printk("\n*** boot record at cycle %d ***\n", hal_get_cycles() );
[50]322    for ( line = 0 ; line < 32 ; line++ )
323    {
324        printk(" %X | %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x |\n",
325               byte,
326               buffer[byte+ 0],buffer[byte+ 1],buffer[byte+ 2],buffer[byte+ 3],
327               buffer[byte+ 4],buffer[byte+ 5],buffer[byte+ 6],buffer[byte+ 7],
328               buffer[byte+ 8],buffer[byte+ 9],buffer[byte+10],buffer[byte+11],
329               buffer[byte+12],buffer[byte+13],buffer[byte+14],buffer[byte+15] );
330
331         byte += 16;
332    }
333#endif
334
[23]335    // check sector size from boot record
336    uint32_t sector_size = get_record_from_buffer( BPB_BYTSPERSEC , buffer , 1 );
[50]337
[23]338    assert( (sector_size == 512) , __FUNCTION__ , "sector size must be 512 bytes" );
339
340    // check cluster size from boot record
341    uint32_t nb_sectors = get_record_from_buffer( BPB_SECPERCLUS , buffer , 1 );
[50]342
[23]343    assert( (nb_sectors == 8) , __FUNCTION__ , "cluster size must be 8 sectors" );
344
345    // check number of FAT copies from boot record
346    uint32_t nb_fats = get_record_from_buffer( BPB_NUMFATS , buffer , 1 );
[50]347
[23]348    assert( (nb_fats == 1) , __FUNCTION__ , "number of FAT copies must be 1" );
349
350    // get & check number of sectors in FAT from boot record
351    uint32_t fat_sectors = get_record_from_buffer( BPB_FAT32_FATSZ32 , buffer , 1 );
[50]352
[23]353    assert( ((fat_sectors & 0xF) == 0) , __FUNCTION__ , "FAT not multiple of 16 sectors");
354
355    // get and check root cluster from boot record
356    uint32_t root_cluster = get_record_from_buffer( BPB_FAT32_ROOTCLUS , buffer , 1 );
[50]357
[23]358    assert( (root_cluster == 2) , __FUNCTION__ , "Root cluster index must be  2");
359
360    // get FAT lba from boot record
361    uint32_t fat_lba = get_record_from_buffer( BPB_RSVDSECCNT , buffer , 1 );
[50]362
363    // release the 512 bytes buffer
364    req.type = KMEM_512_BYTES;
365    req.ptr  = buffer;
366    kmem_free( &req );
367
[23]368    // allocate a mapper for the FAT itself
369    mapper_t * fat_mapper = mapper_create();
[50]370
[23]371    assert( (fat_mapper != NULL) , __FUNCTION__ , "no memory for FAT mapper" );
372
373    // initialize the FATFS context
374    fatfs_ctx->fat_begin_lba         = fat_lba;
375    fatfs_ctx->fat_sectors_count     = fat_sectors; 
376    fatfs_ctx->bytes_per_sector      = sector_size;
377    fatfs_ctx->bytes_per_cluster     = sector_size * nb_sectors;
378    fatfs_ctx->cluster_begin_lba     = fat_lba + fat_sectors;
379    fatfs_ctx->root_dir_cluster      = 2;
380    fatfs_ctx->last_allocated_sector = 0;    // TODO ???
381    fatfs_ctx->last_allocated_index  = 0;    // TODO ???
382    fatfs_ctx->fat_mapper_xp         = XPTR( local_cxy , fat_mapper );
383
[50]384    fatfs_dmsg("\n*** FAT context ***\n" 
385               "- fat_sectors     = %d\n"
386               "- sector size     = %d\n"
387               "- cluster size    = %d\n"
388               "- fat_first_lba   = %d\n"
389               "- data_first_lba  = %d\n"
390               "- mapper          = %l\n",
391               fatfs_ctx->fat_sectors_count,
392               fatfs_ctx->bytes_per_sector,
393               fatfs_ctx->bytes_per_cluster,
394               fatfs_ctx->fat_begin_lba,
395               fatfs_ctx->cluster_begin_lba,
396               fatfs_ctx->fat_mapper_xp );
397
[23]398    // initialize the VFS context
399    vfs_ctx->type    = FS_TYPE_FATFS;
400    vfs_ctx->attr    = 0;                    // not READ_ONLY / not SYNC
401    vfs_ctx->count   = fat_sectors << 10;    // total number of sectors in data region
402    vfs_ctx->blksize = 512;                  // number of bytes per sector
403    vfs_ctx->root_xp = root_inode_xp;
404    vfs_ctx->extend  = fatfs_ctx;
405
406    spinlock_init( &vfs_ctx->lock );
407
408    bitmap_init( vfs_ctx->bitmap , CONFIG_VFS_MAX_INODES );
409
410    return 0;
411
412}  // end fatfs_ctx_init()
413 
414
415
416////////////////////////////////////////////////////
417void fatfs_ctx_destroy( struct vfs_ctx_s * vfs_ctx )
418{
419    kmem_req_t    req;
420    fatfs_ctx_t * fatfs_ctx;
421
422    // get pointer on FATFS context extension
423    fatfs_ctx = (fatfs_ctx_t *)vfs_ctx->extend;
424
425    req.type = KMEM_FATFS_INODE;
426    req.ptr  = fatfs_ctx;
427    kmem_free( &req );
428}
429
430
431////////////////////////////////////////////////////
432error_t fatfs_inode_create( vfs_inode_t * vfs_inode,
433                            uint32_t      first_cluster )
434{
[1]435    kmem_req_t      req;
436    fatfs_inode_t * fatfs_inode;
437
[23]438    // allocate memory for FATFS inode extension
[1]439        req.type    = KMEM_FATFS_INODE;
440        req.size    = sizeof(fatfs_inode_t);
441    req.flags   = AF_KERNEL | AF_ZERO;
442        fatfs_inode = (fatfs_inode_t *)kmem_alloc( &req );
443
444    if( fatfs_inode == NULL ) return ENOMEM;
445
[23]446    // link FATFS inode to VFS inode
[1]447    vfs_inode->extend = fatfs_inode;
448
[23]449    // initialise FATFS inode
450    fatfs_inode->first_cluster = first_cluster;
451 
[1]452    return 0;
453}
454
[23]455///////////////////////////////////////////////////
456void fatfs_inode_destroy( vfs_inode_t * vfs_inode )
[1]457{
[23]458    kmem_req_t      req;
459    fatfs_inode_t * fatfs_inode;
[1]460
[23]461    // get pointer on FATFS inode
462    fatfs_inode = (fatfs_inode_t *)vfs_inode->extend;
[1]463
[23]464    req.type = KMEM_FATFS_INODE;
465    req.ptr  = fatfs_inode;
466    kmem_free( &req );
[1]467
[23]468        vfs_inode->extend = NULL;
[1]469}
470
[23]471
[1]472////////////////////////////////////////////////
473static error_t fatfs_access_page( page_t * page,
474                                  bool_t   is_read )
475{
[23]476    // get memory buffer base address
[53]477    uint8_t * buffer = (uint8_t *)ppm_page2vaddr( page );
[1]478 
479    // get pointer on source mapper and page index from page descriptor
[23]480    mapper_t * mapper      = page->mapper;
[1]481    uint32_t   page_index  = page->index;
482
483    // get VFS inode pointer from mapper
[23]484    vfs_inode_t * vfs_inode = mapper->inode;
[1]485
486    // get FATFS inode pointer for VFS inode
487    fatfs_inode_t * fatfs_inode = (fatfs_inode_t *)vfs_inode->extend;
488
489    // get first cluster index from FATFS inode
490    uint32_t  first_cluster = fatfs_inode->first_cluster;
491
492    // get FATFS context pointer from FATFS inode
[23]493    fatfs_ctx_t * fatfs_ctx = (fatfs_ctx_t *)vfs_inode->ctx->extend;
[1]494
495    // get number of sectors
496    uint32_t count = fatfs_ctx->sectors_per_cluster;
497
498    // compute FATFS_cluster index for the accessed page
[10]499    uint32_t cluster = 0;
[1]500    error_t  error = fatfs_cluster_from_index( fatfs_ctx,
501                                               first_cluster,
502                                               page_index,
503                                               &cluster );
504    if( error ) return EIO;
505
506    // get lba from cluster
507    uint32_t lba = fatfs_lba_from_cluster( fatfs_ctx , cluster );
508
509    // access device
510    if( is_read ) error = dev_ioc_read ( buffer , lba , count );
511    else          error = dev_ioc_write( buffer , lba , count );     
512
513    if( error )
514    {
515        printk("\n[ERROR] in %s : cannot access IOC device\n", __FUNCTION__ );
516        return error;
517    } 
518
519    // successful access
520    return 0;
521}
522
523////////////////////////////////////////////////
524error_t fatfs_write_page( struct page_s * page )
525{
526    bool_t is_read = false;
527    return fatfs_access_page( page , is_read );
528}
529
530///////////////////////////////////////////////
531error_t fatfs_read_page( struct page_s * page )
532{
533    bool_t is_read = true;
534    return fatfs_access_page( page , is_read );
535}
536
Note: See TracBrowser for help on using the repository browser.