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

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

Introduce sigificant modifs in VFS to support the <ls> command,
and the . and .. directories entries.

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