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

Last change on this file since 602 was 602, checked in by alain, 3 years ago

Improve the FAT32 file system to support cat, rm, cp commands.

File size: 74.8 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    // get extended pointer on page descriptor from parent directory mapper
1284    page_xp  = mapper_remote_get_page( mapper_xp , page_id );
1285
1286    if ( page_xp == XPTR_NULL )
1287    {
1288        printk("\n[ERROR] in %s : cannot extend directory mapper\n", __FUNCTION__ );
1289        return -1;
1290    }
1291       
1292    // get pointers on page base
1293    base_xp = ppm_page2base( page_xp );
1294    base    = GET_PTR( base_xp );
1295
1296    // invalidate NORMAL entry in directory cache
1297    base[offset] = 0xE5;
1298
1299    // invalidate LFN entries
1300    while ( nb_lfn )
1301    {
1302        if (offset == 0)  // we must load page (page_id - 1)
1303        {
1304
1305// check page_id
1306assert( (page_id > 0), "page_id and offset cannot be both 0\n" );
1307
1308            // copy the modified page to the IOC device
1309            fatfs_move_page( page_xp , false );   
1310
1311            // get extended pointer on page descriptor from parent directory mapper
1312            page_xp  = mapper_remote_get_page( mapper_xp , page_id );
1313
1314            if ( page_xp == XPTR_NULL )
1315            {
1316                printk("\n[ERROR] in %s : cannot access directory mapper\n", __FUNCTION__ );
1317                return -1;
1318            }
1319       
1320            // get pointers on page base
1321            base_xp = ppm_page2base( page_xp );
1322            base    = GET_PTR( base_xp );
1323
1324            // update offset
1325            offset = 4096;
1326        }
1327
1328        offset = offset - 32;
1329
1330// check for LFN entry
1331assert( (fatfs_get_record( DIR_ATTR, base + offset, 0 ) == ATTR_LONG_NAME_MASK ),
1332"this directory entry must be a LFN\n");
1333
1334        // invalidate LFN entry
1335        base[offset] = 0xE5;
1336
1337        nb_lfn--;
1338    }     
1339
1340    // copy the modified page to the IOC device
1341    fatfs_move_page( page_xp , false );   
1342   
1343
1344#if DEBUG_FATFS_REMOVE_DENTRY
1345cycle = (uint32_t)hal_get_cycles();
1346if( DEBUG_FATFS_REMOVE_DENTRY < cycle )
1347printk("\n[%s]  thread[%x,%x] exit / parent %s / child %s / cycle %d\n",
1348__FUNCTION__, this->process->pid, this->trdid, dir_name, dentry->name, cycle );
1349#endif
1350
1351    return 0;
1352
1353}  // end fatfs_remove_dentry
1354
1355////////////////////////////////////////////////////////////////
1356error_t fatfs_child_init( vfs_inode_t * parent_inode,
1357                          char        * name,
1358                          xptr_t        child_inode_xp )
1359{
1360    // Two embedded loops:
1361    // - scan the parent directory mapper pages
1362    // - scan the directory entries in each 4 Kbytes page
1363
1364#if DEBUG_FATFS_CHILD_INIT
1365char       parent_name[CONFIG_VFS_MAX_NAME_LENGTH];
1366uint32_t   cycle = (uint32_t)hal_get_cycles();
1367thread_t * this  = CURRENT_THREAD;
1368vfs_inode_get_name( XPTR( local_cxy , parent_inode ) , parent_name );
1369if( DEBUG_FATFS_CHILD_INIT < cycle )
1370printk("\n[%s]  thread[%x,%x] enter for child <%s> in parent <%s> / cycle %d\n",
1371__FUNCTION__, this->process->pid, this->trdid, name , parent_name , cycle );
1372#endif
1373
1374// check parent_inode and child_inode
1375assert( (parent_inode != NULL) , "parent_inode is NULL\n" );
1376assert( (child_inode_xp != XPTR_NULL ) , "child_inode is XPTR_NULL\n" );
1377
1378    mapper_t * mapper    = parent_inode->mapper;
1379    xptr_t     mapper_xp = XPTR( local_cxy , mapper );
1380
1381// check parent mapper
1382assert( (mapper != NULL) , "parent mapper is NULL\n");
1383   
1384    char       cname[CONFIG_VFS_MAX_NAME_LENGTH];  // name extracter from each directory entry
1385
1386    char       lfn1[16];         // buffer for one partial cname
1387    char       lfn2[16];         // buffer for one partial cname
1388    char       lfn3[16];         // buffer for one partial cname
1389    xptr_t     page_xp;          // extended pointer on page descriptor
1390    xptr_t     base_xp;          // extended pointer on page base
1391    uint8_t  * base;             // local pointer on page base
1392    uint32_t   attr;             // directory entry ATTR field
1393    uint32_t   ord;              // directory entry ORD field
1394    uint32_t   seq;              // sequence index
1395    uint32_t   lfn       = 0;    // LFN entries number
1396    uint32_t   size      = 0;    // searched file/dir size (bytes)
1397    uint32_t   cluster   = 0;    // searched file/dir cluster index
1398    uint32_t   is_dir    = 0;    // searched file/dir type
1399    int32_t    found     = 0;    // not found (0) / name found (1) / end of dir (-1)
1400    uint32_t   page_id   = 0;    // page index in mapper
1401    uint32_t   dentry_id = 0;    // directory entry index
1402    uint32_t   offset    = 0;    // byte offset in page
1403
1404    // scan the parent directory mapper
1405    while ( found == 0 )
1406    {
1407        // get one page
1408        page_xp = mapper_remote_get_page( mapper_xp , page_id );
1409
1410        if( page_xp == XPTR_NULL) return EIO;
1411
1412        // get page base
1413        base_xp = ppm_page2base( page_xp );
1414        base    = (uint8_t *)GET_PTR( base_xp );
1415
1416#if (DEBUG_FATFS_CHILD_INIT & 0x1)
1417if( DEBUG_FATFS_CHILD_INIT < cycle )
1418{
1419    uint32_t * buf = (uint32_t *)base;
1420    uint32_t line , word;
1421    printk("\n[%s] First 16 dentries for <%s>\n",
1422    __FUNCTION__ , parent_name );
1423    for( line = 0 ; line < 16 ; line++ )
1424    {
1425        printk("%X : ", line );
1426        for( word = 0 ; word < 8 ; word++ ) printk("%X ", buf[(line<<4) + word] );
1427        printk("\n");
1428    }
1429}
1430#endif
1431        // scan this page until end of directory, end of page, or name found
1432        while( (offset < 4096) && (found == 0) )
1433        {
1434            attr = fatfs_get_record( DIR_ATTR , base + offset , 0 );   
1435            ord  = fatfs_get_record( LDIR_ORD , base + offset , 0 );   
1436
1437            if (ord == NO_MORE_ENTRY)                 // no more entry => break
1438            {
1439                found = -1;
1440            }
1441            else if ( ord == FREE_ENTRY )             // free entry => skip
1442            {
1443                offset = offset + 32;
1444            }
1445            else if ( attr == ATTR_LONG_NAME_MASK )   // LFN entry => get partial cname
1446            {
1447                seq = ord & 0x3;
1448                lfn = (seq > lfn) ? seq : lfn;   
1449                if      ( seq == 1 ) fatfs_get_name_from_long( base + offset, lfn1 );
1450                else if ( seq == 2 ) fatfs_get_name_from_long( base + offset, lfn2 );
1451                else if ( seq == 3 ) fatfs_get_name_from_long( base + offset, lfn3 );
1452                offset = offset + 32;
1453            }
1454            else                                 // NORMAL entry
1455            {
1456                // build the extracted name
1457                if      ( lfn == 0 )
1458                {
1459                    fatfs_get_name_from_short( base + offset , cname );
1460                }
1461                else if ( lfn == 1 )
1462                {
1463                    strcpy( cname      , lfn1 );
1464                }   
1465                else if ( lfn == 2 ) 
1466                {
1467                    strcpy( cname      , lfn1 );
1468                    strcpy( cname + 13 , lfn2 );
1469                }
1470                else if ( lfn == 3 ) 
1471                {
1472                    strcpy( cname      , lfn1 );
1473                    strcpy( cname + 13 , lfn2 );
1474                    strcpy( cname + 26 , lfn3 );
1475                }
1476
1477                // get dentry arguments if extracted cname == searched name
1478                if ( strcmp( name , cname ) == 0 )
1479                {
1480                    cluster = (fatfs_get_record( DIR_FST_CLUS_HI , base + offset , 1 ) << 16) |
1481                              (fatfs_get_record( DIR_FST_CLUS_LO , base + offset , 1 )      ) ;
1482                    dentry_id = ((page_id<<12) + offset)>>5;
1483                    is_dir    = ((attr & ATTR_DIRECTORY) == ATTR_DIRECTORY);
1484                    size      = fatfs_get_record( DIR_FILE_SIZE , base + offset , 1 );
1485                    found     = 1;
1486                }
1487                offset = offset + 32;
1488                lfn    = 0;
1489            }
1490        }  // end loop on directory entries in page
1491
1492        page_id++;
1493        offset = 0;
1494
1495    }  // end loop on pages
1496
1497    // analyse the result of scan
1498
1499    if ( found == -1 )  // found end of directory => failure
1500    {
1501
1502#if DEBUG_FATFS_CHILD_INIT
1503cycle = (uint32_t)hal_get_cycles();
1504if( DEBUG_FATFS_CHILD_INIT < cycle )
1505printk("\n[%s]  thread[%x,%x] exit / child <%s> not found / cycle %d\n",
1506__FUNCTION__, this->process->pid, this->trdid, name, cycle );
1507#endif
1508
1509        return -1;
1510    }
1511
1512    // get child inode cluster and local pointer
1513    cxy_t          inode_cxy = GET_CXY( child_inode_xp );
1514    vfs_inode_t  * inode_ptr = (vfs_inode_t *)GET_PTR( child_inode_xp );
1515
1516    // get dentry pointers and cluster
1517    xptr_t         dentry_xp  = hal_remote_l64( XPTR( inode_cxy , &inode_ptr->parent_xp ) ); 
1518    vfs_dentry_t * dentry_ptr = GET_PTR( dentry_xp );
1519    cxy_t          dentry_cxy = GET_CXY( dentry_xp );
1520
1521// dentry descriptor must be in same cluster as parent inode
1522assert( (dentry_cxy == local_cxy) , "illegal dentry cluster\n" );
1523
1524    // update the child inode "type", "size", and "extend" fields
1525    vfs_inode_type_t type = (is_dir) ? INODE_TYPE_DIR : INODE_TYPE_FILE;
1526
1527    hal_remote_s32( XPTR( inode_cxy , &inode_ptr->type   ) , type );
1528    hal_remote_s32( XPTR( inode_cxy , &inode_ptr->size   ) , size );
1529    hal_remote_s32( XPTR( inode_cxy , &inode_ptr->extend ) , cluster );
1530
1531    // update the dentry "extend" field
1532    dentry_ptr->extend = (void *)(intptr_t)dentry_id;
1533
1534#if DEBUG_FATFS_CHILD_INIT
1535cycle = (uint32_t)hal_get_cycles();
1536if( DEBUG_FATFS_CHILD_INIT < cycle )
1537printk("\n[%s]  thread[%x,%x] exit / child <%s> loaded in <%s> / cycle %d\n",
1538__FUNCTION__, this->process->pid, this->trdid, name, parent_name, cycle );
1539#endif
1540
1541    return 0;
1542
1543}  // end fatfs_child_init()
1544
1545///////////////////////////////////////////////
1546error_t fatfs_sync_inode( vfs_inode_t * inode )
1547{
1548
1549// check inode pointer and cluster index
1550assert( (inode != NULL)                  , "inode pointer undefined\n" );
1551assert( (inode->mapper != NULL )         , "mapper pointer undefined\n" );
1552assert( (inode->type == INODE_TYPE_FILE) , "inode must be a file\n" );     
1553
1554#if DEBUG_FATFS_SYNC_INODE
1555char       name[CONFIG_VFS_MAX_NAME_LENGTH];
1556uint32_t   cycle = (uint32_t)hal_get_cycles();
1557thread_t * this  = CURRENT_THREAD;
1558vfs_inode_get_name( XPTR( local_cxy , inode ) , name );
1559if( DEBUG_FATFS_SYNC_INODE < cycle )
1560printk("\n[%s] thread[%x,%x] enter for <%s> / cycle %d\n",
1561__FUNCTION__ , this->process->pid, this->trdid, name, cycle );
1562#endif
1563
1564    error_t    error;
1565    mapper_t * mapper;
1566    page_t   * page;
1567    uint32_t   page_id;
1568
1569    // get mapper from inode
1570    mapper = inode->mapper;
1571
1572    // compute max number of pages in mapper from file size
1573    uint32_t size  = inode->size;
1574    uint32_t pages = size >> CONFIG_PPM_PAGE_SHIFT;
1575    if( size & CONFIG_PPM_PAGE_MASK ) pages++; 
1576         
1577    // get pointer on mapper radix tree
1578    grdxt_t * rt = &mapper->rt;
1579
1580    // scan all pages
1581    for( page_id = 0 ; page_id < pages ; page_id++ )
1582    {
1583        // get page descriptor from mapper
1584        page = grdxt_lookup( rt , page_id );
1585
1586        // check all existing pages
1587        if ( page != NULL )
1588        {
1589            if ( page->flags & PG_DIRTY )
1590            {
1591
1592#if (DEBUG_FATFS_SYNC_INODE & 1)
1593if( DEBUG_FATFS_SYNC_INODE < cycle )
1594printk("\n[%s] thread[%x,%x] synchronizes page %d from <%s> mapper to IOC device\n",
1595__FUNCTION__, page_id, name );
1596#endif
1597                // build extended pointer on page descriptor
1598                xptr_t page_xp = XPTR( local_cxy , page );
1599
1600                // move page from mapper to device
1601                error = fatfs_move_page( page_xp , false );
1602
1603                if ( error )  return -1;
1604
1605                // reset page dirty flag
1606                ppm_page_undo_dirty( page_xp );
1607            }
1608        }
1609    }  // end loop on pages
1610
1611#if DEBUG_FATFS_SYNC_INODE
1612cycle = (uint32_t)hal_get_cycles();
1613if( DEBUG_FATFS_SYNC_INODE < cycle )
1614printk("\n[%s] thread[%x,%x] exit for <%s> / cycle %d\n",
1615__FUNCTION__ , this->process->pid, this->trdid, name, cycle );
1616#endif
1617
1618    return 0;
1619
1620}  // end fatfs_sync_inode()
1621
1622//////////////////////////////
1623error_t fatfs_sync_fat( void )
1624{
1625
1626#if DEBUG_FATFS_SYNC_FAT
1627uint32_t   cycle = (uint32_t)hal_get_cycles();
1628thread_t * this  = CURRENT_THREAD;
1629if( DEBUG_FATFS_SYNC_FAT < cycle )
1630printk("\n[%s] thread[%x,%x] enter / cycle %d\n",
1631__FUNCTION__ , this->process->pid, this->trdid, cycle );
1632#endif
1633
1634    uint32_t   page_id;
1635    error_t    error;
1636
1637    // get FAT mapper pointers an cluster
1638    fatfs_ctx_t * fatfs_ctx  = fs_context[FS_TYPE_FATFS].extend;
1639    xptr_t        mapper_xp  = fatfs_ctx->fat_mapper_xp;
1640    cxy_t         mapper_cxy = GET_CXY( mapper_xp );
1641    mapper_t    * mapper_ptr = GET_PTR( mapper_xp );
1642
1643    // compute max number of 4 Kbytes pages in FAT mapper
1644    // TODO : this could be improved (see fatfs.h) [AG]
1645    uint32_t   pages = fatfs_ctx->fat_sectors_count >> 3;
1646         
1647    // get pointers on remote FAT mapper radix tree
1648    grdxt_t  * rt_ptr = &mapper_ptr->rt;
1649    xptr_t     rt_xp  = XPTR( mapper_cxy , rt_ptr );
1650
1651    // scan all pages
1652    for( page_id = 0 ; page_id < pages ; page_id++ )
1653    {
1654        // get extended pointer on page descriptor from FAT mapper
1655        xptr_t page_xp = grdxt_remote_lookup( rt_xp , page_id );
1656
1657        // check all existing pages
1658        if ( page_xp != XPTR_NULL )
1659        {
1660            page_t * page_ptr = GET_PTR( page_xp );
1661            uint32_t flags    = hal_remote_l32( XPTR( mapper_cxy , &page_ptr->flags ) );
1662
1663            if ( flags & PG_DIRTY )
1664            {
1665
1666#if (DEBUG_FATFS_SYNC_FAT & 1)
1667if( DEBUG_FATFS_SYNC_FAT < cycle )
1668printk("\n[%s] thread[%x,%x] synchronizes page %d from FAT mapper to IOC device\n",
1669__FUNCTION__, page_id );
1670#endif
1671                // move page from mapper to device
1672                error = fatfs_move_page( page_xp , false );
1673
1674                if ( error )  return -1;
1675
1676                // reset page dirty flag
1677                ppm_page_undo_dirty( page_xp );
1678            }
1679        }
1680    }  // end loop on pages
1681
1682#if DEBUG_FATFS_SYNC_FAT
1683cycle = (uint32_t)hal_get_cycles();
1684if( DEBUG_FATFS_SYNC_FAT < cycle )
1685printk("\n[%s] thread[%x,%x] exit / cycle %d\n",
1686__FUNCTION__ , this->process->pid, this->trdid, cycle );
1687#endif
1688
1689    return 0;
1690
1691}  // end fatfs_sync_fat()
1692
1693////////////////////////////////////
1694error_t fatfs_sync_free_info( void )
1695{
1696
1697#if DEBUG_FATFS_SYNC_FSINFO
1698uint32_t   cycle = (uint32_t)hal_get_cycles();
1699thread_t * this  = CURRENT_THREAD;
1700if( DEBUG_FATFS_SYNC_FSINFO < cycle )
1701printk("\n[%s] thread[%x,%x] enter / cycle %d\n",
1702__FUNCTION__ , this->process->pid, this->trdid, cycle );
1703#endif
1704
1705    uint8_t     * buffer;   // dynamically allocated aligned 512 bytes buffer
1706    kmem_req_t    req;
1707    error_t       error;
1708
1709    // get FS_INFO lba, free_ from FATFS context
1710    fatfs_ctx_t * fatfs_ctx  = fs_context[FS_TYPE_FATFS].extend;
1711    uint32_t      lba        = fatfs_ctx->fs_info_lba;
1712    uint32_t      hint       = fatfs_ctx->free_cluster_hint;
1713    uint32_t      number     = fatfs_ctx->free_clusters;
1714
1715    // allocate buffer to store the FS_INFO sector
1716        req.type    = KMEM_512_BYTES;
1717    req.flags   = AF_KERNEL | AF_ZERO;
1718        buffer      = (uint8_t *)kmem_alloc( &req );
1719    if( buffer == NULL ) 
1720    {
1721        printk("\n[PANIC] in %s : cannot allocate buffer\n", __FUNCTION__ );
1722        return ENOMEM;
1723    }
1724     
1725    // load the FS_INFO sector from device to buffer
1726    error = dev_ioc_read( buffer , lba , 1 );
1727    if ( error )
1728    {
1729        printk("\n[PANIC] in %s : cannot read FS_INFO record\n", __FUNCTION__ );
1730        return EIO;
1731    }
1732
1733    // update buffer
1734    fatfs_set_record( FS_FREE_CLUSTERS     , buffer , 1 , number );
1735    fatfs_set_record( FS_FREE_CLUSTER_HINT , buffer , 1 , hint );
1736
1737    // write modified FS_INFO sector from buffer to device
1738    error = dev_ioc_write( buffer , lba , 1 );
1739    if ( error )
1740    {
1741        printk("\n[PANIC] in %s : cannot write FS_INFO record\n", __FUNCTION__ );
1742        return EIO;
1743    }
1744
1745    // release the 512 bytes buffer
1746    req.type = KMEM_512_BYTES;
1747    req.ptr  = buffer;
1748    kmem_free( &req );
1749
1750#if DEBUG_FATFS_SYNC_FSINFO
1751cycle = (uint32_t)hal_get_cycles();
1752if( DEBUG_FATFS_SYNC_FSINFO < cycle )
1753printk("\n[%s] thread[%x,%x] exit / cycle %d\n",
1754__FUNCTION__ , this->process->pid, this->trdid, cycle );
1755#endif
1756
1757    return 0;
1758
1759}  // end fatfs_sync_fs_info()
1760
1761//////////////////////////////////////////////////////////
1762error_t fatfs_cluster_alloc( uint32_t * searched_cluster )
1763{
1764    uint32_t      page_id;        // page index in mapper
1765    uint32_t      slot_id;        // slot index in page (1024 slots per page)
1766    uint32_t      hint;           // first free cluster index in FAT
1767    uint32_t      free_clusters;  // total number of free clusters
1768    vfs_ctx_t   * vfs_ctx;        // local pointer on VFS context (same in all clusters)
1769    fatfs_ctx_t * loc_fatfs_ctx;  // local pointer on local FATFS context
1770    fatfs_ctx_t * fat_fatfs_ctx;  // local pointer on FATFS context in FAT cluster
1771    xptr_t        mapper_xp;      // extended pointer on FAT mapper
1772    cxy_t         mapper_cxy;     // Fat mapper cluster identifier
1773    xptr_t        page_xp;        // extended pointer on current page descriptor in mapper
1774    xptr_t        slot_xp;        // extended pointer on FAT slot defined by hint
1775    xptr_t        lock_xp;        // extended pointer on lock protecting free clusters info
1776    xptr_t        hint_xp;        // extended pointer on free_cluster_hint in FAT cluster
1777    xptr_t        numb_xp;        // extended pointer on free_clusters_number in FAT cluster
1778
1779#if DEBUG_FATFS_CLUSTER_ALLOC
1780uint32_t   cycle = (uint32_t)hal_get_cycles();
1781thread_t * this  = CURRENT_THREAD;
1782if( DEBUG_FATFS_CLUSTER_ALLOC < cycle )
1783printk("\n[%s] thread[%x,%x] enter / cycle = %d\n",
1784__FUNCTION__, this->process->pid, this->trdid, cycle );
1785#endif
1786
1787    // get local pointer on VFS context (same in all clusters)
1788    vfs_ctx = &fs_context[FS_TYPE_FATFS];
1789
1790    // get local pointer on local FATFS context
1791    loc_fatfs_ctx = vfs_ctx->extend;
1792
1793    // get extended pointer and cluster on FAT mapper
1794    mapper_xp  = loc_fatfs_ctx->fat_mapper_xp;
1795    mapper_cxy = GET_CXY( mapper_xp );
1796   
1797    // get local pointer on FATFS context in FAT cluster
1798    fat_fatfs_ctx = hal_remote_lpt( XPTR( mapper_cxy , &vfs_ctx->extend ) );
1799
1800    // build relevant extended pointers in on free clusters info in FAT cluster
1801    lock_xp = XPTR( mapper_cxy , &fat_fatfs_ctx->free_lock );
1802    hint_xp = XPTR( mapper_cxy , &fat_fatfs_ctx->free_cluster_hint );
1803    numb_xp = XPTR( mapper_cxy , &fat_fatfs_ctx->free_clusters );
1804
1805    // take the lock protecting free clusters
1806    remote_queuelock_acquire( lock_xp );
1807
1808    // get hint and free_clusters values from FATFS context
1809    hint          = hal_remote_l32( hint_xp );
1810    free_clusters = hal_remote_l32( numb_xp );
1811       
1812    // get page index & slot index for the first free cluster
1813    page_id  = (hint + 1) >> 10;
1814    slot_id  = (hint + 1) & 0x3FF;
1815
1816    // get relevant page from mapper
1817    page_xp = mapper_remote_get_page( mapper_xp , page_id );
1818
1819    if( page_xp == XPTR_NULL )
1820    {
1821        printk("\n[ERROR] in %s : cannot acces FAT mapper\n", __FUNCTION__ );
1822        return -1;
1823    }
1824
1825    // build extended pointer on free cluster slot
1826    slot_xp = ppm_page2base( page_xp ) + (slot_id<<2);
1827         
1828#if (DEBUG_FATFS_CLUSTER_ALLOC & 1)
1829if( DEBUG_FATFS_CLUSTER_ALLOC < cycle )
1830printk("\n[%s] thread[%x,%x] get free info / hint %x / free_clusters %x\n",
1831__FUNCTION__, this->process->pid, this->trdid, hint, free_clusters );
1832#endif
1833
1834    // check "free_clusters"
1835    if ( free_clusters == 0 )
1836    {
1837        printk("\n[ERROR] in %s : no more free FATFS clusters\n", __FUNCTION__ );
1838        remote_queuelock_acquire( lock_xp );
1839        return -1;
1840    }
1841    else if ( free_clusters < CONFIG_VFS_FREE_CLUSTERS_MIN )
1842    {
1843        printk("\n[WARNING] in %s : only %n free FATFS clusters\n", 
1844        __FUNCTION__, CONFIG_VFS_FREE_CLUSTERS_MIN );
1845    }
1846
1847    // check "hint"
1848    if( hal_remote_l32( slot_xp ) != FREE_CLUSTER )
1849    { 
1850        printk("\n[ERROR] in %s : illegal hint cluster\n", __FUNCTION__ );
1851        remote_queuelock_acquire( lock_xp );
1852        return -1;
1853    }
1854
1855    // update allocated cluster in FAT mapper
1856    hal_remote_s32( slot_xp , END_OF_CHAIN_CLUSTER_MAX );
1857
1858    // update free cluster info
1859    fatfs_free_clusters_decrement( hint + 1 );
1860
1861    // release free clusters busylock
1862    remote_queuelock_release( lock_xp );
1863
1864#if DEBUG_FATFS_CLUSTER_ALLOC
1865cycle = (uint32_t)hal_get_cycles();
1866if( DEBUG_FATFS_CLUSTER_ALLOC < cycle )
1867printk("\n[%s] thread[%x,%x] exit / cluster %x / cycle %d\n",
1868__FUNCTION__, this->process->pid, this->trdid, hint + 1, cycle );
1869#endif
1870
1871    *searched_cluster = hint + 1;
1872    return 0;
1873
1874}  // end fat_cluster_alloc()
1875
1876//////////////////////////////////////////////
1877error_t fatfs_release_inode( xptr_t inode_xp )
1878{
1879    vfs_ctx_t   * vfs_ctx;        // local pointer on VFS context (same in all clusters).
1880    fatfs_ctx_t * loc_fatfs_ctx;  // local pointer on local FATFS context
1881    fatfs_ctx_t * fat_fatfs_ctx;  // local pointer on FATFS context in FAT cluster
1882    xptr_t        mapper_xp;      // extended pointer on FAT mapper
1883    cxy_t         mapper_cxy;     // Fat mapper cluster identifier
1884    xptr_t        lock_xp;        // extended pointer on lock protecting free clusters info.
1885    xptr_t        first_xp;       // extended pointer on inode extension
1886    uint32_t      first_cluster;  // first cluster index for released inode
1887    vfs_inode_t * inode_ptr;
1888    cxy_t         inode_cxy;
1889
1890// check inode pointer
1891assert( (inode_xp != XPTR_NULL) , "inode pointer is NULL\n" );
1892
1893    // get first_cluster from inode extension
1894    inode_ptr     = GET_PTR( inode_xp );
1895    inode_cxy     = GET_CXY( inode_xp );
1896    first_xp      = XPTR( inode_cxy , &inode_ptr->extend );
1897    first_cluster = (uint32_t)(intptr_t)hal_remote_lpt( first_xp );
1898
1899// check first cluster index
1900assert( (first_cluster != 0) , "inode extend is NULL\n" );
1901
1902#if DEBUG_FATFS_RELEASE_INODE
1903char       name[CONFIG_VFS_MAX_NAME_LENGTH];
1904uint32_t   cycle = (uint32_t)hal_get_cycles();
1905thread_t * this  = CURRENT_THREAD;
1906vfs_inode_get_name( inode_xp , name );
1907if( DEBUG_FATFS_RELEASE_INODE < cycle )
1908printk("\n[%s] thread[%x,%x] enter for <%s> / first_cluster %x / cycle %d\n",
1909__FUNCTION__ , this->process->pid, this->trdid, name, first_cluster, cycle );
1910#endif
1911
1912    // get local pointer on VFS context (same in all clusters)
1913    vfs_ctx = &fs_context[FS_TYPE_FATFS];
1914
1915    // get local pointer on local FATFS context
1916    loc_fatfs_ctx = vfs_ctx->extend;
1917
1918    // get extended pointer and cluster on FAT mapper
1919    mapper_xp  = loc_fatfs_ctx->fat_mapper_xp;
1920    mapper_cxy = GET_CXY( mapper_xp );
1921   
1922    // get local pointer on FATFS context in FAT cluster
1923    fat_fatfs_ctx = hal_remote_lpt( XPTR( mapper_cxy , &vfs_ctx->extend ) );
1924
1925    // get extended pointer on free clusters lock in FAT cluster
1926    lock_xp = XPTR( mapper_cxy , &fat_fatfs_ctx->free_lock );
1927
1928    // take lock protecting free clusters
1929    remote_queuelock_acquire( lock_xp );
1930
1931    // call the recursive function to release all clusters from FAT mapper
1932    if ( fatfs_recursive_release( mapper_xp , first_cluster ) )
1933    {
1934        printk("\n[ERROR] in %s : cannot update FAT mapper\n", __FUNCTION__ );
1935        remote_queuelock_release( lock_xp );
1936        return -1;
1937    }
1938
1939    // release lock protecting free cluster
1940    remote_queuelock_release( lock_xp );
1941
1942#if (DEBUG_FATFS_RELEASE_INODE & 1)
1943if( DEBUG_FATFS_RELEASE_INODE < cycle )
1944printk("\n[%s] inode <%s> removed from FAT mapper\n", __FUNCTION__, name );
1945#endif
1946
1947    // update FAT on IOC device (from FAT mapper)
1948    if ( fatfs_sync_fat() )
1949    {
1950        printk("\n[ERROR] in %s : cannot update FAT on device\n", __FUNCTION__ );
1951        return -1;
1952    }
1953
1954#if (DEBUG_FATFS_RELEASE_INODE & 1)
1955if( DEBUG_FATFS_RELEASE_INODE < cycle )
1956printk("\n[%s] inode <%s> removed from FAT on IOC device\n", __FUNCTION__, name );
1957#endif
1958
1959    // update FS-INFO sector on IOC device (from FATFS context)
1960    if ( fatfs_sync_free_info() )
1961    {
1962        printk("\n[ERROR] in %s: cannot update FS_INFO on device\n", __FUNCTION__ );
1963        return -1;
1964    }
1965
1966#if DEBUG_FATFS_RELEASE_INODE
1967cycle = (uint32_t)hal_get_cycles();
1968if( DEBUG_FATFS_RELEASE_INODE < cycle )
1969printk("\n[%s] thread[%x,%x] removed <%s> inode from FATFS / cycle %d\n",
1970__FUNCTION__ , this->process->pid, this->trdid, name, cycle );
1971#endif
1972
1973    return 0;
1974
1975}  // end fatfs_release_inode()
1976
1977/////////////////////////////////////////
1978error_t fatfs_move_page( xptr_t  page_xp,
1979                         bool_t  to_mapper )
1980{
1981    error_t       error;
1982    vfs_inode_t * inode_ptr;
1983    mapper_t    * mapper_ptr;     
1984    uint32_t      page_id;     // page index in mapper
1985
1986#if DEBUG_FATFS_MOVE_PAGE
1987uint32_t   cycle = (uint32_t)hal_get_cycles();
1988thread_t * this  = CURRENT_THREAD;
1989char       name[CONFIG_VFS_MAX_NAME_LENGTH];
1990#endif
1991
1992    // get page cluster an local pointer
1993    cxy_t    page_cxy = GET_CXY( page_xp );
1994    page_t * page_ptr = GET_PTR( page_xp );
1995
1996    // get mapper pointer and page index from page descriptor
1997    mapper_ptr = hal_remote_lpt( XPTR( page_cxy , &page_ptr->mapper ) );
1998    page_id    = hal_remote_l32( XPTR( page_cxy , &page_ptr->index ) );
1999
2000    // get pointer on local FATFS context
2001    fatfs_ctx_t * fatfs_ctx      = fs_context[FS_TYPE_FATFS].extend;
2002
2003    // get page base address
2004    xptr_t    base_xp = ppm_page2base( page_xp );
2005    uint8_t * buffer  = (uint8_t *)GET_PTR( base_xp );
2006 
2007    // get inode pointer from mapper
2008    inode_ptr  = hal_remote_lpt( XPTR( page_cxy , &mapper_ptr->inode ) );
2009
2010    ////////////////////////////// it is the FAT mapper
2011    if( inode_ptr == NULL )
2012    {
2013        // get lba from FATFS context and page_id
2014        uint32_t      lba        = fatfs_ctx->fat_begin_lba + (page_id << 3);
2015 
2016        // access device
2017        if( to_mapper ) error = dev_ioc_sync_read ( buffer , lba , 8 );
2018        else            error = dev_ioc_write( buffer , lba , 8 );     
2019
2020        if( error ) return EIO;
2021
2022#if (DEBUG_FATFS_MOVE_PAGE & 0x1)
2023if( DEBUG_FATFS_MOVE_PAGE < cycle )
2024{
2025    uint32_t * tab = (uint32_t *)buffer;
2026    uint32_t line , word;
2027    printk("\n***** %s : First 64 words of page %d in FAT mapper\n",
2028    __FUNCTION__ , page_id );
2029    for( line = 0 ; line < 8 ; line++ )
2030    {
2031        printk("%X : ", line );
2032        for( word = 0 ; word < 8 ; word++ ) printk("%X ", tab[(line<<3) + word] );
2033        printk("\n");
2034    }
2035}
2036#endif
2037
2038#if DEBUG_FATFS_MOVE_PAGE
2039cycle = (uint32_t)hal_get_cycles();
2040if( DEBUG_FATFS_MOVE_PAGE < cycle )
2041{
2042    if (to_mapper)
2043         printk("\n[%s] thread[%x,%x] load page %d of FAT / cycle %d\n",
2044         __FUNCTION__, this->process->pid, this->trdid, page_id, cycle );
2045    else
2046        printk("\n[%s] thread[%x,%x] sync page %d of FAT / cycle %d\n",
2047        __FUNCTION__, this->process->pid, this->trdid, page_id, cycle );
2048}
2049#endif
2050
2051    }
2052    ///////////////////////// it is an inode mapper
2053    else                       
2054    {
2055
2056#if DEBUG_FATFS_MOVE_PAGE
2057vfs_inode_get_name( XPTR( page_cxy , inode_ptr ) , name );
2058#endif
2059
2060        uint32_t  searched_cluster;
2061        uint32_t  first_cluster;
2062
2063        // get first_cluster from inode extension
2064        void * extend = hal_remote_lpt( XPTR( page_cxy , &inode_ptr->extend ) );
2065        first_cluster = (uint32_t)(intptr_t)extend;
2066
2067        // compute searched_cluster
2068        if( page_id == 0 )            // no need to access FAT mapper
2069        {
2070            // searched cluster is first cluster
2071            searched_cluster = first_cluster;
2072        }
2073        else                        // FAT mapper access required
2074        {
2075            // access FAT mapper to get searched cluster
2076            error = fatfs_get_cluster( first_cluster,
2077                                       page_id,
2078                                       &searched_cluster );
2079            if( error )  return EIO;
2080        }
2081
2082        // get lba from searched_cluster
2083        uint32_t lba = fatfs_lba_from_cluster( fatfs_ctx , searched_cluster );
2084
2085        // access device
2086        if( to_mapper ) error = dev_ioc_sync_read ( buffer , lba , 8 );
2087        else            error = dev_ioc_write( buffer , lba , 8 );     
2088
2089        if( error ) return EIO;
2090
2091#if (DEBUG_FATFS_MOVE_PAGE & 0x1)
2092if( DEBUG_FATFS_MOVE_PAGE < cycle )
2093{
2094    uint32_t * tab = (uint32_t *)buffer;
2095    uint32_t line , word;
2096    printk("\n***** %s : First 64 words of page %d in <%s> mapper\n",
2097    __FUNCTION__, page_id, name );
2098    for( line = 0 ; line < 8 ; line++ )
2099    {
2100        printk("%X : ", line );
2101        for( word = 0 ; word < 8 ; word++ ) printk("%X ", tab[(line<<3) + word] );
2102        printk("\n");
2103    }
2104}
2105#endif
2106
2107#if DEBUG_FATFS_MOVE_PAGE
2108cycle = (uint32_t)hal_get_cycles();
2109if(DEBUG_FATFS_MOVE_PAGE < cycle)
2110{
2111    if(to_mapper)
2112        printk("\n[%s] thread[%x,%x] load page %d of <%s> inode / cycle %d\n",
2113        __FUNCTION__, this->process->pid, this->trdid, page_id, name, cycle );
2114    else
2115        printk("\n[%s] thread[%x,%x] sync page %d of <%s> inode / cycle %d\n",
2116        __FUNCTION__, this->process->pid, this->trdid, page_id, name, cycle );
2117}
2118#endif
2119
2120    }
2121
2122    return 0;
2123
2124}  // end fatfs_move_page()
2125
2126
Note: See TracBrowser for help on using the repository browser.