source: trunk/kernel/fs/fatfs.c @ 612

Last change on this file since 612 was 612, checked in by alain, 5 years ago

Fix several bugs in vfs.c, fatfs.c, and devfs.c to support
the <.> and <..> directory entries.

File size: 80.5 KB
Line 
1/*
2 * fatfs.c - FATFS file system API implementation.
3 *
4 * Author    Alain Greiner (2016,2017,2018)
5 *
6 * Copyright (c) UPMC Sorbonne Universites
7 *
8 * This file is part of ALMOS-MKH.
9 *
10 * ALMOS-MKH is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; version 2.0 of the License.
13 *
14 * ALMOS-MKH is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with ALMOS-MKH; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24
25#include <hal_kernel_types.h>
26#include <hal_special.h>
27#include <printk.h>
28#include <thread.h>
29#include <kmem.h>
30#include <ppm.h>
31#include <vfs.h>
32#include <string.h>
33#include <rpc.h>
34#include <mapper.h>
35#include <cluster.h>
36#include <dev_ioc.h>
37#include <fatfs.h>
38
39
40//////////////////////////////////////////////////////////////////////////////////////////
41//          Extern  variables         
42//////////////////////////////////////////////////////////////////////////////////////////
43
44extern vfs_ctx_t     fs_context[FS_TYPES_NR];   // allocated in kernel_init.c file
45
46//////////////////////////////////////////////////////////////////////////////////////////
47//              FATFS specific static functions
48//////////////////////////////////////////////////////////////////////////////////////////
49
50//////////////////////////////////////////////////////////////////////////////////////////
51// These functions return the "offset" and "length" values of an
52// [offset,length] constant defined in the fatfs.h file.
53//////////////////////////////////////////////////////////////////////////////////////////
54
55static inline int get_length( int offset __attribute__((unused)), int length ) { return length; }
56
57static inline int get_offset( int offset, int length __attribute__((unused)) ) { return offset; }
58
59//////////////////////////////////////////////////////////////////////////////////////////
60// This static function returns the LBA of the first sector of a FAT cluster.
61// This function can be called by any thread running in any cluster.
62//////////////////////////////////////////////////////////////////////////////////////////
63// @ ctx          :     pointer on FATFS context.
64// @ cluster  : cluster index in FATFS.
65// @ return the lba value.
66//////////////////////////////////////////////////////////////////////////////////////////
67static inline uint32_t fatfs_lba_from_cluster( fatfs_ctx_t * ctx,
68                                               uint32_t      cluster )
69{
70    return (ctx->cluster_begin_lba + ((cluster - 2) << 3));
71}
72
73//////////////////////////////////////////////////////////////////////////////////////////
74// This function return an integer record value (one, two, or four bytes)
75// from a memory buffer, taking into account endianness.
76//////////////////////////////////////////////////////////////////////////////////////////
77// @ offset        : first byte of record in buffer.
78// @ size          : record length in bytes (1/2/4).
79// @ buffer        : pointer on buffer base.
80// @ little endian : the most significant byte has the highest address when true.
81// @ return the integer value in a 32 bits word.
82//////////////////////////////////////////////////////////////////////////////////////////
83static uint32_t fatfs_get_record( uint32_t    offset,
84                                  uint32_t    size,
85                                  uint8_t   * buffer,
86                                  uint32_t    little_endian )
87{
88    uint32_t n;
89    uint32_t res  = 0;
90
91    if ( little_endian )
92    {
93        for( n = size ; n > 0 ; n-- ) res = (res<<8) | buffer[offset+n-1];
94    }
95    else // big_endian
96    {
97        for( n = 0 ; n < size ; n++ ) res = (res<<8) | buffer[offset+n];
98    }
99    return res;
100
101}  // end fatfs_get_record()
102
103//////////////////////////////////////////////////////////////////////////////////////////
104// This function writes one, two, or four bytes from a 32 bits integer to a memory buffer,
105// taking into account endianness.
106//////////////////////////////////////////////////////////////////////////////////////////
107// @ offset        : first byte of record in buffer.
108// @ size          : record length in bytes (1/2/4).
109// @ buffer        : pointer on buffer base.
110// @ little endian : the most significant byte has the highest address when true.
111// @ return the integer value in a 32 bits word.
112//////////////////////////////////////////////////////////////////////////////////////////
113static void fatfs_set_record( uint32_t    offset,
114                              uint32_t    size,
115                              uint8_t   * buffer,
116                              uint32_t    little_endian,
117                              uint32_t    value )
118{
119    uint32_t n;
120
121    if ( little_endian )
122    {
123        for( n = size ; n > 0 ; n-- ) buffer[offset+n-1] = (uint8_t)(value>>((n-1)<<3));
124    }
125    else // big_endian
126    {
127        for( n = 0 ; n < size ; n++ ) buffer[offset+n] = (uint8_t)(value>>((size-1-n)<<3));
128    }
129
130}  // end fatfs_set_record()
131
132//////////////////////////////////////////////////////////////////////////////////////////
133// This static function retun in the <name> buffer a short name stored in
134// a SFN FATFS directory entry.
135/////////////////////////i////////////////////////////////////////////////////////////////
136// @ buffer   : pointer on buffer containing the directory entry.
137// @ name     : [out] buffer allocated by the caller.
138//////////////////////////////////////////////////////////////////////////////////////////
139static void fatfs_get_name_from_short( uint8_t * buffer,
140                                       char    * name )
141{
142    uint32_t i;
143    uint32_t j = 0;
144
145    // get name
146    for ( i = 0; i < 8 && buffer[i] != ' '; i++ )
147    {
148        name[j] = to_lower( buffer[i] );
149        j++;
150    }
151
152    // get extension
153    for ( i = 8; i < 8 + 3 && buffer[i] != ' '; i++ )
154    {
155        // we entered the loop so there is an extension. add the dot
156        if ( i == 8 )
157        {
158            name[j] = '.';
159            j++;
160        }
161
162        name[j] = to_lower( buffer[i] );
163        j++;
164    }
165
166    name[j] = '\0';
167
168}  // fatfs_get_name_from_short()
169
170//////////////////////////////////////////////////////////////////////////////////////////
171// This static function retun in the <name> buffer a partial name stored in
172// a LFN FATFS directory entry.
173/////////////////////////i////////////////////////////////////////////////////////////////
174// @ buffer   : pointer on buffer containing the directory entry.
175// @ name     : [out] buffer allocated by the caller.
176//////////////////////////////////////////////////////////////////////////////////////////
177static void fatfs_get_name_from_long( uint8_t * buffer,
178                                      char    * name )
179{
180    uint32_t   name_offset   = 0;
181    uint32_t   buffer_offset = get_length(LDIR_ORD);
182    uint32_t   l_name_1      = get_length(LDIR_NAME_1);
183    uint32_t   l_name_2      = get_length(LDIR_NAME_2);
184    uint32_t   l_name_3      = get_length(LDIR_NAME_3);
185    uint32_t   l_attr        = get_length(LDIR_ATTR);
186    uint32_t   l_type        = get_length(LDIR_TYPE);
187    uint32_t   l_chksum      = get_length(LDIR_CHKSUM);
188    uint32_t   l_rsvd        = get_length(LDIR_RSVD);
189
190    uint32_t   j             = 0;
191    uint32_t   eof           = 0;
192
193    while ( (buffer_offset != DIR_ENTRY_SIZE)  && (!eof) )
194    {
195        while (j != l_name_1 && !eof )
196        {
197            if ( (buffer[buffer_offset] == 0x00) || 
198                 (buffer[buffer_offset] == 0xFF) )
199            {
200                eof = 1;
201                continue;
202            }
203            name[name_offset] = buffer[buffer_offset];
204            buffer_offset += 2;
205            j += 2;
206            name_offset++;
207        }
208
209        buffer_offset += (l_attr + l_type + l_chksum);
210        j = 0;
211
212        while (j != l_name_2 && !eof )
213        {
214            if ( (buffer[buffer_offset] == 0x00) || 
215                 (buffer[buffer_offset] == 0xFF) )
216            {
217                eof = 1;
218                continue;
219            }
220            name[name_offset] = buffer[buffer_offset];
221            buffer_offset += 2;
222            j += 2;
223            name_offset++;
224        }
225
226        buffer_offset += l_rsvd;
227        j = 0;
228
229        while (j != l_name_3 && !eof )
230        {
231            if ( (buffer[buffer_offset] == 0x00) || 
232                 (buffer[buffer_offset] == 0xFF) )
233            {
234                eof = 1;
235                continue;
236            }
237            name[name_offset] = buffer[buffer_offset];
238            buffer_offset += 2;
239            j += 2;
240            name_offset++;
241        }
242    }
243    name[name_offset] = 0;
244
245} // end fatfs_get_name_from_long()
246
247//////////////////////////////////////////////////////////////////////////////////////////
248// This static function analyse the <name> input argument, and returns in other
249// output arguments various informations required to store the name in FATFS directory.
250// The <name> length cannot be larger than 31 characters :
251// - Short name (less than 13 characters) require 1 LFN entry.
252// - Medium names (from 14 to 26 characters require 2 LFN entries.
253// - Large names (up to 31 characters) require 3 LFN entries.
254//////////////////////////////////////////////////////////////////////////////////////////
255// @ name     : [in]  complete directory entry name.
256// @ length   : [out] total number of characters in name.
257// @ nb_lfn   : [out] number of LFN entries required to store the name.
258// @ sfn      : [out] a legal SFN name extracted from name / upper case and 8-3 format.
259// @ checksum : [out] checksum to be stored in SFN.
260// @ returns 0 on success / returns 1 if the name length is larger than 31 characters.
261//////////////////////////////////////////////////////////////////////////////////////////
262static error_t fatfs_name_format( const char  * name,
263                                  uint32_t    * length,
264                                  uint32_t    * nb_lfn,
265                                  char        * sfn,
266                                  uint8_t     * checksum )
267{
268    // compute name length
269    uint32_t name_length = strlen( name );
270    *length = name_length;
271
272    uint32_t suffix_length = 0;
273    uint32_t prefix_length = 0;
274    uint32_t dot_found     = 0;
275    uint32_t i;
276
277    // compute prefix and suffix length
278    // only the last '.' is taken into account
279    for ( i=0 ; i<name_length ; i++ )
280    {
281        if (name[i] == '.' )
282        {
283            if ( dot_found ) 
284            {
285                prefix_length += suffix_length + 1;
286                suffix_length =  0;
287            }
288            else
289            {
290                dot_found = 1;
291            }
292        }
293        else
294        { 
295            if ( dot_found)  suffix_length++;
296            else             prefix_length++;
297        }
298    } 
299
300    // build SFN prefix (8bits)
301    if (prefix_length <= 8)
302    {
303        for( i=0 ; i<8 ; i++)
304        {
305            if ( i<prefix_length ) sfn[i] = to_upper( name[i] );
306            else                   sfn[i] = 0x20;
307        }
308    }
309    else
310    {
311        for( i=0 ; i<6 ; i++)
312        {
313            sfn[i] = to_upper( name[i] );
314        }
315        sfn[6] = 0x7E;
316        sfn[7] = 0x31;
317    }
318
319    // build SFN suffix (3 bits)
320    if ( suffix_length == 0 )
321    {
322        sfn[8]  = 0x20;
323        sfn[9]  = 0x20;
324        sfn[10] = 0x20;
325    }
326    else if ( suffix_length == 1 )
327    {
328        sfn[8]  = to_upper( name[name_length-1] );
329        sfn[9]  = 0x20;
330        sfn[10] = 0x20;
331    }
332    else if ( suffix_length == 2 )
333    {
334        sfn[8]  = to_upper( name[name_length-2] );
335        sfn[9]  = to_upper( name[name_length-1] );
336        sfn[10] = 0x20;
337    }
338    else
339    {
340        sfn[8]  = to_upper( name[name_length-suffix_length] );
341        sfn[9]  = to_upper( name[name_length-suffix_length+1] );
342        sfn[10] = to_upper( name[name_length-suffix_length+2] );
343    }
344
345    // compute 8 bits checksum
346    uint8_t sum = 0;
347    for ( i=0 ; i<11 ; i++ )
348    {
349        sum = (((sum & 0x01)<<7) | ((sum & 0xFE)>>1)) + sfn[i];
350    }
351    *checksum = sum;
352
353    // set nb_lfn and length values
354    if      ( name_length <= 13 )
355    {
356        *nb_lfn  = 1;
357        return 0;
358    }
359    else if ( name_length <= 26 )
360    {
361        *nb_lfn  = 2;
362        return 0;
363    }
364    else if ( name_length <= 31 )
365    {
366        *nb_lfn  = 3;
367        return 0;
368    }
369    else
370    {
371        return 1;
372    }
373}   // end fatfs_name_format() 
374
375//////////////////////////////////////////////////////////////////////////////////////////
376// This static function - atomically - decrements "free_clusters", and updates
377// the "free_cluster_hint" shared variables in the FATFS context in the FAT cluster.
378// It scan the FAT to find the first free slot larger than the <cluster> argument,
379// and set "free_cluster_hint" <= (free - 1).
380//
381// WARNING : The free_lock protecting exclusive access to these variables
382//           must be taken by the calling function.
383//////////////////////////////////////////////////////////////////////////////////////////
384// @ cluster     : recently allocated cluster index in FAT.
385//////////////////////////////////////////////////////////////////////////////////////////
386static error_t fatfs_free_clusters_decrement( uint32_t  cluster )
387{
388    fatfs_ctx_t * loc_ctx;      // local pointer on local FATFS context
389    fatfs_ctx_t * fat_ctx;      // local pointer on FATFS in cluster containing FAT mapper
390    cxy_t         mapper_cxy;   // cluster identifier for cluster containing FAT mapper
391    xptr_t        mapper_xp;    // extended pointer on FAT mapper
392    xptr_t        hint_xp;      // extended pointer on "free_cluster_hint" shared variable
393    xptr_t        numb_xp;      // extended pointer on "free_clusters" shared variable
394    uint32_t      numb;         // "free_clusters" variable current value
395    uint32_t      page_id;      // page index in FAT mapper
396    uint32_t      slot_id;      // slot index in one page of FAT (1024 slots per page)
397    uint32_t      page_max;     // max number of pages in FAT mapper
398    xptr_t        page_xp;      // extended pointer on current page in FAT mapper
399    xptr_t        slot_xp;      // extended pointer on current slot in FAT mapper
400
401#if DEBUG_FATFS_FREE_CLUSTERS
402uint32_t   cycle = (uint32_t)hal_get_cycles();
403thread_t * this  = CURRENT_THREAD;
404if( DEBUG_FATFS_FREE_CLUSTERS < (uint32_t)hal_get_cycles() )
405printk("\n[%s] thread[%x,%x] enter for allocated cluster %x / cycle %d\n",
406__FUNCTION__, this->process->pid, this->trdid, cluster , cycle );
407#endif
408
409    // get local pointer on local FATFS context
410    loc_ctx = fs_context[FS_TYPE_FATFS].extend;
411
412    // get cluster containing FAT mapper
413    mapper_xp  = loc_ctx->fat_mapper_xp;
414    mapper_cxy = GET_CXY( mapper_xp ); 
415
416    // get local pointer on FATFS context in FAT cluster
417    fat_ctx = hal_remote_lpt( XPTR( mapper_cxy , &fs_context[FS_TYPE_FATFS].extend ) );
418
419    // build extended pointers on free_clusters, and free_cluster_hint
420    hint_xp = XPTR( mapper_cxy , &fat_ctx->free_cluster_hint );
421    numb_xp = XPTR( mapper_cxy , &fat_ctx->free_clusters );
422
423    // update "free_clusters"
424    numb = hal_remote_l32( numb_xp );
425    hal_remote_s32( numb_xp , numb - 1 );
426
427    // scan FAT mapper to find the first free slot > cluster
428    // and update "free_cluster_hint" as (free - 1)
429    page_id  = (cluster + 1) >> 10;
430    slot_id  = (cluster + 1) & 0x3FF;
431    page_max = (loc_ctx->fat_sectors_count >> 3);
432
433    // scan FAT mapper / loop on pages
434    while ( page_id < page_max )           
435    {
436        // get current page from mapper
437        page_xp = mapper_remote_get_page( mapper_xp , page_id );
438
439        if( page_xp == XPTR_NULL )
440        {
441            printk("\n[ERROR] in %s : cannot access FAT mapper\n", __FUNCTION__ );
442            return -1;
443        }
444
445        // scan FAT mapper / loop on slots
446        while ( slot_id < 1024 )
447        {
448            // get extended pointer on current slot
449            slot_xp = ppm_page2base( page_xp ) + (slot_id << 2);
450
451            // test FAT slot value
452            if ( hal_remote_l32( slot_xp ) == FREE_CLUSTER )
453            {
454                // update "free_cluster_hint" <= (free - 1)
455                hal_remote_s32( hint_xp , (page_id << 10) + slot_id - 1 );
456
457#if DEBUG_FATFS_FREE_CLUSTERS
458cycle = (uint32_t)hal_get_cycles();
459if( DEBUG_FATFS_FREE_CLUSTERS < (uint32_t)hal_get_cycles() )
460printk("\n[%s] thread[%x,%x] exit / hint %x / free_clusters %x / cycle %d\n",
461__FUNCTION__, this->process->pid, this->trdid,
462hal_remote_l32(hint_xp), hal_remote_l32(numb_xp), cycle );
463#endif
464                return 0;
465            }
466
467            // increment  slot_id
468            slot_id++;
469
470        }  // end loop on slots
471
472        // update loop variables
473        page_id++;
474        slot_id = 0;
475
476    }  // end loop on pages
477
478    // return error if no free cluster found
479    printk("\n[ERROR] in %s : No free cluster found\n", __FUNCTION__ );
480    return -1;
481   
482}  // end fatfs_free_clusters_decrement()
483
484//////////////////////////////////////////////////////////////////////////////////////////
485// This static function atomically increments <free_clusters>, and updates
486// the <free_cluster_hint> shared variables in the FATFS context in the FAT cluster.
487// If the released cluster index is smaller than the current (hint + 1) value,
488// it set "free_cluster_hint" <= cluster - 1.
489//
490// WARNING : The free_lock protecting exclusive access to these variables
491//           must be taken by the calling function.
492//////////////////////////////////////////////////////////////////////////////////////////
493// @ cluster     : recently released cluster index in FAT.
494//////////////////////////////////////////////////////////////////////////////////////////
495static void fatfs_free_clusters_increment( uint32_t  cluster )
496{
497    fatfs_ctx_t * loc_ctx;      // local pointer on local FATFS context
498    fatfs_ctx_t * fat_ctx;      // local pointer on FATFS in cluster containing FAT mapper
499    cxy_t         fat_cxy;      // cluster identifier for cluster containing FAT mapper
500    xptr_t        hint_xp;      // extended pointer on "free_cluster_hint" shared variable
501    xptr_t        numb_xp;      // extended pointer on "free_clusters" shared variable
502    uint32_t      hint;         // "free_cluster_hint" variable current value
503    uint32_t      numb;         // "free_clusters" variable current value
504
505    // get local pointer on local FATFS context
506    loc_ctx = fs_context[FS_TYPE_FATFS].extend;
507
508    // get cluster containing FAT mapper
509    fat_cxy = GET_CXY( loc_ctx->fat_mapper_xp );
510
511    // get local pointer on FATFS context in FAT cluster
512    fat_ctx = hal_remote_lpt( XPTR( fat_cxy , &fs_context[FS_TYPE_FATFS].extend ) );
513
514    // build extended pointers free_lock, free_clusters, and free_cluster_hint
515    hint_xp = XPTR( fat_cxy , &fat_ctx->free_cluster_hint );
516    numb_xp = XPTR( fat_cxy , &fat_ctx->free_clusters );
517
518    // get current value of free_cluster_hint and free_clusters
519    hint = hal_remote_l32( hint_xp );
520    numb = hal_remote_l32( numb_xp );
521
522    // update free_cluster_hint if required
523    if ( cluster < (hint + 1) ) hal_remote_s32( hint_xp , (cluster - 1) );
524
525    // update free_clusters
526    hal_remote_s32( numb_xp , numb + 1 );
527
528#if DEBUG_FATFS_FREE_CLUSTERS
529thread_t * this = CURRENT_THREAD;
530if( DEBUG_FATFS_FREE_CLUSTERS < (uint32_t)hal_get_cycles() )
531printk("\n[%s] thread[%x,%x] updates free cluster info : hint %x / number %x\n",
532__FUNCTION__, this->process->pid, this->trdid,
533hal_remote_l32( hint_xp ), hal_remote_l32( numb_xp ) );
534#endif
535
536}  // end fatfs_free_clusters_increment()
537
538//////////////////////////////////////////////////////////////////////////////////////////
539// This recursive function is called by the generic function fatfs_release_all_clusters()
540// It release all clusters allocated to a given inode in the FAT mapper.
541// The removal is done in reverse order of the linked list (from last to first).
542// It does NOT update the FS on the IOC device.
543//////////////////////////////////////////////////////////////////////////////////////////
544// @ fat_mapper_xp : extended pointer on FAT mapper.
545// @ cluster       : cluster index in FAT.
546// @ return 0 if success / return -1 if error (cannot access FAT)
547//////////////////////////////////////////////////////////////////////////////////////////
548static error_t fatfs_recursive_release( xptr_t    fat_mapper_xp,
549                                        uint32_t  cluster )
550{
551    uint32_t next;
552
553    // get next cluster from FAT mapper
554    if ( mapper_remote_get_32( fat_mapper_xp , cluster , &next ) ) return -1;
555
556#if (DEBUG_FATFS_RELEASE_INODE & 1)
557thread_t * this = CURRENT_THREAD;
558if ( DEBUG_FATFS_RELEASE_INODE < (uint32_t)hal_get_cycles() )
559printk("\n[%s] thread[%x,%x] access FAT for cluster %x / next %x\n",
560__FUNCTION__, this->process->pid, this->trdid, cluster, next );
561#endif
562
563    if ( next < END_OF_CHAIN_CLUSTER_MIN )  // non terminal case
564    {
565        // call fatfs_recursive_release() on next cluster
566        if ( fatfs_recursive_release( fat_mapper_xp , next ) ) return -1;
567    }       
568
569    // update current cluster in FAT mapper
570    if ( mapper_remote_set_32( fat_mapper_xp, cluster , FREE_CLUSTER ) ) return -1;
571
572    // Update free_cluster_hint and free_clusters in FAT context
573    fatfs_free_clusters_increment( cluster );
574
575    return 0;
576
577}  // end fatfs_recursive_release()
578
579
580//////////////////////////////////////////////////////////////////////////////////////////
581//              FATFS specific extern functions
582//////////////////////////////////////////////////////////////////////////////////////////
583
584//////////////////////////////
585void fatfs_ctx_display( void )
586{
587    // get pointer on local FATFS context
588    vfs_ctx_t   * vfs_ctx   = &fs_context[FS_TYPE_FATFS];
589    fatfs_ctx_t * fatfs_ctx = (fatfs_ctx_t *)vfs_ctx->extend;
590
591    printk("\n*** FAT context ***\n" 
592           "- fat_sectors       = %d\n"
593           "- sector size       = %d\n"
594           "- cluster size      = %d\n"
595           "- fat_first_lba     = %d\n"
596           "- data_first_lba    = %d\n"
597           "- root_dir_cluster  = %d\n"
598           "- free_clusters     = %d\n"
599           "- free_cluster_hint = %d\n"
600           "- fat_mapper_xp     = %l\n",
601           fatfs_ctx->fat_sectors_count,
602           fatfs_ctx->bytes_per_sector,
603           fatfs_ctx->sectors_per_cluster * fatfs_ctx->bytes_per_sector,
604           fatfs_ctx->fat_begin_lba,
605           fatfs_ctx->cluster_begin_lba,
606           fatfs_ctx->root_dir_cluster,
607           fatfs_ctx->free_clusters,
608           fatfs_ctx->free_cluster_hint,
609           fatfs_ctx->fat_mapper_xp );
610
611}  // end fatfs_ctx_display()
612
613//////////////////////////////////////////
614void fatfs_display_fat( uint32_t  page_id,
615                        uint32_t  nentries )
616{
617    uint32_t line;
618    uint32_t maxline;
619
620    // copute numner of lines to display
621    maxline = nentries >> 3;
622    if( nentries & 0x7 ) maxline++;
623
624    // get pointer on local FATFS context
625    vfs_ctx_t   * vfs_ctx   = &fs_context[FS_TYPE_FATFS];
626    fatfs_ctx_t * fatfs_ctx = (fatfs_ctx_t *)vfs_ctx->extend;
627
628    // get extended pointer on FAT mapper
629    xptr_t fat_mapper_xp = fatfs_ctx->fat_mapper_xp;
630
631    // get extended pointer and cluster of FAT mapper requested page
632    xptr_t     page_xp  = mapper_remote_get_page( fat_mapper_xp , page_id );
633
634    // get extended pointer on requested page base
635    xptr_t     base_xp  = ppm_page2base( page_xp );
636
637    printk("\n***** FAT content / page %d *****\n", page_id );
638    for( line = 0 ; line < maxline ; line++ )
639    {
640        printk("%x : %X | %X | %X | %X | %X | %X | %X | %X\n", (line<<3),
641        hal_remote_l32( base_xp + ((line<<5)      ) ),
642        hal_remote_l32( base_xp + ((line<<5) + 4  ) ),
643        hal_remote_l32( base_xp + ((line<<5) + 8  ) ),
644        hal_remote_l32( base_xp + ((line<<5) + 12 ) ),
645        hal_remote_l32( base_xp + ((line<<5) + 16 ) ),
646        hal_remote_l32( base_xp + ((line<<5) + 20 ) ),
647        hal_remote_l32( base_xp + ((line<<5) + 24 ) ),
648        hal_remote_l32( base_xp + ((line<<5) + 28 ) ) );
649    }
650
651}  // end fatfs_display_fat()
652
653///////////////////////////////////////////////////////
654error_t fatfs_get_cluster( uint32_t   first_cluster_id,
655                           uint32_t   searched_page_index,
656                           uint32_t * searched_cluster_id )
657{
658    xptr_t     current_page_xp;        // pointer on current page descriptor
659    uint32_t * buffer;                 // pointer on current page (array of uint32_t)
660    uint32_t   current_page_index;     // index of current page in FAT
661    uint32_t   current_page_offset;    // offset of slot in current page
662    uint32_t   page_count_in_file;     // index of page in file (index in linked list)
663    uint32_t   next_cluster_id;        // content of current FAT slot
664
665assert( (searched_page_index > 0) ,
666"no FAT access required for first page\n");
667
668#if DEBUG_FATFS_GET_CLUSTER
669uint32_t   cycle = (uint32_t)hal_get_cycles();
670thread_t * this  = CURRENT_THREAD;
671if( DEBUG_FATFS_GET_CLUSTER < cycle )
672printk("\n[%s] thread[%x,%x] enter / first_cluster_id %d / searched_index / cycle %d\n",
673__FUNCTION__, this->process->pid, this->trdid, first_cluster_id, searched_page_index, cycle );
674#endif
675
676    // get local pointer on local FATFS context
677    fatfs_ctx_t * ctx = fs_context[FS_TYPE_FATFS].extend;
678
679    // get extended pointer and cluster on FAT mapper
680    xptr_t mapper_xp  = ctx->fat_mapper_xp;
681    cxy_t  mapper_cxy = GET_CXY( mapper_xp );
682
683    // initialize loop variable (1024 slots per page)
684    current_page_index  = first_cluster_id >> 10;
685    current_page_offset = first_cluster_id & 0x3FF;
686    page_count_in_file  = 0;
687    next_cluster_id     = 0xFFFFFFFF;
688
689    // scan FAT (i.e. traverse FAT linked list)
690    while( page_count_in_file < searched_page_index )
691    {
692        // get pointer on current page descriptor
693        current_page_xp = mapper_remote_get_page( mapper_xp , current_page_index );
694
695        if( current_page_xp == XPTR_NULL )
696        {
697            // TODO
698            return -1;
699        }
700
701        // get pointer on buffer for current page
702        xptr_t base_xp = ppm_page2base( current_page_xp );
703        buffer = (uint32_t *)GET_PTR( base_xp );
704
705        // get FAT slot content
706        next_cluster_id = hal_remote_l32( XPTR( mapper_cxy , &buffer[current_page_offset] ) );
707
708#if (DEBUG_FATFS_GET_CLUSTER & 1)
709if( DEBUG_FATFS_GET_CLUSTER < cycle )
710printk("\n[%s] traverse FAT / current_page_index = %d\n"
711"current_page_offset = %d / next_cluster_id = %d\n",
712__FUNCTION__, current_page_index, current_page_offset , next_cluster_id );
713#endif
714
715        // update loop variables
716        current_page_index  = next_cluster_id >> 10;
717        current_page_offset = next_cluster_id & 0x3FF;
718        page_count_in_file++;
719    }
720
721    if( next_cluster_id == 0xFFFFFFFF ) return -1;
722   
723#if DEBUG_FATFS_GET_CLUSTER
724cycle = (uint32_t)hal_get_cycles();
725if( DEBUG_FATFS_GET_CLUSTER < cycle )
726printk("\n[%s] thread[%x,%x] exit / searched_cluster_id = %d / cycle %d\n",
727__FUNCTION__, this->process->pid, this->trdid, next_cluster_id / cycle );
728#endif
729
730    *searched_cluster_id = next_cluster_id;
731    return 0;
732
733}  // end fatfs_get_cluster()
734
735
736
737///////////////////////////////////////////////////////////////////////////////////////
738// Generic API : the following functions are called by the kernel VFS
739//               and must be defined by all supported file systems.
740///////////////////////////////////////////////////////////////////////////////////////
741
742/////////////////////////////////////
743fatfs_ctx_t * fatfs_ctx_alloc( void )
744{
745    kmem_req_t    req;
746        req.type    = KMEM_FATFS_CTX;
747        req.size    = sizeof(fatfs_ctx_t);
748    req.flags   = AF_KERNEL | AF_ZERO;
749
750        return (fatfs_ctx_t *)kmem_alloc( &req );
751}
752
753//////////////////////////////////////////////
754void fatfs_ctx_init( fatfs_ctx_t * fatfs_ctx )
755{
756    error_t       error;
757    kmem_req_t    req;
758    uint8_t     * buffer;
759
760#if DEBUG_FATFS_CTX_INIT
761uint32_t cycle = (uint32_t)hal_get_cycles();
762if( DEBUG_FATFS_CTX_INIT < cycle )
763printk("\n[%s] thread[%x,%x] enter for fatfs_ctx = %x / cycle %d\n",
764__FUNCTION__ , this->process->pid, this->trdid, fatfs_ctx , cycle );
765#endif
766
767// check argument
768assert( (fatfs_ctx != NULL) , "pointer on FATFS context is NULL\n" );
769
770// check only cluster 0 does FATFS init
771assert( (local_cxy == 0) , "only cluster 0 can initialize FATFS\n");
772
773    // allocate a 512 bytes buffer to store the boot record
774        req.type    = KMEM_512_BYTES;
775    req.flags   = AF_KERNEL | AF_ZERO;
776        buffer      = (uint8_t *)kmem_alloc( &req );
777
778    if( buffer == NULL ) 
779    {
780        printk("\n[PANIC] in %s : cannot allocate buffer\n", __FUNCTION__ );
781        hal_core_sleep();
782    }
783     
784    // load the BOOT record from device
785    error = dev_ioc_sync_read( buffer , 0 , 1 );
786
787    if ( error )
788    {
789        printk("\n[PANIC] in %s : cannot access boot record\n", __FUNCTION__ );
790        hal_core_sleep();
791    }
792
793#if (DEBUG_FATFS_CTX_INIT & 0x1)
794if( DEBUG_FATFS_CTX_INIT < cycle )
795{
796    uint32_t   line;
797    uint32_t   byte = 0;
798    printk("\n***** %s : FAT boot record\n", __FUNCTION__ );
799    for ( line = 0 ; line < 32 ; line++ )
800    {
801        printk(" %X | %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x |\n",
802               byte,
803               buffer[byte+ 0],buffer[byte+ 1],buffer[byte+ 2],buffer[byte+ 3],
804               buffer[byte+ 4],buffer[byte+ 5],buffer[byte+ 6],buffer[byte+ 7],
805               buffer[byte+ 8],buffer[byte+ 9],buffer[byte+10],buffer[byte+11],
806               buffer[byte+12],buffer[byte+13],buffer[byte+14],buffer[byte+15] );
807
808         byte += 16;
809    }
810}
811#endif
812
813    // get sector size from boot record
814    uint32_t sector_size = fatfs_get_record( BPB_BYTSPERSEC , buffer , 1 );
815    if ( sector_size != 512 )
816    {
817        printk("\n[PANIC] in %s : sector size must be 512 bytes\n", __FUNCTION__ );
818        hal_core_sleep();
819    }
820
821    // get cluster size from boot record
822    uint32_t nb_sectors = fatfs_get_record( BPB_SECPERCLUS , buffer , 1 );
823    if ( nb_sectors != 8 )
824    {
825        printk("\n[PANIC] in %s : cluster size must be 8 sectors\n", __FUNCTION__ );
826        hal_core_sleep();
827    }
828
829    // get number of FAT copies from boot record
830    uint32_t nb_fats = fatfs_get_record( BPB_NUMFATS , buffer , 1 );
831    if ( nb_fats != 1 )
832    {
833        printk("\n[PANIC] in %s : number of FAT copies must be 1\n", __FUNCTION__ );
834        hal_core_sleep();
835    }
836
837    // get number of sectors in FAT from boot record
838    uint32_t fat_sectors = fatfs_get_record( BPB_FAT32_FATSZ32 , buffer , 1 );
839    if ( (fat_sectors & 0xF) != 0 )
840    {
841        printk("\n[PANIC] in %s : FAT size not multiple of 16 sectors\n", __FUNCTION__ );
842        hal_core_sleep();
843    }
844
845    // get root cluster from boot record
846    uint32_t root_cluster = fatfs_get_record( BPB_FAT32_ROOTCLUS , buffer , 1 );
847    if ( root_cluster != 2 ) 
848    {
849        printk("\n[PANIC] in %s : root cluster index must be 2\n", __FUNCTION__ );
850        hal_core_sleep();
851    }
852
853    // get FAT lba from boot record
854    uint32_t fat_lba = fatfs_get_record( BPB_RSVDSECCNT , buffer , 1 );
855
856    // get FS_INFO sector lba from boot record
857    uint32_t fs_info_lba = fatfs_get_record( BPB_FAT32_FSINFO , buffer , 1 );
858
859    // load the FS_INFO record from device
860    error = dev_ioc_sync_read( buffer , fs_info_lba , 1 );
861
862    if ( error )
863    {
864        printk("\n[PANIC] in %s : cannot access FS_INFO record\n", __FUNCTION__ );
865        hal_core_sleep();
866    }
867
868    // get free clusters number from FS_INFO record
869    uint32_t free_clusters = fatfs_get_record( FS_FREE_CLUSTERS , buffer , 1 );
870    if ( free_clusters >= fat_sectors << 7 )
871    {
872        printk("\n[PANIC] in %s : unconsistent free_clusters\n", __FUNCTION__ );
873        hal_core_sleep();
874    }
875
876    // get cluster hint from FS_INFO record
877    uint32_t free_cluster_hint = fatfs_get_record( FS_FREE_CLUSTER_HINT , buffer , 1 );
878    if ( free_cluster_hint >= fat_sectors << 7 )
879    {
880        printk("\n[PANIC] in %s : unconsistent free_cluster_hint\n", __FUNCTION__ );
881        hal_core_sleep();
882    }
883
884    // release the 512 bytes buffer
885    req.type = KMEM_512_BYTES;
886    req.ptr  = buffer;
887    kmem_free( &req );
888
889    // allocate a mapper for the FAT itself
890    mapper_t * fat_mapper = mapper_create( FS_TYPE_FATFS );
891    if ( fat_mapper == NULL )
892    {
893        printk("\n[PANIC] in %s : no memory for FAT mapper\n", __FUNCTION__ );
894        hal_core_sleep();
895    }
896
897    // WARNING : the inode field MUST be NULL for the FAT mapper
898    fat_mapper->inode = NULL;
899
900    // initialize the FATFS context
901    fatfs_ctx->fat_begin_lba         = fat_lba;
902    fatfs_ctx->fat_sectors_count     = fat_sectors; 
903    fatfs_ctx->bytes_per_sector      = sector_size;
904    fatfs_ctx->sectors_per_cluster   = nb_sectors;
905    fatfs_ctx->cluster_begin_lba     = fat_lba + fat_sectors;
906    fatfs_ctx->root_dir_cluster      = 2;
907    fatfs_ctx->fat_mapper_xp         = XPTR( local_cxy , fat_mapper );
908    fatfs_ctx->free_clusters         = free_clusters;
909    fatfs_ctx->free_cluster_hint     = free_cluster_hint;
910
911    remote_queuelock_init( XPTR( local_cxy , &fatfs_ctx->free_lock ) , LOCK_FATFS_FREE );
912
913#if DEBUG_FATFS_CTX_INIT
914cycle = (uint32_t)hal_get_cycles();
915if( DEBUG_FATFS_CTX_INIT < cycle )
916printk("\n[%s]  thread[%x,%x] exit for fatfs_ctx = %x / cycle %d\n",
917__FUNCTION__, this->process->pid, this->trdid, fatfs_ctx, cycle );
918#endif
919
920}  // end fatfs_ctx_init()
921
922/////////////////////////////////////////////////
923void fatfs_ctx_destroy( fatfs_ctx_t * fatfs_ctx )
924{
925    kmem_req_t    req;
926    req.type = KMEM_FATFS_CTX;
927    req.ptr  = fatfs_ctx;
928    kmem_free( &req );
929}
930
931///////////////////////////////////////////////
932error_t fatfs_add_dentry( vfs_inode_t  * inode,
933                          vfs_dentry_t * dentry )
934{
935    error_t       error;
936    uint32_t      length;        // dentry name length
937    uint32_t      nb_lfn;        // number or required LFN
938    char          sfn[11];       // buffer for SFN name
939    uint8_t       checksum;      // name checksum
940    mapper_t    * mapper;        // loal pointer on parent inode mapper
941    xptr_t        mapper_xp;     // extended pointer on parent inode mapper
942    xptr_t        child_xp;      // extended pointer on child inode
943    cxy_t         child_cxy;     // child inode cluster
944    vfs_inode_t * child_ptr;     // child inode local pointer
945    uint32_t      size;          // child inode size
946    uint32_t      type;          // child inode type
947    uint32_t      cluster;       // child inode cluster index
948
949#if DEBUG_FATFS_ADD_DENTRY
950char       dir_name[CONFIG_VFS_MAX_NAME_LENGTH];
951uint32_t   cycle = (uint32_t)hal_get_cycles();
952thread_t * this  = CURRENT_THREAD;
953vfs_inode_get_name( XPTR( local_cxy , inode ) , dir_name );
954if( DEBUG_FATFS_ADD_DENTRY < cycle )
955printk("\n[%s]  thread[%x,%x] enter / parent <%s> / child <%s> / cycle %d\n",
956__FUNCTION__, this->process->pid, this->trdid, dir_name, dentry->name, cycle );
957#endif
958
959// check arguments
960assert( (inode != NULL) , "inode pointer is NULL\n" );
961assert( (dentry != NULL) , "dentry pointer is NULL\n" );
962assert( (inode->type == INODE_TYPE_DIR) , "inode is not a directory\n" );
963assert( (inode->mapper != NULL ) , "mapper pointer is NULL\n" );
964 
965    // get pointers on directory mapper
966    mapper    = inode->mapper;
967    mapper_xp = XPTR( local_cxy , mapper );
968
969    // get extended pointers on remote child inode
970    child_xp  = dentry->child_xp;
971    child_cxy = GET_CXY( child_xp );
972    child_ptr = GET_PTR( child_xp );
973
974    // get relevant infos from child inode
975    type    =                     hal_remote_l32( XPTR( child_cxy , &child_ptr->type ) );
976    size    =                     hal_remote_l32( XPTR( child_cxy , &child_ptr->size ) );
977    cluster = (uint32_t)(intptr_t)hal_remote_lpt( XPTR( child_cxy , &child_ptr->extend ) );
978
979    // analyse dentry name
980    error = fatfs_name_format( dentry->name,
981                               &length,
982                               &nb_lfn,
983                               sfn,
984                               &checksum );
985    if ( error )
986    {
987        printk("\n[ERROR] in %s : dentry name > 31 bytes\n", __FUNCTION__ );
988        return -1;
989    }
990                               
991    // Search end of directory with two embedded loops:
992    // - scan the pages in the mapper
993    // - scan the entries in each page to find NO_MORE_ENTRY
994
995    xptr_t     page_xp;                 // extended pointer on page descriptor
996    xptr_t     base_xp;                 // extended pointer on page base
997    uint8_t  * base;                    // local pointer on page base (array of bytes)
998    uint32_t   page_id = 0;             // page index in mapper
999    uint32_t   offset  = 0;             // position in page
1000    uint32_t   found   = 0;             // NO_MORE_ENTRY found
1001
1002    // loop on pages in mapper
1003    while ( found == 0 )
1004    {
1005        // get extended pointer on page descriptor in mapper
1006        page_xp  = mapper_remote_get_page( mapper_xp , page_id );
1007
1008        if ( page_xp == XPTR_NULL )
1009        {
1010            printk("\n[ERROR] in %s : cannot extend directory mapper\n", __FUNCTION__ );
1011            return -1;
1012        }
1013       
1014        // get pointer on page base
1015        base_xp = ppm_page2base( page_xp );
1016        base = GET_PTR( base_xp );
1017
1018        // loop on directory entries in this page
1019        while ( (offset < 4096) && (found == 0) )
1020        {
1021            if ( fatfs_get_record( LDIR_ORD, (base + offset), 0 ) == NO_MORE_ENTRY )
1022            {
1023                found = 1;
1024            } 
1025            else
1026            {
1027                offset = offset + 32;
1028            }
1029        }  // end loop on entries
1030
1031        if ( found == 0 )
1032        {
1033            page_id++;
1034            offset = 0;
1035        }
1036    }  // end loop on pages
1037
1038    // Modify the directory mapper: depending on the name length,
1039    // the new child requires to write (3, 4, or 5) directory entries.
1040    // To actually register the new child, we use a 5 steps FSM
1041    // (one state per entry to be written), that is traversed as:
1042    // LFN3 -> LFN2 -> LFN1 -> NORMAL -> NOMORE
1043    // At most two pages are modified:
1044    // - the page containing the NO_MORE_ENTRY is always modified
1045    // - the following page can be modified if the name spread on to pages.
1046
1047    char * name = dentry->name;
1048
1049    uint32_t step;          // FSM state
1050
1051    if      ( nb_lfn == 1 ) step = 3;
1052    else if ( nb_lfn == 2 ) step = 4;
1053    else if ( nb_lfn == 3 ) step = 5;
1054   
1055    uint8_t  * entry;       // pointer on directory entry to be written
1056    uint32_t   i;           // byte index in one 32 bytes directory
1057    uint32_t   c;           // character index in name
1058
1059    while ( step )   
1060    {
1061        // when the new child is split on two pages,
1062        // we need to access a new page in mapper
1063        if ( offset >= 4096 )
1064        {
1065            // copy the modified page to IOC device
1066            fatfs_move_page( page_xp , false );   
1067
1068            // get the next page in FAT mapper
1069            page_xp  = mapper_remote_get_page( mapper_xp , page_id + 1 );
1070
1071            if ( page_xp == XPTR_NULL )
1072            {
1073                printk("\n[ERROR] in %s : cannot extend directory mapper\n", __FUNCTION__ );
1074                return -1;
1075            }
1076       
1077            // get pointer on page base
1078            base_xp = ppm_page2base( page_xp );
1079            base = GET_PTR( base_xp );
1080           
1081            // update offset
1082            offset = 0;
1083        }
1084
1085        // compute directory entry address
1086        entry = base + offset;
1087
1088#if (DEBUG_FATFS_ADD_DENTRY & 1)
1089if( DEBUG_FATFS_ADD_DENTRY < cycle )
1090printk("\n[%s] FSM step = %d / offset = %x / nb_lfn = %d\n",
1091__FUNCTION__, step, offset, nb_lfn );
1092#endif
1093
1094        // write 32 bytes (one directory entry) per iteration
1095        switch ( step )
1096        {
1097            case 5:   // write LFN3 entry
1098            {
1099                c = 26;
1100                // scan the 32 bytes in dir_entry
1101                for ( i = 0 ; i < 32 ; i++ )
1102                {
1103                    if (i == 0)
1104                    {
1105                        if ( nb_lfn == 3) entry[i] = 0x43;
1106                        else              entry[i] = 0x03;
1107                    }
1108                    else if ( ( ((i >= 1 ) && (i<=10) && ((i&1)==1))   ||
1109                                ((i >= 14) && (i<=25) && ((i&1)==0))   ||
1110                                ((i >= 28) && (i<=31) && ((i&1)==0)) ) &&
1111                              ( c < length ) )
1112                    {
1113                                          entry[i] = name[c];
1114                                          c++;
1115                    }
1116                    else if (i == 11)     entry[i] = 0x0F;
1117                    else if (i == 13)     entry[i] = checksum;
1118                    else                  entry[i] = 0x00;
1119                }
1120                step--;
1121                break;
1122            }
1123            case 4:   // write LFN2 entry 
1124            {
1125                c = 13;
1126                // scan the 32 bytes in dir_entry
1127                for ( i = 0 ; i < 32 ; i++ )
1128                {
1129                    if (i == 0)
1130                    {
1131                        if ( nb_lfn == 2) entry[i] = 0x42;
1132                        else              entry[i] = 0x02;
1133                    }
1134                    else if ( ( ((i >= 1 ) && (i<=10) && ((i&1)==1))   ||
1135                                ((i >= 14) && (i<=25) && ((i&1)==0))   ||
1136                                ((i >= 28) && (i<=31) && ((i&1)==0)) ) &&
1137                              ( c < length ) )
1138                    {
1139                                          entry[i] = name[c];
1140                                          c++;
1141                    }
1142                    else if (i == 11)     entry[i] = 0x0F;
1143                    else if (i == 13)     entry[i] = checksum;
1144                    else                  entry[i] = 0x00;
1145                }
1146                step--;
1147                break;
1148            }
1149            case 3:   // Write LFN1 entry   
1150            {
1151                c = 0;
1152                // scan the 32 bytes in dir_entry
1153                for ( i = 0 ; i < 32 ; i++ )
1154                {
1155                    if (i == 0)
1156                    {
1157                        if ( nb_lfn == 1) entry[i] = 0x41;
1158                        else              entry[i] = 0x01;
1159                    }
1160                    else if ( ( ((i >= 1 ) && (i<=10) && ((i&1)==1))   ||
1161                                ((i >= 14) && (i<=25) && ((i&1)==0))   ||
1162                                ((i >= 28) && (i<=31) && ((i&1)==0)) ) &&
1163                              ( c < length ) )
1164                    {
1165                                          entry[i] = name[c];
1166                                          c++;
1167                    }
1168                    else if (i == 11)     entry[i] = 0x0F;
1169                    else if (i == 13)     entry[i] = checksum;
1170                    else                  entry[i] = 0x00;
1171                }
1172                step--;
1173                break;
1174            }
1175            case 2:   // write NORMAL entry     
1176            {
1177                // scan the 32 bytes in dir_entry
1178                for ( i = 0 ; i < 32 ; i++ )
1179                {
1180                    if      ( i < 11 )                              // 8.3 SFN
1181                    {
1182                                          entry[i] = sfn[i];
1183                    }
1184                    else if (i == 11)                               // ATTR
1185                    {
1186                        if (type == INODE_TYPE_DIR)  entry[i] = 0x10;
1187                        else                         entry[i] = 0x20;
1188                    }
1189                    else if (i == 20)     entry[i] = cluster>>16;   // cluster.B2
1190                    else if (i == 21)     entry[i] = cluster>>24;   // cluster.B3
1191                    else if (i == 26)     entry[i] = cluster>>0;    // cluster.B0
1192                    else if (i == 27)     entry[i] = cluster>>8;    // cluster.B1
1193                    else if (i == 28)     entry[i] = size>>0;       // size.B0
1194                    else if (i == 29)     entry[i] = size>>8;       // size.B1
1195                    else if (i == 30)     entry[i] = size>>16;      // size.B2
1196                    else if (i == 31)     entry[i] = size>>24;      // size.B3
1197                    else                  entry[i] = 0x00;
1198                }
1199
1200                // update the "extend" field in dentry descriptor
1201                dentry->extend = (void*)(intptr_t)(((page_id<<12) + offset)>>5);
1202
1203                step--;
1204                break;
1205            }
1206            case 1:   // write NOMORE entry 
1207            {
1208                entry [0] = 0x00;
1209                step--;
1210                break;
1211            }
1212        } // end switch step
1213
1214        offset += 32;
1215
1216    } // exit while     
1217
1218    // copy the modified page to the IOC device
1219    fatfs_move_page( page_xp , false );   
1220
1221#if DEBUG_FATFS_ADD_DENTRY
1222cycle = (uint32_t)hal_get_cycles();
1223if( DEBUG_FATFS_ADD_DENTRY < cycle )
1224printk("\n[%s]  thread[%x,%x] exit / parent %s / child %s / cycle %d\n",
1225__FUNCTION__, this->process->pid, this->trdid, dir_name, dentry->name, cycle );
1226#endif
1227
1228    return 0;
1229
1230}  // end fatfs_add_dentry()
1231
1232//////////////////////////////////////////////////
1233error_t fatfs_remove_dentry( vfs_inode_t  * inode,
1234                             vfs_dentry_t * dentry )
1235{
1236    xptr_t     mapper_xp;  // extended pointer on mapper
1237    mapper_t * mapper;     // local pointer on mapper
1238    xptr_t     page_xp;    // extended pointer on mapper page descriptor
1239    xptr_t     base_xp;    // extended pointer on mapper page base
1240    uint8_t  * base;       // local pointer on mapper page base
1241
1242#if DEBUG_FATFS_REMOVE_DENTRY
1243char       dir_name[CONFIG_VFS_MAX_NAME_LENGTH];
1244uint32_t   cycle = (uint32_t)hal_get_cycles();
1245thread_t * this  = CURRENT_THREAD;
1246vfs_inode_get_name( XPTR( local_cxy , inode ) , dir_name );
1247if( DEBUG_FATFS_REMOVE_DENTRY < cycle )
1248printk("\n[%s] thread[%x,%x] enter / parent <%s> / child <%s> / cycle %d\n",
1249__FUNCTION__, this->process->pid, this->trdid, dir_name, dentry->name, cycle );
1250#endif
1251
1252// check arguments
1253assert( (inode != NULL) , "inode pointer is NULL\n" );
1254assert( (dentry != NULL) , "dentry pointer is NULL\n" );
1255assert( (inode->type == INODE_TYPE_DIR) , "inode is not a directory\n" );
1256assert( (inode->mapper != NULL ) , "mapper pointer is NULL\n" );
1257
1258    // get pointers on directory mapper
1259    mapper    = inode->mapper;
1260    mapper_xp = XPTR( local_cxy , mapper );
1261
1262    // compute number of LFN entries
1263    uint32_t nb_lfn;
1264    uint32_t name_length = strlen( dentry->name );
1265
1266    if      ( name_length <= 13 ) nb_lfn  = 1;
1267    else if ( name_length <= 26 ) nb_lfn  = 2;
1268    else                          nb_lfn  = 3;
1269
1270    // we must invalidate (2, 3 or 4) 32 bytes entries:
1271    // the NORMAL entry (registered in dentry->extend) and all preceding LFN entries
1272    // At most two pages are modified:
1273    // - the page containing the NORMAL entry is always modified.
1274    // - the preceding page is modified when the name spread on two pages.
1275
1276    // get 32 bytes directory entry index from dentry->extend
1277    uint32_t  dentry_id  = (uint32_t)(intptr_t)dentry->extend; 
1278
1279    // get page index and offset in parent directory mapper
1280    uint32_t  page_id    = dentry_id >> 7;
1281    uint32_t  offset     = (dentry_id & 0x7F)<<5;
1282
1283#if DEBUG_FATFS_REMOVE_DENTRY & 1
1284if( DEBUG_FATFS_REMOVE_DENTRY < cycle )
1285printk("\n[%s] dentry_id %x / page_id %x / offset %x\n",
1286__FUNCTION__, dentry_id, page_id, offset );
1287#endif
1288
1289    // get extended pointer on page descriptor from parent directory mapper
1290    page_xp  = mapper_remote_get_page( mapper_xp , page_id );
1291
1292    if ( page_xp == XPTR_NULL )
1293    {
1294        printk("\n[ERROR] in %s : cannot extend directory mapper\n", __FUNCTION__ );
1295        return -1;
1296    }
1297       
1298    // get pointers on page base
1299    base_xp = ppm_page2base( page_xp );
1300    base    = GET_PTR( base_xp );
1301
1302    // invalidate NORMAL entry in directory cache
1303    base[offset] = 0xE5;
1304
1305    // invalidate LFN entries
1306    while ( nb_lfn )
1307    {
1308        if (offset == 0)  // we must load page (page_id - 1)
1309        {
1310
1311// check page_id
1312assert( (page_id > 0), "page_id and offset cannot be both 0\n" );
1313
1314            // copy the modified page to the IOC device
1315            fatfs_move_page( page_xp , false );   
1316
1317            // get extended pointer on page descriptor from parent directory mapper
1318            page_xp  = mapper_remote_get_page( mapper_xp , page_id );
1319
1320            if ( page_xp == XPTR_NULL )
1321            {
1322                printk("\n[ERROR] in %s : cannot access directory mapper\n", __FUNCTION__ );
1323                return -1;
1324            }
1325       
1326            // get pointers on page base
1327            base_xp = ppm_page2base( page_xp );
1328            base    = GET_PTR( base_xp );
1329
1330            // update offset
1331            offset = 4096;
1332        }
1333
1334        offset = offset - 32;
1335
1336// check for LFN entry
1337assert( (fatfs_get_record( DIR_ATTR, base + offset, 0 ) == ATTR_LONG_NAME_MASK ),
1338"this directory entry must be a LFN\n");
1339
1340        // invalidate LFN entry
1341        base[offset] = 0xE5;
1342
1343        nb_lfn--;
1344    }     
1345
1346    // copy the modified page to the IOC device
1347    fatfs_move_page( page_xp , false );   
1348   
1349
1350#if DEBUG_FATFS_REMOVE_DENTRY
1351cycle = (uint32_t)hal_get_cycles();
1352if( DEBUG_FATFS_REMOVE_DENTRY < cycle )
1353printk("\n[%s] thread[%x,%x] exit / parent %s / child %s / cycle %d\n",
1354__FUNCTION__, this->process->pid, this->trdid, dir_name, dentry->name, cycle );
1355#endif
1356
1357    return 0;
1358
1359}  // end fatfs_remove_dentry
1360
1361/////////////////////////////////////////////////////
1362error_t fatfs_get_dentry( vfs_inode_t * parent_inode,
1363                          char        * name,
1364                          xptr_t        child_inode_xp )
1365{
1366    // Two embedded loops to scan the directory mapper:
1367    // - scan the parent directory mapper pages
1368    // - scan the directory entries in each 4 Kbytes page
1369
1370#if DEBUG_FATFS_GET_DENTRY
1371char       parent_name[CONFIG_VFS_MAX_NAME_LENGTH];
1372uint32_t   cycle = (uint32_t)hal_get_cycles();
1373thread_t * this  = CURRENT_THREAD;
1374vfs_inode_get_name( XPTR( local_cxy , parent_inode ) , parent_name );
1375if( DEBUG_FATFS_GET_DENTRY < cycle )
1376printk("\n[%s]  thread[%x,%x] enter for child <%s> in parent <%s> / cycle %d\n",
1377__FUNCTION__, this->process->pid, this->trdid, name , parent_name , cycle );
1378#endif
1379
1380// check parent_inode and child_inode
1381assert( (parent_inode != NULL) , "parent_inode is NULL\n" );
1382assert( (child_inode_xp != XPTR_NULL ) , "child_inode is XPTR_NULL\n" );
1383
1384    mapper_t * mapper    = parent_inode->mapper;
1385    xptr_t     mapper_xp = XPTR( local_cxy , mapper );
1386
1387// check parent mapper
1388assert( (mapper != NULL) , "parent mapper is NULL\n");
1389   
1390    char       cname[CONFIG_VFS_MAX_NAME_LENGTH];  // name extracter from each directory entry
1391
1392    char       lfn1[16];         // buffer for one partial cname
1393    char       lfn2[16];         // buffer for one partial cname
1394    char       lfn3[16];         // buffer for one partial cname
1395    xptr_t     page_xp;          // extended pointer on page descriptor
1396    xptr_t     base_xp;          // extended pointer on page base
1397    uint8_t  * base;             // local pointer on page base
1398    uint32_t   attr;             // directory entry ATTR field
1399    uint32_t   ord;              // directory entry ORD field
1400    uint32_t   seq;              // sequence index
1401    uint32_t   lfn       = 0;    // LFN entries number
1402    uint32_t   size      = 0;    // searched file/dir size (bytes)
1403    uint32_t   cluster   = 0;    // searched file/dir cluster index
1404    uint32_t   is_dir    = 0;    // searched file/dir type
1405    int32_t    found     = 0;    // not found (0) / name found (1) / end of dir (-1)
1406    uint32_t   page_id   = 0;    // page index in mapper
1407    uint32_t   dentry_id = 0;    // directory entry index
1408    uint32_t   offset    = 0;    // byte offset in page
1409
1410    // scan the parent directory mapper
1411    while ( found == 0 )
1412    {
1413        // get one page
1414        page_xp = mapper_remote_get_page( mapper_xp , page_id );
1415
1416        if( page_xp == XPTR_NULL) return EIO;
1417
1418        // get page base
1419        base_xp = ppm_page2base( page_xp );
1420        base    = (uint8_t *)GET_PTR( base_xp );
1421
1422#if (DEBUG_FATFS_GET_DENTRY & 0x1)
1423if( DEBUG_FATFS_GET_DENTRY < cycle )
1424mapper_display_page( mapper_xp , page_id , 256 , parent_name );
1425#endif
1426        // scan this page until end of directory, end of page, or name found
1427        while( (offset < 4096) && (found == 0) )
1428        {
1429            attr = fatfs_get_record( DIR_ATTR , base + offset , 0 );   
1430            ord  = fatfs_get_record( LDIR_ORD , base + offset , 0 );   
1431
1432            if (ord == NO_MORE_ENTRY)                 // no more entry => break
1433            {
1434                found = -1;
1435            }
1436            else if ( ord == FREE_ENTRY )             // free entry => skip
1437            {
1438                offset = offset + 32;
1439            }
1440            else if ( attr == ATTR_LONG_NAME_MASK )   // LFN entry => get partial cname
1441            {
1442                seq = ord & 0x3;
1443                lfn = (seq > lfn) ? seq : lfn;   
1444                if      ( seq == 1 ) fatfs_get_name_from_long( base + offset, lfn1 );
1445                else if ( seq == 2 ) fatfs_get_name_from_long( base + offset, lfn2 );
1446                else if ( seq == 3 ) fatfs_get_name_from_long( base + offset, lfn3 );
1447                offset = offset + 32;
1448            }
1449            else                                 // NORMAL entry
1450            {
1451                // build the extracted name
1452                if      ( lfn == 0 )
1453                {
1454                    fatfs_get_name_from_short( base + offset , cname );
1455                }
1456                else if ( lfn == 1 )
1457                {
1458                    strcpy( cname      , lfn1 );
1459                }   
1460                else if ( lfn == 2 ) 
1461                {
1462                    strcpy( cname      , lfn1 );
1463                    strcpy( cname + 13 , lfn2 );
1464                }
1465                else if ( lfn == 3 ) 
1466                {
1467                    strcpy( cname      , lfn1 );
1468                    strcpy( cname + 13 , lfn2 );
1469                    strcpy( cname + 26 , lfn3 );
1470                }
1471
1472                // get dentry arguments if extracted cname == searched name
1473                if ( strcmp( name , cname ) == 0 )
1474                {
1475                    cluster = (fatfs_get_record( DIR_FST_CLUS_HI , base + offset , 1 ) << 16) |
1476                              (fatfs_get_record( DIR_FST_CLUS_LO , base + offset , 1 )      ) ;
1477                    dentry_id = ((page_id<<12) + offset)>>5;
1478                    is_dir    = ((attr & ATTR_DIRECTORY) == ATTR_DIRECTORY);
1479                    size      = fatfs_get_record( DIR_FILE_SIZE , base + offset , 1 );
1480                    found     = 1;
1481                }
1482                offset = offset + 32;
1483                lfn    = 0;
1484            }
1485        }  // end loop on directory entries in page
1486
1487        page_id++;
1488        offset = 0;
1489
1490    }  // end loop on pages
1491
1492    // analyse the result of scan
1493
1494    if ( found == -1 )  // found end of directory => failure
1495    {
1496
1497#if DEBUG_FATFS_GET_DENTRY
1498cycle = (uint32_t)hal_get_cycles();
1499if( DEBUG_FATFS_GET_DENTRY < cycle )
1500printk("\n[%s]  thread[%x,%x] exit / child <%s> not found / cycle %d\n",
1501__FUNCTION__, this->process->pid, this->trdid, name, cycle );
1502#endif
1503
1504        return -1;
1505    }
1506
1507    // get child inode cluster and local pointer
1508    cxy_t          inode_cxy = GET_CXY( child_inode_xp );
1509    vfs_inode_t  * inode_ptr = GET_PTR( child_inode_xp );
1510
1511    // build extended pointer on parent dentried root
1512    xptr_t parents_root_xp = XPTR( inode_cxy , &inode_ptr->parents );
1513
1514// check child inode has at least one parent
1515assert( (xlist_is_empty( parents_root_xp ) == false ), "child inode must have one parent\n");
1516
1517    // get dentry pointers and cluster
1518    xptr_t         dentry_xp  = XLIST_FIRST( parents_root_xp , vfs_dentry_t , parents );
1519    vfs_dentry_t * dentry_ptr = GET_PTR( dentry_xp );
1520    cxy_t          dentry_cxy = GET_CXY( dentry_xp );
1521
1522// check dentry descriptor in same cluster as parent inode
1523assert( (dentry_cxy == local_cxy) , "illegal dentry cluster\n" );
1524
1525    // update the child inode "type", "size", and "extend" fields
1526    vfs_inode_type_t type = (is_dir) ? INODE_TYPE_DIR : INODE_TYPE_FILE;
1527
1528    hal_remote_s32( XPTR( inode_cxy , &inode_ptr->type   ) , type );
1529    hal_remote_s32( XPTR( inode_cxy , &inode_ptr->size   ) , size );
1530    hal_remote_s32( XPTR( inode_cxy , &inode_ptr->extend ) , cluster );
1531
1532    // update the dentry "extend" field
1533    dentry_ptr->extend = (void *)(intptr_t)dentry_id;
1534
1535#if DEBUG_FATFS_GET_DENTRY
1536cycle = (uint32_t)hal_get_cycles();
1537if( DEBUG_FATFS_GET_DENTRY < cycle )
1538printk("\n[%s]  thread[%x,%x] exit / child <%s> loaded in <%s> / cycle %d\n",
1539__FUNCTION__, this->process->pid, this->trdid, name, parent_name, cycle );
1540#endif
1541
1542    return 0;
1543
1544}  // end fatfs_get_dentry()
1545
1546///////////////////////////////////////////////////////
1547error_t fatfs_get_user_dir( struct vfs_inode_s * inode,
1548                            struct dirent      * array, 
1549                            uint32_t             max_dirent,
1550                            uint32_t             min_dentry,
1551                            bool_t               detailed,
1552                            uint32_t           * entries,
1553                            bool_t             * done )
1554{
1555    // Two embedded loops to scan the directory mapper:
1556    // - scan the parent directory mapper pages starting always from page 0
1557    // - scan the 32 bytes NORMAL/LFN directory entries in each page
1558    // Only valid dentries are copied : dentry_id >= min_dentry && dirent_id < dirent_max
1559
1560#if DEBUG_FATFS_GET_USER_DIR
1561char       inode_name[CONFIG_VFS_MAX_NAME_LENGTH];
1562uint32_t   cycle = (uint32_t)hal_get_cycles();
1563thread_t * this  = CURRENT_THREAD;
1564vfs_inode_get_name( XPTR( local_cxy , inode ) , inode_name );
1565if( DEBUG_FATFS_GET_USER_DIR < cycle )
1566printk("\n[%s]  thread[%x,%x] enter for inode <%s> / cycle %d\n",
1567__FUNCTION__, this->process->pid, this->trdid, inode_name , cycle );
1568#endif
1569
1570    mapper_t * mapper    = inode->mapper;
1571    xptr_t     mapper_xp = XPTR( local_cxy , mapper );
1572
1573// check mapper pointer
1574assert( (mapper != NULL) , "mapper is NULL\n");
1575   
1576// TODO handle the detailed flag
1577assert( (detailed == false), "detailed argument not supported/n");
1578
1579    char       cname[CONFIG_VFS_MAX_NAME_LENGTH];  // name extracter from each directory entry
1580
1581    char       lfn1[16];           // buffer for one partial cname
1582    char       lfn2[16];           // buffer for one partial cname
1583    char       lfn3[16];           // buffer for one partial cname
1584    xptr_t     page_xp;            // extended pointer on page descriptor
1585    xptr_t     base_xp;            // extended pointer on page base
1586    uint8_t  * base;               // local pointer on page base
1587    uint32_t   attr;               // directory entry ATTR field
1588    uint32_t   ord;                // directory entry ORD field
1589    uint32_t   seq;                // sequence index
1590    uint32_t   lfn       = 0;      // LFN entries number
1591    uint32_t   offset    = 0;      // byte offset in page
1592    uint32_t   page_id   = 0;      // page index in mapper
1593    uint32_t   dentry_id = 0;      // valid (i.e. copied) dentry index in mapper
1594    uint32_t   dirent_id = 0;      // slot index in dirent array to initialize
1595    bool_t     end       = false;  // true if end of directory found
1596
1597    // loop on mapper pages
1598    while ( (end == false) && (dirent_id < max_dirent) )
1599    {
1600        // get one page from mapper
1601        page_xp = mapper_remote_get_page( mapper_xp , page_id );
1602
1603        if( page_xp == XPTR_NULL) return -1;
1604
1605        // get page base
1606        base_xp = ppm_page2base( page_xp );
1607        base    = (uint8_t *)GET_PTR( base_xp );
1608
1609#if (DEBUG_FATFS_GET_USER_DIR & 0x1)
1610if( DEBUG_FATFS_GET_USER_DIR < cycle )
1611mapper_display_page( mapper_xp , page_id , 256 , inode_name );
1612#endif
1613        // loop on NORMAL/LFN (32 bytes) directory entries in this page
1614        while( (end == false) && (offset < 4096) )
1615        {
1616            // compute condition to copy one dentry to dirent array
1617            bool_t valid = (dentry_id >= min_dentry) && (dirent_id <  max_dirent );
1618
1619            attr = fatfs_get_record( DIR_ATTR , base + offset , 0 );   
1620            ord  = fatfs_get_record( LDIR_ORD , base + offset , 0 );   
1621
1622            if (ord == NO_MORE_ENTRY)                 // no more entry => break
1623            {
1624                end = true;
1625            }
1626            else if ( ord == FREE_ENTRY )             // free entry => skip
1627            {
1628                offset = offset + 32;
1629            }
1630            else if ( attr == ATTR_LONG_NAME_MASK )   // LFN entry
1631            {
1632                if( valid )
1633                {
1634                    // get partial cname
1635                    seq = ord & 0x3;
1636                    lfn = (seq > lfn) ? seq : lfn;   
1637                    if      ( seq == 1 ) fatfs_get_name_from_long( base + offset, lfn1 );
1638                    else if ( seq == 2 ) fatfs_get_name_from_long( base + offset, lfn2 );
1639                    else if ( seq == 3 ) fatfs_get_name_from_long( base + offset, lfn3 );
1640                }
1641                offset = offset + 32;
1642            }
1643            else                                     // NORMAL entry
1644            {
1645                // increment dentry_id
1646                dentry_id++;
1647
1648                if( valid )
1649                {
1650                    // build the complete cname
1651                    if      ( lfn == 0 )
1652                    {
1653                        fatfs_get_name_from_short( base + offset , cname );
1654                    }
1655                    else if ( lfn == 1 )
1656                    {
1657                        strcpy( cname      , lfn1 );
1658                    }   
1659                    else if ( lfn == 2 ) 
1660                    {
1661                        strcpy( cname      , lfn1 );
1662                        strcpy( cname + 13 , lfn2 );
1663                    }
1664                    else if ( lfn == 3 ) 
1665                    {
1666                        strcpy( cname      , lfn1 );
1667                        strcpy( cname + 13 , lfn2 );
1668                        strcpy( cname + 26 , lfn3 );
1669                    }
1670                   
1671                    // copy cname into dirent array
1672                    strcpy( array[dirent_id].d_name , cname ); 
1673
1674                    // increment dirent_id
1675                    dirent_id++;
1676                }
1677                offset = offset + 32;
1678                lfn    = 0;
1679            }
1680        }  // end loop on directory entries in page
1681
1682        page_id++;
1683        offset = 0;
1684
1685    }  // end loop on pages
1686
1687    // return result of scan
1688    *done    = end;
1689    *entries = dirent_id;
1690
1691#if DEBUG_FATFS_GET_USER_DIR
1692cycle = (uint32_t)hal_get_cycles();
1693if( DEBUG_FATFS_GET_USER_DIR < cycle )
1694printk("\n[%s]  thread[%x,%x] exit for inode <%s> / %d entries / cycle %d\n",
1695__FUNCTION__, this->process->pid, this->trdid, inode_name, entries, cycle );
1696#endif
1697
1698    return 0;
1699
1700}  // end fatfs_get_user_dir()
1701
1702///////////////////////////////////////////////
1703error_t fatfs_sync_inode( vfs_inode_t * inode )
1704{
1705
1706// check inode pointer and cluster index
1707assert( (inode != NULL)                  , "inode pointer undefined\n" );
1708assert( (inode->mapper != NULL )         , "mapper pointer undefined\n" );
1709assert( (inode->type == INODE_TYPE_FILE) , "inode must be a file\n" );     
1710
1711#if DEBUG_FATFS_SYNC_INODE
1712char       name[CONFIG_VFS_MAX_NAME_LENGTH];
1713uint32_t   cycle = (uint32_t)hal_get_cycles();
1714thread_t * this  = CURRENT_THREAD;
1715vfs_inode_get_name( XPTR( local_cxy , inode ) , name );
1716if( DEBUG_FATFS_SYNC_INODE < cycle )
1717printk("\n[%s] thread[%x,%x] enter for <%s> / cycle %d\n",
1718__FUNCTION__ , this->process->pid, this->trdid, name, cycle );
1719#endif
1720
1721    error_t    error;
1722    mapper_t * mapper;
1723    page_t   * page;
1724    uint32_t   page_id;
1725
1726    // get mapper from inode
1727    mapper = inode->mapper;
1728
1729    // compute max number of pages in mapper from file size
1730    uint32_t size  = inode->size;
1731    uint32_t pages = size >> CONFIG_PPM_PAGE_SHIFT;
1732    if( size & CONFIG_PPM_PAGE_MASK ) pages++; 
1733         
1734    // get pointer on mapper radix tree
1735    grdxt_t * rt = &mapper->rt;
1736
1737    // scan all pages
1738    for( page_id = 0 ; page_id < pages ; page_id++ )
1739    {
1740        // get page descriptor from mapper
1741        page = grdxt_lookup( rt , page_id );
1742
1743        // check all existing pages
1744        if ( page != NULL )
1745        {
1746            if ( page->flags & PG_DIRTY )
1747            {
1748
1749#if (DEBUG_FATFS_SYNC_INODE & 1)
1750if( DEBUG_FATFS_SYNC_INODE < cycle )
1751printk("\n[%s] thread[%x,%x] synchronizes page %d from <%s> mapper to IOC device\n",
1752__FUNCTION__, page_id, name );
1753#endif
1754                // build extended pointer on page descriptor
1755                xptr_t page_xp = XPTR( local_cxy , page );
1756
1757                // move page from mapper to device
1758                error = fatfs_move_page( page_xp , false );
1759
1760                if ( error )  return -1;
1761
1762                // reset page dirty flag
1763                ppm_page_undo_dirty( page_xp );
1764            }
1765        }
1766    }  // end loop on pages
1767
1768#if DEBUG_FATFS_SYNC_INODE
1769cycle = (uint32_t)hal_get_cycles();
1770if( DEBUG_FATFS_SYNC_INODE < cycle )
1771printk("\n[%s] thread[%x,%x] exit for <%s> / cycle %d\n",
1772__FUNCTION__ , this->process->pid, this->trdid, name, cycle );
1773#endif
1774
1775    return 0;
1776
1777}  // end fatfs_sync_inode()
1778
1779//////////////////////////////
1780error_t fatfs_sync_fat( void )
1781{
1782
1783#if DEBUG_FATFS_SYNC_FAT
1784uint32_t   cycle = (uint32_t)hal_get_cycles();
1785thread_t * this  = CURRENT_THREAD;
1786if( DEBUG_FATFS_SYNC_FAT < cycle )
1787printk("\n[%s] thread[%x,%x] enter / cycle %d\n",
1788__FUNCTION__ , this->process->pid, this->trdid, cycle );
1789#endif
1790
1791    uint32_t   page_id;
1792    error_t    error;
1793
1794    // get FAT mapper pointers an cluster
1795    fatfs_ctx_t * fatfs_ctx  = fs_context[FS_TYPE_FATFS].extend;
1796    xptr_t        mapper_xp  = fatfs_ctx->fat_mapper_xp;
1797    cxy_t         mapper_cxy = GET_CXY( mapper_xp );
1798    mapper_t    * mapper_ptr = GET_PTR( mapper_xp );
1799
1800    // compute max number of 4 Kbytes pages in FAT mapper
1801    // TODO : this could be improved (see fatfs.h) [AG]
1802    uint32_t   pages = fatfs_ctx->fat_sectors_count >> 3;
1803         
1804    // get pointers on remote FAT mapper radix tree
1805    grdxt_t  * rt_ptr = &mapper_ptr->rt;
1806    xptr_t     rt_xp  = XPTR( mapper_cxy , rt_ptr );
1807
1808    // scan all pages
1809    for( page_id = 0 ; page_id < pages ; page_id++ )
1810    {
1811        // get extended pointer on page descriptor from FAT mapper
1812        xptr_t page_xp = grdxt_remote_lookup( rt_xp , page_id );
1813
1814        // check all existing pages
1815        if ( page_xp != XPTR_NULL )
1816        {
1817            page_t * page_ptr = GET_PTR( page_xp );
1818            uint32_t flags    = hal_remote_l32( XPTR( mapper_cxy , &page_ptr->flags ) );
1819
1820            if ( flags & PG_DIRTY )
1821            {
1822
1823#if (DEBUG_FATFS_SYNC_FAT & 1)
1824if( DEBUG_FATFS_SYNC_FAT < cycle )
1825printk("\n[%s] thread[%x,%x] synchronizes page %d from FAT mapper to IOC device\n",
1826__FUNCTION__, page_id );
1827#endif
1828                // move page from mapper to device
1829                error = fatfs_move_page( page_xp , false );
1830
1831                if ( error )  return -1;
1832
1833                // reset page dirty flag
1834                ppm_page_undo_dirty( page_xp );
1835            }
1836        }
1837    }  // end loop on pages
1838
1839#if DEBUG_FATFS_SYNC_FAT
1840cycle = (uint32_t)hal_get_cycles();
1841if( DEBUG_FATFS_SYNC_FAT < cycle )
1842printk("\n[%s] thread[%x,%x] exit / cycle %d\n",
1843__FUNCTION__ , this->process->pid, this->trdid, cycle );
1844#endif
1845
1846    return 0;
1847
1848}  // end fatfs_sync_fat()
1849
1850////////////////////////////////////
1851error_t fatfs_sync_free_info( void )
1852{
1853
1854#if DEBUG_FATFS_SYNC_FSINFO
1855uint32_t   cycle = (uint32_t)hal_get_cycles();
1856thread_t * this  = CURRENT_THREAD;
1857if( DEBUG_FATFS_SYNC_FSINFO < cycle )
1858printk("\n[%s] thread[%x,%x] enter / cycle %d\n",
1859__FUNCTION__ , this->process->pid, this->trdid, cycle );
1860#endif
1861
1862    uint8_t     * buffer;   // dynamically allocated aligned 512 bytes buffer
1863    kmem_req_t    req;
1864    error_t       error;
1865
1866    // get FS_INFO lba, free_ from FATFS context
1867    fatfs_ctx_t * fatfs_ctx  = fs_context[FS_TYPE_FATFS].extend;
1868    uint32_t      lba        = fatfs_ctx->fs_info_lba;
1869    uint32_t      hint       = fatfs_ctx->free_cluster_hint;
1870    uint32_t      number     = fatfs_ctx->free_clusters;
1871
1872    // allocate buffer to store the FS_INFO sector
1873        req.type    = KMEM_512_BYTES;
1874    req.flags   = AF_KERNEL | AF_ZERO;
1875        buffer      = (uint8_t *)kmem_alloc( &req );
1876    if( buffer == NULL ) 
1877    {
1878        printk("\n[PANIC] in %s : cannot allocate buffer\n", __FUNCTION__ );
1879        return ENOMEM;
1880    }
1881     
1882    // load the FS_INFO sector from device to buffer
1883    error = dev_ioc_read( buffer , lba , 1 );
1884    if ( error )
1885    {
1886        printk("\n[PANIC] in %s : cannot read FS_INFO record\n", __FUNCTION__ );
1887        return EIO;
1888    }
1889
1890    // update buffer
1891    fatfs_set_record( FS_FREE_CLUSTERS     , buffer , 1 , number );
1892    fatfs_set_record( FS_FREE_CLUSTER_HINT , buffer , 1 , hint );
1893
1894    // write modified FS_INFO sector from buffer to device
1895    error = dev_ioc_write( buffer , lba , 1 );
1896    if ( error )
1897    {
1898        printk("\n[PANIC] in %s : cannot write FS_INFO record\n", __FUNCTION__ );
1899        return EIO;
1900    }
1901
1902    // release the 512 bytes buffer
1903    req.type = KMEM_512_BYTES;
1904    req.ptr  = buffer;
1905    kmem_free( &req );
1906
1907#if DEBUG_FATFS_SYNC_FSINFO
1908cycle = (uint32_t)hal_get_cycles();
1909if( DEBUG_FATFS_SYNC_FSINFO < cycle )
1910printk("\n[%s] thread[%x,%x] exit / cycle %d\n",
1911__FUNCTION__ , this->process->pid, this->trdid, cycle );
1912#endif
1913
1914    return 0;
1915
1916}  // end fatfs_sync_fs_info()
1917
1918//////////////////////////////////////////////////////////
1919error_t fatfs_cluster_alloc( uint32_t * searched_cluster )
1920{
1921    uint32_t      page_id;        // page index in mapper
1922    uint32_t      slot_id;        // slot index in page (1024 slots per page)
1923    uint32_t      hint;           // first free cluster index in FAT
1924    uint32_t      free_clusters;  // total number of free clusters
1925    vfs_ctx_t   * vfs_ctx;        // local pointer on VFS context (same in all clusters)
1926    fatfs_ctx_t * loc_fatfs_ctx;  // local pointer on local FATFS context
1927    fatfs_ctx_t * fat_fatfs_ctx;  // local pointer on FATFS context in FAT cluster
1928    xptr_t        mapper_xp;      // extended pointer on FAT mapper
1929    cxy_t         mapper_cxy;     // Fat mapper cluster identifier
1930    xptr_t        page_xp;        // extended pointer on current page descriptor in mapper
1931    xptr_t        slot_xp;        // extended pointer on FAT slot defined by hint
1932    xptr_t        lock_xp;        // extended pointer on lock protecting free clusters info
1933    xptr_t        hint_xp;        // extended pointer on free_cluster_hint in FAT cluster
1934    xptr_t        numb_xp;        // extended pointer on free_clusters_number in FAT cluster
1935
1936#if DEBUG_FATFS_CLUSTER_ALLOC
1937uint32_t   cycle = (uint32_t)hal_get_cycles();
1938thread_t * this  = CURRENT_THREAD;
1939if( DEBUG_FATFS_CLUSTER_ALLOC < cycle )
1940printk("\n[%s] thread[%x,%x] enter / cycle = %d\n",
1941__FUNCTION__, this->process->pid, this->trdid, cycle );
1942#endif
1943
1944    // get local pointer on VFS context (same in all clusters)
1945    vfs_ctx = &fs_context[FS_TYPE_FATFS];
1946
1947    // get local pointer on local FATFS context
1948    loc_fatfs_ctx = vfs_ctx->extend;
1949
1950    // get extended pointer and cluster on FAT mapper
1951    mapper_xp  = loc_fatfs_ctx->fat_mapper_xp;
1952    mapper_cxy = GET_CXY( mapper_xp );
1953   
1954    // get local pointer on FATFS context in FAT cluster
1955    fat_fatfs_ctx = hal_remote_lpt( XPTR( mapper_cxy , &vfs_ctx->extend ) );
1956
1957    // build relevant extended pointers in on free clusters info in FAT cluster
1958    lock_xp = XPTR( mapper_cxy , &fat_fatfs_ctx->free_lock );
1959    hint_xp = XPTR( mapper_cxy , &fat_fatfs_ctx->free_cluster_hint );
1960    numb_xp = XPTR( mapper_cxy , &fat_fatfs_ctx->free_clusters );
1961
1962    // take the lock protecting free clusters
1963    remote_queuelock_acquire( lock_xp );
1964
1965    // get hint and free_clusters values from FATFS context
1966    hint          = hal_remote_l32( hint_xp );
1967    free_clusters = hal_remote_l32( numb_xp );
1968       
1969    // get page index & slot index for the first free cluster
1970    page_id  = (hint + 1) >> 10;
1971    slot_id  = (hint + 1) & 0x3FF;
1972
1973    // get relevant page from mapper
1974    page_xp = mapper_remote_get_page( mapper_xp , page_id );
1975
1976    if( page_xp == XPTR_NULL )
1977    {
1978        printk("\n[ERROR] in %s : cannot acces FAT mapper\n", __FUNCTION__ );
1979        return -1;
1980    }
1981
1982    // build extended pointer on free cluster slot
1983    slot_xp = ppm_page2base( page_xp ) + (slot_id<<2);
1984         
1985#if (DEBUG_FATFS_CLUSTER_ALLOC & 1)
1986if( DEBUG_FATFS_CLUSTER_ALLOC < cycle )
1987printk("\n[%s] thread[%x,%x] get free info / hint %x / free_clusters %x\n",
1988__FUNCTION__, this->process->pid, this->trdid, hint, free_clusters );
1989#endif
1990
1991    // check "free_clusters"
1992    if ( free_clusters == 0 )
1993    {
1994        printk("\n[ERROR] in %s : no more free FATFS clusters\n", __FUNCTION__ );
1995        remote_queuelock_acquire( lock_xp );
1996        return -1;
1997    }
1998    else if ( free_clusters < CONFIG_VFS_FREE_CLUSTERS_MIN )
1999    {
2000        printk("\n[WARNING] in %s : only %n free FATFS clusters\n", 
2001        __FUNCTION__, CONFIG_VFS_FREE_CLUSTERS_MIN );
2002    }
2003
2004    // check "hint"
2005    if( hal_remote_l32( slot_xp ) != FREE_CLUSTER )
2006    { 
2007        printk("\n[ERROR] in %s : illegal hint cluster\n", __FUNCTION__ );
2008        remote_queuelock_acquire( lock_xp );
2009        return -1;
2010    }
2011
2012    // update allocated cluster in FAT mapper
2013    hal_remote_s32( slot_xp , END_OF_CHAIN_CLUSTER_MAX );
2014
2015    // update free cluster info
2016    fatfs_free_clusters_decrement( hint + 1 );
2017
2018    // release free clusters busylock
2019    remote_queuelock_release( lock_xp );
2020
2021#if DEBUG_FATFS_CLUSTER_ALLOC
2022cycle = (uint32_t)hal_get_cycles();
2023if( DEBUG_FATFS_CLUSTER_ALLOC < cycle )
2024printk("\n[%s] thread[%x,%x] exit / cluster %x / cycle %d\n",
2025__FUNCTION__, this->process->pid, this->trdid, hint + 1, cycle );
2026#endif
2027
2028    *searched_cluster = hint + 1;
2029    return 0;
2030
2031}  // end fat_cluster_alloc()
2032
2033//////////////////////////////////////////////
2034error_t fatfs_release_inode( xptr_t inode_xp )
2035{
2036    vfs_ctx_t   * vfs_ctx;        // local pointer on VFS context (same in all clusters).
2037    fatfs_ctx_t * loc_fatfs_ctx;  // local pointer on local FATFS context
2038    fatfs_ctx_t * fat_fatfs_ctx;  // local pointer on FATFS context in FAT cluster
2039    xptr_t        mapper_xp;      // extended pointer on FAT mapper
2040    cxy_t         mapper_cxy;     // Fat mapper cluster identifier
2041    xptr_t        lock_xp;        // extended pointer on lock protecting free clusters info.
2042    xptr_t        first_xp;       // extended pointer on inode extension
2043    uint32_t      first_cluster;  // first cluster index for released inode
2044    vfs_inode_t * inode_ptr;
2045    cxy_t         inode_cxy;
2046
2047// check inode pointer
2048assert( (inode_xp != XPTR_NULL) , "inode pointer is NULL\n" );
2049
2050    // get first_cluster from inode extension
2051    inode_ptr     = GET_PTR( inode_xp );
2052    inode_cxy     = GET_CXY( inode_xp );
2053    first_xp      = XPTR( inode_cxy , &inode_ptr->extend );
2054    first_cluster = (uint32_t)(intptr_t)hal_remote_lpt( first_xp );
2055
2056// check first cluster index
2057assert( (first_cluster != 0) , "inode extend is NULL\n" );
2058
2059#if DEBUG_FATFS_RELEASE_INODE
2060char       name[CONFIG_VFS_MAX_NAME_LENGTH];
2061uint32_t   cycle = (uint32_t)hal_get_cycles();
2062thread_t * this  = CURRENT_THREAD;
2063vfs_inode_get_name( inode_xp , name );
2064if( DEBUG_FATFS_RELEASE_INODE < cycle )
2065printk("\n[%s] thread[%x,%x] enter for <%s> / first_cluster %x / cycle %d\n",
2066__FUNCTION__ , this->process->pid, this->trdid, name, first_cluster, cycle );
2067#endif
2068
2069    // get local pointer on VFS context (same in all clusters)
2070    vfs_ctx = &fs_context[FS_TYPE_FATFS];
2071
2072    // get local pointer on local FATFS context
2073    loc_fatfs_ctx = vfs_ctx->extend;
2074
2075    // get extended pointer and cluster on FAT mapper
2076    mapper_xp  = loc_fatfs_ctx->fat_mapper_xp;
2077    mapper_cxy = GET_CXY( mapper_xp );
2078   
2079    // get local pointer on FATFS context in FAT cluster
2080    fat_fatfs_ctx = hal_remote_lpt( XPTR( mapper_cxy , &vfs_ctx->extend ) );
2081
2082    // get extended pointer on free clusters lock in FAT cluster
2083    lock_xp = XPTR( mapper_cxy , &fat_fatfs_ctx->free_lock );
2084
2085    // take lock protecting free clusters
2086    remote_queuelock_acquire( lock_xp );
2087
2088    // call the recursive function to release all clusters from FAT mapper
2089    if ( fatfs_recursive_release( mapper_xp , first_cluster ) )
2090    {
2091        printk("\n[ERROR] in %s : cannot update FAT mapper\n", __FUNCTION__ );
2092        remote_queuelock_release( lock_xp );
2093        return -1;
2094    }
2095
2096    // release lock protecting free cluster
2097    remote_queuelock_release( lock_xp );
2098
2099#if (DEBUG_FATFS_RELEASE_INODE & 1)
2100if( DEBUG_FATFS_RELEASE_INODE < cycle )
2101printk("\n[%s] inode <%s> removed from FAT mapper\n", __FUNCTION__, name );
2102#endif
2103
2104    // update FAT on IOC device (from FAT mapper)
2105    if ( fatfs_sync_fat() )
2106    {
2107        printk("\n[ERROR] in %s : cannot update FAT on device\n", __FUNCTION__ );
2108        return -1;
2109    }
2110
2111#if (DEBUG_FATFS_RELEASE_INODE & 1)
2112if( DEBUG_FATFS_RELEASE_INODE < cycle )
2113printk("\n[%s] inode <%s> removed from FAT on IOC device\n", __FUNCTION__, name );
2114#endif
2115
2116    // update FS-INFO sector on IOC device (from FATFS context)
2117    if ( fatfs_sync_free_info() )
2118    {
2119        printk("\n[ERROR] in %s: cannot update FS_INFO on device\n", __FUNCTION__ );
2120        return -1;
2121    }
2122
2123#if DEBUG_FATFS_RELEASE_INODE
2124cycle = (uint32_t)hal_get_cycles();
2125if( DEBUG_FATFS_RELEASE_INODE < cycle )
2126printk("\n[%s] thread[%x,%x] removed <%s> inode from FATFS / cycle %d\n",
2127__FUNCTION__ , this->process->pid, this->trdid, name, cycle );
2128#endif
2129
2130    return 0;
2131
2132}  // end fatfs_release_inode()
2133
2134/////////////////////////////////////////
2135error_t fatfs_move_page( xptr_t  page_xp,
2136                         bool_t  to_mapper )
2137{
2138    error_t       error;
2139    vfs_inode_t * inode_ptr;
2140    mapper_t    * mapper_ptr;     
2141    uint32_t      page_id;     // page index in mapper
2142
2143#if DEBUG_FATFS_MOVE_PAGE
2144uint32_t   cycle = (uint32_t)hal_get_cycles();
2145thread_t * this  = CURRENT_THREAD;
2146char       name[CONFIG_VFS_MAX_NAME_LENGTH];
2147#endif
2148
2149    // get page cluster an local pointer
2150    cxy_t    page_cxy = GET_CXY( page_xp );
2151    page_t * page_ptr = GET_PTR( page_xp );
2152
2153    // get mapper pointer and page index from page descriptor
2154    mapper_ptr = hal_remote_lpt( XPTR( page_cxy , &page_ptr->mapper ) );
2155    page_id    = hal_remote_l32( XPTR( page_cxy , &page_ptr->index ) );
2156
2157    // get pointer on local FATFS context
2158    fatfs_ctx_t * fatfs_ctx = fs_context[FS_TYPE_FATFS].extend;
2159
2160    // get page base address
2161    xptr_t    base_xp = ppm_page2base( page_xp );
2162    uint8_t * buffer  = (uint8_t *)GET_PTR( base_xp );
2163 
2164    // get inode pointer from mapper
2165    inode_ptr  = hal_remote_lpt( XPTR( page_cxy , &mapper_ptr->inode ) );
2166
2167    ////////////////////////////// it is the FAT mapper
2168    if( inode_ptr == NULL )
2169    {
2170        // get lba from FATFS context and page_id
2171        uint32_t      lba        = fatfs_ctx->fat_begin_lba + (page_id << 3);
2172 
2173        // access device
2174        if( to_mapper ) error = dev_ioc_sync_read ( buffer , lba , 8 );
2175        else            error = dev_ioc_write( buffer , lba , 8 );     
2176
2177        if( error ) return EIO;
2178
2179#if (DEBUG_FATFS_MOVE_PAGE & 0x1)
2180if( DEBUG_FATFS_MOVE_PAGE < cycle )
2181mapper_display_page( XPTR(page_cxy , mapper_ptr) , page_id , "FAT" );
2182#endif
2183
2184#if DEBUG_FATFS_MOVE_PAGE
2185cycle = (uint32_t)hal_get_cycles();
2186if( DEBUG_FATFS_MOVE_PAGE < cycle )
2187{
2188    if (to_mapper)
2189         printk("\n[%s] thread[%x,%x] load page %d of FAT / cycle %d\n",
2190         __FUNCTION__, this->process->pid, this->trdid, page_id, cycle );
2191    else
2192        printk("\n[%s] thread[%x,%x] sync page %d of FAT / cycle %d\n",
2193        __FUNCTION__, this->process->pid, this->trdid, page_id, cycle );
2194}
2195#endif
2196
2197    }
2198    ///////////////////////// it is an inode mapper
2199    else                       
2200    {
2201
2202#if DEBUG_FATFS_MOVE_PAGE
2203vfs_inode_get_name( XPTR( page_cxy , inode_ptr ) , name );
2204#endif
2205
2206        uint32_t  searched_cluster;
2207        uint32_t  first_cluster;
2208
2209        // get first_cluster from inode extension
2210        void * extend = hal_remote_lpt( XPTR( page_cxy , &inode_ptr->extend ) );
2211        first_cluster = (uint32_t)(intptr_t)extend;
2212
2213        // compute searched_cluster
2214        if( page_id == 0 )            // no need to access FAT mapper
2215        {
2216            // searched cluster is first cluster
2217            searched_cluster = first_cluster;
2218        }
2219        else                        // FAT mapper access required
2220        {
2221            // access FAT mapper to get searched cluster
2222            error = fatfs_get_cluster( first_cluster,
2223                                       page_id,
2224                                       &searched_cluster );
2225            if( error )  return EIO;
2226        }
2227
2228        // get lba from searched_cluster
2229        uint32_t lba = fatfs_lba_from_cluster( fatfs_ctx , searched_cluster );
2230
2231        // access device
2232        if( to_mapper ) error = dev_ioc_sync_read ( buffer , lba , 8 );
2233        else            error = dev_ioc_write( buffer , lba , 8 );     
2234
2235        if( error ) return EIO;
2236
2237#if (DEBUG_FATFS_MOVE_PAGE & 0x1)
2238if( DEBUG_FATFS_MOVE_PAGE < cycle )
2239char string[CONFIG_VFS_MAX_NAME_LENGTH];
2240vfs_inode_get_name( XPTR(page_cxy , inode_ptr) , string );
2241mapper_display_page( XPTR(page_cxy , mapper_ptr) , page_id , string );
2242#endif
2243
2244#if DEBUG_FATFS_MOVE_PAGE
2245cycle = (uint32_t)hal_get_cycles();
2246if(DEBUG_FATFS_MOVE_PAGE < cycle)
2247{
2248    if(to_mapper)
2249        printk("\n[%s] thread[%x,%x] load page %d of <%s> inode / cycle %d\n",
2250        __FUNCTION__, this->process->pid, this->trdid, page_id, name, cycle );
2251    else
2252        printk("\n[%s] thread[%x,%x] sync page %d of <%s> inode / cycle %d\n",
2253        __FUNCTION__, this->process->pid, this->trdid, page_id, name, cycle );
2254}
2255#endif
2256
2257    }
2258
2259    return 0;
2260
2261}  // end fatfs_move_page()
2262
2263
Note: See TracBrowser for help on using the repository browser.