source: soft/giet_vm/giet_fat32/fat32.c @ 357

Last change on this file since 357 was 354, checked in by alain, 11 years ago

Cosmetic: reducing debug verbosity.

  • Property svn:executable set to *
File size: 62.7 KB
Line 
1//////////////////////////////////////////////////////////////////////////////////
2// File     : fat32.c
3// Date     : 01/09/2013
4// Authors  : Marco Jankovic, Cesar Fuguet & Alain Greiner
5// Copyright (c) UPMC-LIP6
6//////////////////////////////////////////////////////////////////////////////////
7// The fat32.h and fat32.c files define a library of access functions
8// to a FAT32 disk on a block device. It is intended to be used
9// by the GIET_VM nano-kernel for both the boot code and the kernel code.
10// This code uses functions defined in the utils.c and drivers.c files.
11//////////////////////////////////////////////////////////////////////////////////
12// Implementation notes:
13// 1. the "lba" (Logical Block Address) is the physical sector index on
14//    the block device. The physical sector size is supposed to be 512 bytes.
15// 2. the "cluster" variable is actually a cluster index. A cluster contains
16//    typically 8 sectors (4K bytes) and the cluster index is a 32 bits word.
17// 2. This FAT32 library uses a FAT cache whose storage capacity is one
18//    sector (512 bytes, or 128 cluster indexes in FAT)
19// 3. This FAT32 library can be used in four modes: BOOT_PA/BOOT_VA/KERNEL/USER
20//    defining different behaviours for the IOC driver.
21//////////////////////////////////////////////////////////////////////////////////
22
23#include <giet_config.h>
24#include <fat32.h>
25#include <tty_driver.h>
26#include <ioc_driver.h>
27#include <utils.h>
28
29//////////////////////////////////////////////////////////////////////////////////
30//      Global variable used by all FAT access functions
31//////////////////////////////////////////////////////////////////////////////////
32
33__attribute__((section (".kdata"))) 
34fat32_fs_t fat __attribute__((aligned(64)));
35
36//////////////////////////////////////////////////////////////////////////////////
37// This function displays the content of the FAT cache
38//////////////////////////////////////////////////////////////////////////////////
39void display_fat_cache()
40{
41    unsigned int line;
42    unsigned int word;
43    unsigned int temp[9];
44
45    temp[8] = 0;
46
47    _printf("\n*********************** fat_cache_lba = %x *****************************\n",
48            fat.cache_lba );
49
50    for ( line=0 ; line<16 ; line++ )
51    {
52        // display address
53        _printf( "%x : ", (fat.cache_lba<<9) + (line<<5) );
54
55        // display data hexa
56        for ( word=0 ; word<8 ; word++ )
57        {
58            unsigned int byte  = (line<<5) + (word<<2);
59            unsigned int hexa  = (fat.fat_cache[byte  ]<<24) |
60                                 (fat.fat_cache[byte+1]<<16) |
61                                 (fat.fat_cache[byte+2]<< 8) |
62                                 (fat.fat_cache[byte+3]);
63            _printf("%x | ", hexa );
64
65            // prepare display ascii
66            temp[word] = fat.fat_cache[byte]         |
67                         (fat.fat_cache[byte+1]<<8)  |
68                         (fat.fat_cache[byte+2]<<16) |
69                         (fat.fat_cache[byte+3]<<24) ;
70        }
71       
72        // display data ascii
73        _printf( (char*)temp );
74        _printf("\n");
75    }
76    _printf("**************************************************************************\n");
77} // end display_fat_cache() 
78
79//////////////////////////////////////////////////////////////////////////////////
80// This function returns the length of a FAT field. This field is identified
81// man by an (offset,length) mnemonic defined in fat32.h file.
82//////////////////////////////////////////////////////////////////////////////////
83static inline int get_length( int offset, 
84                              int length)
85{
86    return length;
87}
88
89//////////////////////////////////////////////////////////////////////////////
90// Write one 32 bits word "value" in a char[] buffer.
91// This field is defined by the offset and size arguments.
92//////////////////////////////////////////////////////////////////////////////
93static void write_entry( unsigned int   offset,
94                         unsigned int   size,
95                         char*          buffer,
96                         unsigned int   value )
97{
98    unsigned int turn = 0;
99    unsigned int res  = value;
100    unsigned int mask = 0x000000ff;
101
102    while( turn != size - 1 )
103    {
104        buffer[ offset + turn ] = res & mask;
105        res = res >> 8;
106        turn++;
107    }
108    buffer[offset + turn] = res & mask;
109}
110
111//////////////////////////////////////////////////////////////////////////////
112// Read one 32 bits word in a char[] buffer, taking endianness into account.
113// This field is defined by the offset and size arguments.
114//////////////////////////////////////////////////////////////////////////////
115static unsigned int read_entry( unsigned int   offset,
116                                unsigned int   size,
117                                char*          buffer,
118                                unsigned int   little_indian )
119{
120    unsigned int turn;
121    unsigned int res  = 0;
122    unsigned int mask = 0x000000ff;
123
124    if( little_indian )
125    {
126        turn = size;
127        while( turn != 1 )
128        {
129            res = res | (buffer[offset + (turn-1)] & mask);
130            res = res << 8;
131            turn--;
132        }
133        res = (buffer[offset + (turn-1)] & mask) | res;
134    }
135    else
136    {
137        turn = 0;
138        while( turn != size - 1 )
139        {
140
141            res = res  | (buffer[ offset + turn ] & mask );
142            res = res << 8;
143            turn++;
144        }
145        res = res | (buffer[offset + turn] & mask);
146    }
147    return res;
148}
149
150//////////////////////////////////////////////////////////////////////////////////
151// This function retuns the cluster index from the lba of a DATA sector.
152// The lba must be larger than the lba of the first DATA sector.
153// The DATA region indexing starts a cluster 2.
154//////////////////////////////////////////////////////////////////////////////////
155static inline unsigned int lba_to_cluster( unsigned int lba )                   
156{
157   if (lba < fat.data_lba ) return 0;
158
159   return ( (lba - fat.data_lba) / fat.sectors_per_cluster) + 2; 
160}
161
162//////////////////////////////////////////////////////////////////////////////////
163// This function retuns the lba of first sector in DATA region
164// from the cluster index. The cluster index must be larger than 2.
165//////////////////////////////////////////////////////////////////////////////////
166static inline unsigned int cluster_to_lba( unsigned int cluster )       
167{
168   if ( cluster < 2 ) return 0; 
169
170   return  (fat.sectors_per_cluster * (cluster - 2)) + fat.data_lba;
171}
172
173/////////////////////////////////////////////////////////////////////////////////
174// This function search the FAT (using the FAT cache), and returns
175// the next cluster index from the current cluster index in the FAT.
176// remark: a sector of FAT contains 128 cluster indexes.
177/////////////////////////////////////////////////////////////////////////////////
178static unsigned int get_next_cluster_id( unsigned int mode,
179                                         unsigned int cluster )
180{
181    // compute lba of the sector containing the cluster index
182    unsigned int lba = fat.fat_lba + (cluster / 128);
183
184    if ( lba == fat.cache_lba )      // hit in cache
185    {
186        return read_entry( ((cluster % 128) * 4), 
187                           4, 
188                           fat.fat_cache,
189                           1 );
190    }
191    else                                  // miss in cache
192    {
193        // we cannot access fat in user mode
194        if( mode == IOC_USER_MODE ) mode = IOC_KERNEL_MODE;
195       
196        // access fat
197        if( _ioc_read( 0,                 // channel
198                       mode,              // mode for IOC driver
199                       lba,               // sector index
200                       fat.fat_cache,     // fat cache
201                       1 ) )              // one sector
202        {
203            _printf("[FAT_ERROR] in get_next cluster_id() "
204                    "cannot read block %x\n", lba );
205            return 1;
206        }
207        fat.cache_lba = lba;
208
209        return read_entry( ((cluster % 128) * 4), 
210                           4, 
211                           fat.fat_cache,
212                           1 );
213    }
214}
215
216//////////////////////////////////////////////////////
217static inline unsigned char to_upper(unsigned char c)
218{
219   if (c >= 'a' && c <= 'z') return (c & ~(0x20));
220   else                      return c;
221}
222
223////////////////////////////////////////////////////////////////
224// This function is a filter:
225// Return the c character if c is a legal short name character
226// Return the '_' character if c is illegal
227////////////////////////////////////////////////////////////////
228static unsigned char illegal_short(unsigned char c)
229{
230   const unsigned char illegal_char [] =";+=[]’,\"*\\<>/?:|\0";
231   short i = 0;
232   while (illegal_char[i]!='\0')
233   {
234      if (c == illegal_char[i])
235         return '_';
236      i++;
237   }
238   return c;
239}
240
241/////////////////////////////////////////////////////////////////////////////////
242// This function test if the string argument is a legal SFN (Short File Name)
243// and copies this name (removing the .) in the sfn_string argument.
244// Criteria for a Short File Name are:
245// - separator is '.' (extension is not mandatory)
246// - 1 <= name length <= 8
247// - 0 <= extension length <= 3
248// - no illegal character (see illega_short() function)
249// Return 1 if it string is a legal SFN
250// Return 0 if not legal SFN
251/////////////////////////////////////////////////////////////////////////////////
252static int is_short( char* string, 
253                     char* sfn_string)
254{
255    int s_size   = 0;
256    int dot_ext  = 0;       // dot offset in the filename
257    int name_len = 0;       // length of file name
258    int ext_len  = 0;       // length of extension
259    int i        = 0;
260    int sc_i     = 0;
261    char ch;
262
263    if(string[0] == '.' && string[1] == '\0')
264    {
265        sfn_string[0] = '.';
266        return 1;
267    }
268    if(string[0] == '.' && string[1] == '.' && string[2] == '\0')
269    {
270        sfn_string[0] = '.';
271        sfn_string[1] = '.';
272        return 1;
273    }
274    sfn_string[11] = '\0';
275    while (string[s_size] != '\0')
276    {
277        if (string[s_size] == '.')
278        {
279            dot_ext = s_size;
280            ext_len = -1;
281        }
282        ext_len++;
283        s_size++;
284    }
285    if (dot_ext != 0)
286    {
287        name_len = s_size - ext_len - 1;
288    }
289    else
290    {
291        name_len = s_size;
292        ext_len = 0;
293    }
294    if ( ext_len > 3 || ( name_len > 8))
295    {
296        return 0;
297    }
298    if (dot_ext != 0)
299    {
300        while (i != ext_len)
301        {
302            ch = to_upper(string[dot_ext + 1 + i]);
303            ch = illegal_short(ch);
304            sfn_string[8+i] = ch;
305            i++;
306        } 
307    }
308    i = 0;
309    sc_i = 0;
310    while (i!= name_len)
311    {
312        ch = to_upper(string[i]);
313        ch = illegal_short(ch);
314        if (ch != '.') sfn_string[sc_i++] = ch;
315        i++;
316    }
317    return 1;
318}
319
320///////////////////////////////////////////////////////////////////////
321// This function analyses the pathname argument, from the character
322// defined by the *nb_read argument.
323// It copies the found name (between '/') in the name[] buffer,
324// and updates the nb_read argument.
325// Return 1 if name found, Return 0 if NUL character found,
326///////////////////////////////////////////////////////////////////////
327static int get_name_from_path( char*          pathname,
328                               char*          name,
329                               unsigned int*  nb_read ) 
330{
331    if ( pathname[*nb_read] == 0 ) return 0;
332
333    int i = (pathname[*nb_read] == '/')? (*nb_read) + 1 : *nb_read;
334    int j = 0;
335   
336    while(pathname[i] != '/' && pathname[i] != '\0')
337    {
338        name[j] = pathname[i];   
339        j++;
340        i++;
341    }
342    name[j] = 0;
343
344    if ( pathname[i] == '/' ) *nb_read += j+1;
345    else                      *nb_read += j;
346
347    return 1;
348}
349
350////////////////////////////////////////////////////////////////////////////////
351static int get_name_from_short( char* dir_entry,     // input:  SFN dir_entry
352                                char* entry_name )   // output: name
353{
354    unsigned int i   = 0;
355    unsigned int length = get_length(DIR_NAME);
356
357    while ( i < length )
358    {
359        entry_name[i] = dir_entry[i];
360        i++;
361    }
362    entry_name[i] = '\0';
363
364    return i;
365}
366
367///////////////////////////////////////////////////////////////////////////////
368static int get_name_from_long( char *dir_entry,     // input : LFN dir_entry
369                               char *entry_name )   // output : name
370{
371    unsigned int   entry_name_offset   = 0;
372    unsigned int   dir_entry_offset    = get_length(LDIR_ORD);
373    unsigned int   l_name_1            = get_length(LDIR_NAME_1);
374    unsigned int   l_name_2            = get_length(LDIR_NAME_2);
375    unsigned int   l_name_3            = get_length(LDIR_NAME_3);
376    unsigned int   l_attr              = get_length(LDIR_ATTR);
377    unsigned int   l_type              = get_length(LDIR_TYPE);
378    unsigned int   l_chksum            = get_length(LDIR_CHKSUM);
379    unsigned int   l_rsvd              = get_length(LDIR_RSVD);
380
381    unsigned int j            = 0;
382    unsigned int eof          = 0;
383
384    while ( (dir_entry_offset != DIR_ENTRY_SIZE)  && (!eof) )
385    {
386        while (j != l_name_1 && !eof )
387        {
388            if ( (dir_entry[dir_entry_offset] == 0x00) || 
389                 (dir_entry[dir_entry_offset] == 0xFF) )
390            {
391                eof = 1;
392                continue;
393            }
394            entry_name[entry_name_offset] = dir_entry[dir_entry_offset];
395            dir_entry_offset += 2;
396            j += 2;
397            entry_name_offset++;
398        }
399
400        dir_entry_offset += (l_attr + l_type + l_chksum);
401        j = 0;
402
403        while (j != l_name_2 && !eof )
404        {
405            if ( (dir_entry[dir_entry_offset] == 0x00) || 
406                 (dir_entry[dir_entry_offset] == 0xFF) )
407            {
408                eof = 1;
409                continue;
410            }
411            entry_name[entry_name_offset] = dir_entry[dir_entry_offset];
412            dir_entry_offset += 2;
413            j += 2;
414            entry_name_offset++;
415        }
416
417        dir_entry_offset += l_rsvd;
418        j = 0;
419
420        while (j != l_name_3 && !eof )
421        {
422            if ( (dir_entry[dir_entry_offset] == 0x00) || 
423                 (dir_entry[dir_entry_offset] == 0xFF) )
424            {
425                eof = 1;
426                continue;
427            }
428            entry_name[entry_name_offset] = dir_entry[dir_entry_offset];
429            dir_entry_offset += 2;
430            j += 2;
431            entry_name_offset++;
432        }
433    }
434    entry_name[entry_name_offset] = '\0';
435
436    return entry_name_offset;
437} // end get_name_from_long()
438
439//////////////////////////////////////////////////////////////////////////////////////
440// This function update a DIR_ENTRY, write a new value into a specific field
441// (ex : DIR_FILE_SIZE, when we want update the file size after a fat_write)
442// Return 0 in case of success, > 0 if failure.
443//////////////////////////////////////////////////////////////////////////////////////
444// TODO : make this function less complex
445//////////////////////////////////////////////////////////////////////////////////////
446static inline unsigned int update_entry( unsigned int fd_id, 
447                                         unsigned int field,
448                                         unsigned int size,
449                                         unsigned int value )
450{
451    char dir_entry[32];   // buffer to store a full directory_entry
452    char name_entry[14];  // buffer to store a 13 characters (partial) name
453    char file_name[256];  // buffer to store the name (not pathname) of the file
454    char sfn[12]            = {[0 ... 10] = ' ', '\0'};      // buffer for a Short File Name
455
456    unsigned int lba       = fat.fd[fd_id].lba_dir_entry;    // Lba of file dir_entry
457    unsigned int is_sfn;         
458    unsigned int attr      = 0;                              // directory entry attribute
459    unsigned int ord       = 0;                              // directory entry sequence
460    unsigned int found     = 0;                              // name found
461    unsigned int offset    = 0;
462    unsigned int i         = 0;
463    unsigned int nb_read   = 0;
464
465    for ( i = 0 ; i < 32 ; i++ ) dir_entry[i]  = 0;
466    for ( i = 0 ; i < 14 ; i++ ) name_entry[i] = 0;
467   
468    // Get the name of the file.
469    while ( get_name_from_path( fat.fd[fd_id].name, file_name, &nb_read ) )
470    {
471    }
472
473    // Check if file_name is short
474    is_sfn = is_short( file_name, sfn );
475
476    if ( _ioc_read( 0,               // channel
477                    IOC_KERNEL_MODE, // mode for IOC driver
478                    lba,             // sector index
479                    fat.fat_cache,   // buffer address
480                    1 ) )            // one sector
481    {
482        _printf("[FAT ERROR] in update_entry() cannot read sector %x\n", lba );
483        return 1;
484    }
485    fat.cache_lba = lba;
486
487    // - the offset increment is an integer number of directory entry (32 bytes)
488    // - the exit condition is success (name found) or failure (end of directory)
489    while ( !found )
490    {
491        attr = read_entry( DIR_ATTR, fat.fat_cache + offset, 0 );
492        ord  = read_entry( LDIR_ORD, fat.fat_cache + offset, 0 );
493
494        if ( is_sfn == 1 )                                     // searched name is short
495        {
496            if      ( (ord != FREE_ENTRY ) &&
497                    (ord != NO_MORE_ENTRY) &&
498                    (attr == ATTR_LONG_NAME_MASK) )    // LFN entry : skipped
499            {
500                offset     = offset + ((ord & 0xF) * DIR_ENTRY_SIZE);
501                continue;
502            }
503            else if ( (attr != ATTR_LONG_NAME_MASK) && 
504                    (ord  != FREE_ENTRY) && 
505                    (ord  != NO_MORE_ENTRY ) )         // SFN entry : checked
506            {
507                memcpy( dir_entry, fat.fat_cache + offset, DIR_ENTRY_SIZE );   
508            }
509            else if (ord == NO_MORE_ENTRY )            // end of directory : return
510            {
511                _printf("[FAT ERROR] in update_entry() : reaches end of directory\n");
512                return 1;
513            }
514            else                                                                           // free entry : skipped
515            {
516                offset = offset + DIR_ENTRY_SIZE;
517                continue;
518            }
519        }
520        else                                           // searched name is long
521        {
522            if      ( (attr == ATTR_LONG_NAME_MASK) && 
523                    (ord != FREE_ENTRY) &&
524                    (ord != NO_MORE_ENTRY) )           // LFN entry : checked
525            {
526                memcpy( dir_entry, fat.fat_cache + offset, DIR_ENTRY_SIZE );   
527            }
528            else if ( (attr != ATTR_LONG_NAME_MASK) && 
529                    (ord  != FREE_ENTRY) && 
530                    (ord  != NO_MORE_ENTRY))               // SFN entry : skipped
531            {
532                offset = offset + DIR_ENTRY_SIZE;
533                continue;
534            }
535            else if (ord == NO_MORE_ENTRY )                        // end of directory : return
536            {
537                _printf("[FAT ERROR] in update_entry() reaches end of directory\n");
538                return 1;
539            }
540            else                                       // free entry : skipped
541            {
542                offset = offset + DIR_ENTRY_SIZE;
543                continue;
544            }
545        }
546
547        // testing the name extracted from dir entry
548
549        if ( is_sfn == 1 )                             // searched name is short
550        {
551            get_name_from_short( dir_entry, name_entry );
552
553            if ( _strncmp( (char*)sfn, (char*)name_entry, 13 ) == 0 )
554            {
555                write_entry(offset + field, size, fat.fat_cache, value);
556                found = 1;
557            }
558            else                                                                       // no matching : skip
559            {
560                offset = offset + DIR_ENTRY_SIZE;
561            }
562        }
563        else                                           // searched name is long
564        {
565            get_name_from_long( dir_entry, name_entry );
566
567            unsigned shift = ((ord & 0xf) - 1) * 13;
568            if ( _strncmp( (char*)(file_name + shift), (char*)name_entry, 13 ) == 0 )
569            {
570                if ( (ord & 0xf) == 1 )
571                {
572                    offset = offset + DIR_ENTRY_SIZE;
573                    write_entry(offset + field, size, fat.fat_cache, value);
574                    found = 1;
575                }
576                offset = offset + DIR_ENTRY_SIZE;
577                continue;
578            }
579            else                                                                       // no matching : skip
580            {
581                offset = offset + ((ord & 0xf) * DIR_ENTRY_SIZE) + DIR_ENTRY_SIZE;
582            }
583        }
584    }
585
586    return _ioc_write( 0,                // channel
587                       IOC_KERNEL_MODE,  // mode
588                       lba,              // sector index
589                       fat.fat_cache,    // source buffer
590                       1 );              // one sector
591}
592//////////////////////////////////////////////////////////////////////////////////
593// This function update FS_INFO:
594// last cluster allocated and number of free cluster.
595// Return 0 in case of success, > 0 if failure.
596//////////////////////////////////////////////////////////////////////////////////
597static inline unsigned int update_fs_info( )
598{
599    unsigned int lba = fat.fs_info_lba;
600
601#if GIET_DEBUG_FAT
602_printf("\n[FAT DEBUG] Enter update_fs_info()\n");
603#endif
604
605    if ( lba == fat.cache_lba )            // hit cache
606    {
607        write_entry( FS_FREE_CLUSTER     , fat.fat_cache, fat.number_free_cluster );
608        write_entry( FS_FREE_CLUSTER_HINT, fat.fat_cache, fat.last_cluster_allocated );
609    }
610    else                                   // miss cache
611    {
612        if ( _ioc_read( 0,                 // channel
613                        IOC_KERNEL_MODE,   // mode for IOC driver
614                        lba,               // sector index
615                        fat.fat_cache,     // source buffer
616                        1 ) )              // one sector
617        {
618            _printf("[FAT_ERROR] in update_fat() cannot read block %x\n", lba );
619            return 1;
620        }
621        fat.cache_lba = lba;
622        write_entry( FS_FREE_CLUSTER     , fat.fat_cache, fat.number_free_cluster );
623        write_entry( FS_FREE_CLUSTER_HINT, fat.fat_cache, fat.last_cluster_allocated );
624    }
625    return _ioc_write( 0,                // channel
626                       IOC_KERNEL_MODE,  // mode   
627                       lba,              // sector index
628                       fat.fat_cache,    // source buffer
629                       1 );              // one sector
630}
631
632//////////////////////////////////////////////////////////////////////////////////
633// This function update FAT, write a new value into cluster index.
634// Used by the function _fat_allocate to update the chaining of clusters.
635// Return 0 in case of success, > 0 if failure.
636//////////////////////////////////////////////////////////////////////////////////
637static inline unsigned int update_fat( unsigned int cluster, 
638                                       unsigned int value  )
639{
640    unsigned int lba = fat.fat_lba + (cluster / 128);
641
642#if GIET_DEBUG_FAT
643_printf("\n[FAT DEBUG] Enter update_fat() : cluster = %x / value = %x\n",
644        cluster, value );
645#endif
646
647    if ( lba == fat.cache_lba )            // hit cache
648    {
649        write_entry( ((cluster % 128) << 2), 4, fat.fat_cache, value );
650    }
651    else                                   // miss cache
652    {
653        if ( _ioc_read( 0,                 // channel
654                        IOC_KERNEL_MODE,   // mode for IOC driver
655                        lba,               // sector index
656                        fat.fat_cache,     // source buffer
657                        1 ) )              // one sector
658        {
659            _printf("[FAT_ERROR] in update_fat() cannot read block %x\n");
660            return 1;
661        }
662        fat.cache_lba = lba;
663        write_entry( ((cluster % 128) << 2), 4, fat.fat_cache, value );
664    }
665    return _ioc_write( 0,                // channel
666                       IOC_KERNEL_MODE,  // mode     
667                       lba,              // sector indexs
668                       fat.fat_cache,    // source buffer
669                       1 );              // one sector
670}
671
672//////////////////////////////////////////////////////////////////////////////////
673// This function allocate a count number of cluster to a file by calling the
674// update_fat function that takes care to update the chaining of clusters.
675// return 0 if success, -1 if failure
676//////////////////////////////////////////////////////////////////////////////////
677static inline int _fat_allocate( unsigned int fd_id, 
678                                 unsigned int count )
679{
680    unsigned int next_cluster        = fat.fd[fd_id].first_cluster;   // Get the first cluster of file
681    unsigned int cluster_to_allocate = count;                         // Number of cluster to allocate
682
683    unsigned int last_cluster_file;                                   // Last cluster of the file (EOC)
684
685    unsigned int free_cluster = fat.last_cluster_allocated + 1;       // First free cluster
686
687    // Check if free_cluster is really free (must be true)
688    if ( get_next_cluster_id( IOC_KERNEL_MODE, free_cluster ) != FREE_CLUSTER)
689    {
690        _printf("\n[FAT ERROR] in _fat_allocate() : first free_cluster not free\n");
691        return -1;
692    }
693    // Check if FAT contains enough cluster free for this allocation
694    if ( count > fat.number_free_cluster )
695    {
696        _printf("\n[FAT ERROR] in _fat_allocate() : Not enough free cluster(s)\n");
697        return -1;
698    }
699
700#if GIET_DEBUG_FAT
701_printf("\n[FAT DEBUG] Enter in _fat_allocate() for file %d\n", fd_id );
702#endif
703
704    // Get the last cluster allocated for the file (seek END_OF_CHAIN_CLUSTER).
705    do{
706        last_cluster_file = next_cluster;
707        next_cluster      = get_next_cluster_id( IOC_KERNEL_MODE, next_cluster );
708    }while ( next_cluster < END_OF_CHAIN_CLUSTER );
709
710    // Loop on the number of cluster needed to be allocated
711    while ( cluster_to_allocate > 0 )
712    {
713
714#if GIET_DEBUG_FAT
715_printf("\n[FAT DEBUG] cluster to update = %x / free cluster = %x / clusters required = %d\n",
716        last_cluster_file, free_cluster, cluster_to_allocate );
717#endif
718
719        // update, in the FAT, the value of last cluster allocated by the index
720        // of free cluster.
721        if ( update_fat( last_cluster_file, free_cluster ) )
722        {
723            _printf("\n[FAT ERROR] in _fat_allocate() : update fat failed\n");
724            return -1;
725        }
726
727        cluster_to_allocate = cluster_to_allocate - 1;
728        // Last cluster allocated is then free_cluster
729        last_cluster_file = free_cluster;
730
731        // Last cluster to allocate done, then we must close the chain of clusters
732        if ( cluster_to_allocate == 0 )
733        {
734            // update, in the FAT, the value of the last cluster allocated by
735            // END_OF_CHAIN_CLUSTER
736            if ( update_fat( last_cluster_file, END_OF_CHAIN_CLUSTER ) )
737            {
738                _printf("\n[FAT ERROR] in _fat_allocate() : update fat failed\n");
739                return -1;
740            }
741        }
742
743        free_cluster = free_cluster + 1;
744
745        // Check if free_cluster is really free (must be true)
746        if ( get_next_cluster_id( IOC_KERNEL_MODE, free_cluster ) != FREE_CLUSTER)
747        {
748            _printf("\n[FAT ERROR] in _fat_allocate() : free_cluster not free\n");
749            return -1;
750        }
751    }
752
753    // Update field number_free_cluster and last_cluster_allocated
754    // of structure fat for next fat_allocate
755    fat.last_cluster_allocated = last_cluster_file;
756    fat.number_free_cluster    = fat.number_free_cluster - count;
757
758    if ( update_fs_info() )
759    {
760        _printf("\n[FAT ERROR] in _fat_allocate() : update fs_info failed\n");
761        return -1;
762    }
763
764    return 0;
765}
766
767///////////////////////////////////////////////////////////////////////////////
768// This function returns the cluster index from a (32 bytes) directory entry
769///////////////////////////////////////////////////////////////////////////////
770static inline unsigned int read_cluster( char* buf )                 
771{
772   unsigned int cluster = read_entry( DIR_FST_CLUS_HI, buf, 1 ) << 16;
773   cluster = cluster | read_entry( DIR_FST_CLUS_LO, buf, 1 );
774   return cluster;
775} 
776
777
778////////////////////////////////////////////////////////////////////////////////////////
779// This function read the blocks defined by the cluster index argument, in a data
780// region containing a directory to search the name of a file/firectory,
781// and returns the cluster index of the file/directory when the name has been found.
782// Return cluster index if name found / Return -1 if not found,
783////////////////////////////////////////////////////////////////////////////////////////
784static int scan_directory( unsigned int   mode,            // mode for IOC driver
785                           unsigned int   cluster,         // cluster containing dir_entry
786                           char*          file_name,       // searched file/directory name
787                           unsigned int*  file_size,       // file size
788                           unsigned int*  lba_dir_entry )  // lba of dir_entry
789{
790
791#if GIET_DEBUG_FAT
792_printf("\n[FAT DEBUG] enter _scan_directory() searching dir/file %s", file_name );
793#endif
794
795    char dir_entry[32];   // buffer to store a full directory_entry
796    char name_entry[14];  // buffer to store a 13 characters (partial) name
797
798    char sfn[12]            = {[0 ... 10] = ' ', '\0'};   // buffer for a Short File Name
799    unsigned int  is_sfn    = is_short(file_name, sfn);   // if file_name is short, sfn = 1     
800    unsigned int  offset    = 0;                          // byte offset in block
801    unsigned int  block_id  = fat.sectors_per_cluster;   // sector index initialisation       
802    unsigned int  lba       = cluster_to_lba(cluster);   
803    unsigned int  attr      = 0;                          // directory entry attribute
804    unsigned int  ord       = 0;                          // directory entry sequence
805    unsigned int  found     = 0;                          // name found
806    unsigned int  i;
807
808    for( i = 0 ; i < 32 ; i++ ) dir_entry[i]  = 0;
809    for( i = 0 ; i < 14 ; i++ ) name_entry[i] = 0;
810
811    // load first cluster sector from DATA region into FAT cache
812    // other sectors will be loaded inside loop as required
813    if( _ioc_read( 0,               // channel
814                   mode,            // mode for IOC driver
815                   lba,             // sector index
816                   fat.fat_cache,   // buffer address
817                   1 ) )            // one sector
818    {
819        _printf("[FAT ERROR] in scan directory() cannot read sector %x\n", lba );
820        return -1;
821    }
822
823    fat.cache_lba = lba;
824
825    // in this loop we scan all names in directory identified by cluster:
826    // - the offset increment is an integer number of directory entry (32 bytes)
827    // - the exit condition is success (name found) or failure (end of directory)
828    while( 1 )
829    {
830        // load a new sector if required
831        if (offset >= 512)             
832        {
833            if ( block_id )           // not a new cluster
834            {
835                lba += 1;
836                block_id --;
837            }
838            else                                          // get next cluster
839            {
840                cluster = get_next_cluster_id( mode, cluster );
841
842                if ( cluster >= END_OF_CHAIN_CLUSTER  ) return END_OF_CHAIN_CLUSTER;
843
844                lba      = cluster_to_lba(cluster);
845                block_id = fat.sectors_per_cluster;
846            }
847            if( _ioc_read( 0,               // channel
848                           mode,            // mode for IOC driver
849                           lba,             // sector index
850                           fat.fat_cache,   // buffer address
851                           1 ) )            // one sector
852            {
853                _printf("[FAT ERROR] in scan directory() cannot read sector %x\n", lba );
854                return -1;
855            }
856            fat.cache_lba = lba;
857            block_id--;
858            offset = offset % 512;
859        }
860
861        // analyse a directory entry (pointed by fat.fat_cache + offset)
862        if ( !found )
863        { 
864            attr = read_entry( DIR_ATTR, fat.fat_cache + offset, 0);   
865            ord  = read_entry( LDIR_ORD, fat.fat_cache + offset, 0);
866
867            if ( is_sfn == 1 )                            // searched name is short
868            {
869                if      ( (ord != FREE_ENTRY ) &&
870                          (ord != NO_MORE_ENTRY) &&
871                          (attr == ATTR_LONG_NAME_MASK) )    // LFN entry : skipped
872                {
873                                        offset     = offset + ((ord & 0xF) * DIR_ENTRY_SIZE);
874                    continue;
875                }
876                else if ( (attr != ATTR_LONG_NAME_MASK) && 
877                          (ord  != FREE_ENTRY) && 
878                          (ord  != NO_MORE_ENTRY ) )         // SFN entry : checked
879                {
880                    memcpy( dir_entry, fat.fat_cache + offset, DIR_ENTRY_SIZE );   
881                    offset = offset + DIR_ENTRY_SIZE;
882                }
883                else if (ord == NO_MORE_ENTRY )              // end of directory : return
884                {
885                    return END_OF_CHAIN_CLUSTER;
886                }
887                else                                                                         // free entry : skipped
888                {
889                    offset = offset + DIR_ENTRY_SIZE;
890                    continue;
891                }
892            }
893            else                                      // searched name is long
894            {
895                if( (attr == ATTR_LONG_NAME_MASK) && 
896                    (ord != FREE_ENTRY) &&
897                    (ord != NO_MORE_ENTRY) )                 // LFN entry : checked
898                {
899                    memcpy( dir_entry, fat.fat_cache + offset, DIR_ENTRY_SIZE );   
900                    offset = offset + DIR_ENTRY_SIZE;
901                }
902                else if( (attr != ATTR_LONG_NAME_MASK) && 
903                         (ord  != FREE_ENTRY) && 
904                         (ord  != NO_MORE_ENTRY))                        // SFN entry : skipped
905                {
906                    offset = offset + DIR_ENTRY_SIZE;
907                    continue;
908                }
909                else if (ord == NO_MORE_ENTRY )                          // end of director : return
910                {
911                    return END_OF_CHAIN_CLUSTER;
912                }
913                else                                           // free entry : skipped
914                {
915                    offset = offset + DIR_ENTRY_SIZE;
916                    continue;
917                }
918            }
919
920            // testing the name extracted from dir entry
921            if ( is_sfn == 1 )                            // searched name is short
922            {
923                get_name_from_short( dir_entry, name_entry );
924
925                if ( _strncmp( (char*)sfn, (char*)name_entry, 13 ) == 0 )
926                {
927                    *file_size = read_entry( DIR_FILE_SIZE , dir_entry, 1 );
928                    *lba_dir_entry = lba;
929                    return read_cluster( dir_entry );
930                }
931            }
932            else                                         // searched name is long
933            {
934                get_name_from_long( dir_entry, name_entry );
935
936                unsigned shift = ((ord & 0xf) - 1) * 13;
937                if ( _strncmp( (char*)(file_name + shift), (char*)name_entry, 13 ) == 0 )
938                {
939                    if( (ord & 0xf) == 1 )  found = 1;
940                    continue;
941                }
942                else                                                                 // no matching : skip
943                {
944                    offset = offset + ((ord & 0xf) * DIR_ENTRY_SIZE);
945                }
946            }
947        } 
948        else    // file found
949        {
950            memcpy( dir_entry, fat.fat_cache + offset, DIR_ENTRY_SIZE );   
951            offset     = offset + DIR_ENTRY_SIZE;
952            *file_size = read_entry( DIR_FILE_SIZE, dir_entry, 1 );
953            *lba_dir_entry = lba;
954
955            return read_cluster( dir_entry );
956        }
957    }
958    return -1;
959} // end scan_directory()
960
961
962//////////////////////////////////////////////////////////////////////
963// This function create a new entry in a directory identified
964// by "dir_cluster". The name is defined by "name".
965// The type (dir/file) is defined by "is_file".
966// Returns cluster index if success, Returns -1 if error.
967//////////////////////////////////////////////////////////////////////
968static int fat_create( char*           name,
969                       unsigned int    is_file,
970                       unsigned int    dir_cluster )
971{
972    _printf("\n[FAT ERROR] _fat_create() not implemented\n");
973    return 0;
974}  //end _fat_create()
975
976
977
978////////////// Extern functions //////////////////////////////////////////
979
980//////////////////////////////////////////////////////////////////////////
981// This function initializes the FAT structure, including the
982// files descriptors array, from informations found in the boot record.
983//////////////////////////////////////////////////////////////////////////
984// Return 0 if success, Return -1 if failure
985//////////////////////////////////////////////////////////////////////////
986int _fat_init( unsigned int mode )   // mode for IOC driver
987{
988    unsigned int   n;
989
990#if GIET_DEBUG_FAT
991unsigned int procid  = _get_procid();
992unsigned int cid     = procid / NB_PROCS_MAX;
993unsigned int lpid    = procid % NB_PROCS_MAX;
994unsigned int x       = cid >> Y_WIDTH;
995unsigned int y       = cid & ((1<<Y_WIDTH) - 1);
996
997_printf("\n[FAT DEBUG] Processor[%d,%d,%d] enters _fat_init()\n",
998        x, y, lpid );
999#endif
1000   
1001    // load Boot Record (VBR) into fat cache
1002    if ( _ioc_read( 0,                   // channel
1003                    mode,                // mode for IOC driver
1004                    0,                   // sector index
1005                    fat.fat_cache,       // buffer address
1006                    1 ) )                // one sector
1007    {
1008        _printf("\n[FAT ERROR] in _fat_init() cannot load VBR\n");
1009        return -1;
1010    }
1011    fat.cache_lba = 0;
1012
1013#if GIET_DEBUG_FAT
1014_printf("\n[FAT DEBUG] Boot Sector Loaded\n");
1015#endif
1016
1017    // checking various FAT32 assuptions from boot sector
1018    if( read_entry( BPB_BYTSPERSEC, fat.fat_cache, 1 ) != 512 )
1019    {
1020        _printf("\n[FAT ERROR] The sector size must be 512 bytes\n");
1021        return -1; 
1022    }
1023    if( read_entry( BPB_NUMFATS, fat.fat_cache, 1 ) != 1 )
1024    {
1025        _printf("\n[FAT ERROR] The number of FAT copies in FAT region must be 1\n");
1026        return -1; 
1027    }
1028    if( (read_entry( BPB_FAT32_FATSZ32, fat.fat_cache, 1 ) & 0xF) != 0 )
1029    {
1030        _printf("\n[FAT ERROR] The FAT region in FAT32 must be multiple of 32 sectors\n");
1031        return -1; 
1032    }
1033    if( read_entry( BPB_FAT32_ROOTCLUS, fat.fat_cache, 1 ) != 2 )
1034    {
1035        _printf("\n[FAT ERROR] The first cluster index must be 2\n");
1036        return -1; 
1037    }
1038    // FS Info always in sector 1
1039    fat.fs_info_lba         = read_entry( BPB_FAT32_FSINFO, fat.fat_cache, 1 );
1040
1041    // initialise fat descriptor from VBR
1042    fat.sectors_per_cluster = read_entry( BPB_SECPERCLUS, fat.fat_cache, 1 );
1043    fat.sector_size         = read_entry( BPB_BYTSPERSEC, fat.fat_cache, 1 );
1044    fat.cluster_size        = fat.sectors_per_cluster * 512;
1045    fat.fat_sectors         = read_entry( BPB_FAT32_FATSZ32, fat.fat_cache, 1 );
1046    fat.fat_lba             = read_entry( BPB_RSVDSECCNT, fat.fat_cache, 1 );
1047    fat.data_lba            = fat.fat_lba + fat.fat_sectors;
1048    fat.fat_lock.value      = 0;
1049    fat.initialised         = FAT_INITIALISED;
1050
1051    // initialise file descriptor array
1052    for( n = 0 ; n < GIET_OPEN_FILES_MAX ; n++ ) fat.fd[n].used = 0;
1053
1054#if GIET_DEBUG_FAT
1055_printf("\n[FAT DEBUG] FS_INFO Sector = %x\n", fat.fs_info_lba );
1056#endif
1057
1058    // load FS_INFO into fat cache
1059    if ( _ioc_read( 0,                  // channel
1060                    mode,               // mode for IOC driver
1061                    fat.fs_info_lba,    // sector index
1062                    fat.fat_cache,      // buffer address
1063                    1 ) )               // one sector
1064    { 
1065        _printf("\n[FAT ERROR] in _fat_init() cannot load FS_INFO Sector\n"); 
1066        return -1;
1067    }
1068    fat.cache_lba = fat.fs_info_lba;
1069
1070    fat.number_free_cluster    = read_entry( FS_FREE_CLUSTER     , fat.fat_cache, 1);
1071    fat.last_cluster_allocated = read_entry( FS_FREE_CLUSTER_HINT, fat.fat_cache, 1);
1072
1073#if GIET_DEBUG_FAT
1074_printf("\n[FAT DEBUG] Processor[%d,%d,%d] exit _fat_init() / "
1075        "free clusters = %x / last allocated cluster = %x\n",
1076        x, y, lpid, fat.number_free_cluster, fat.last_cluster_allocated );
1077#endif
1078
1079    return 0;
1080}  // end _fat_init()
1081
1082/////////////////
1083void _fat_print()
1084{
1085    _printf("\n########################## FAT32 ###########################"); 
1086    _printf("\nFAT initialised                %x", fat.initialised );
1087    _printf("\nSector Size  (bytes)           %x", fat.sector_size );
1088    _printf("\nSectors per cluster            %x", fat.sectors_per_cluster );
1089    _printf("\nFAT region first lba           %x", fat.fat_lba );
1090    _printf("\nData region first lba          %x", fat.data_lba );
1091    _printf("\nNumber of sectors for one FAT  %x", fat.fat_sectors );
1092    _printf("\n############################################################\n");
1093}
1094
1095///////////////////////////////////////////////////////////////////////////////
1096// This function checks that the kernel FAT structure has been initialised.
1097// It makes the FAT initialisation if it is the first open request.
1098// This function searches a file identified by the "pathname" argument.
1099// It starts from root (cluster 2) to scan successively each subdirectory.
1100// When the file is not found, but the path is found, and "creat" is set,
1101// a new file is created and introduced in the directory.
1102// Finally, it sets a new open file in the file descriptors array.
1103// The same file can be open several times by differents tasks.
1104///////////////////////////////////////////////////////////////////////////////
1105// Returns file descriptor index if success, returns -1 if error.
1106///////////////////////////////////////////////////////////////////////////////
1107int _fat_open( unsigned     mode,
1108               char*        pathname,
1109               unsigned int creat )
1110{
1111    char                 name[256];        // buffer for one name in pathname
1112    unsigned int         nb_read;              // number of characters written in name[]
1113    unsigned int         cluster;          // current cluster index when scanning FAT
1114    unsigned int         dir_cluster;      // previous cluster index when scanning FAT
1115    unsigned int         fd_id;            // index when scanning file descriptors array
1116    unsigned int         file_size = 0;    // number of bytes
1117    unsigned int         last_name = 0;    // directory containing file name is reached
1118    unsigned int         lba       = 0;    // lba of dir_entry for this file
1119   
1120#if GIET_DEBUG_FAT
1121unsigned int procid  = _get_procid();
1122unsigned int cid     = procid / NB_PROCS_MAX;
1123unsigned int lpid    = procid % NB_PROCS_MAX;
1124unsigned int x       = cid >> Y_WIDTH;
1125unsigned int y       = cid & ((1<<Y_WIDTH) - 1);
1126
1127_printf("\n[FAT DEBUG] Processor[%d,%d,%d] enters _fat_open() for file %s\n",
1128        x, y, lpid, pathname );
1129#endif
1130
1131    // checking arguments
1132    if ( creat )
1133    {
1134        _printf("[FAT ERROR] in _fat_open() : create not supported yet\n");
1135        return -1;
1136    }
1137
1138    // takes the FAT lock for exclusive access
1139    _get_lock( &fat.fat_lock );
1140
1141#if GIET_DEBUG_FAT
1142_printf("\n[FAT DEBUG] Processor[%d,%d,%d] takes the FAT lock\n",
1143        x, y, lpid );
1144#endif
1145
1146    // FAT initialisation if required
1147    if( fat.initialised != FAT_INITIALISED )
1148    {
1149        if ( _fat_init( mode ) )
1150        {
1151            _printf("[FAT ERROR] in _fat_open() : Cannot initialize FAT descriptor\n");
1152
1153            // release FAT lock
1154            _release_lock( &fat.fat_lock );
1155
1156            return -1;
1157        }
1158
1159#if GIET_DEBUG_FAT
1160_printf("\n[FAT DEBUG] Processor[%d,%d,%d] initialises FAT descriptor\n",
1161        x, y, lpid );
1162_fat_print();
1163#endif
1164
1165    }
1166 
1167    // Scan the directories, starting from the root directory (cluster 2)
1168    // - The get_name_from_path() function extracts (successively)
1169    //   each directory name from the pathname, and store it in name[] buffer
1170    // - The scan_directory() function scan one (or several) cluster(s) containing
1171    //   a directory looking for name[], and return the cluster index
1172    //   corresponding to the directory/file found.
1173    nb_read     = 0;
1174    cluster     = 2;
1175    last_name   = 0;
1176    while ( get_name_from_path( pathname, name, &nb_read) )
1177    {
1178
1179#if GIET_DEBUG_FAT
1180_printf("\n[FAT DEBUG] Processor[%d,%d,%d] search dir/file : %s\n",
1181        x, y, lpid, name );
1182#endif
1183
1184        // test if we reach the last name (file name)
1185        if( pathname[nb_read] == 0 ) 
1186        {
1187            last_name   = 1;
1188            dir_cluster = cluster;
1189        }
1190
1191        // scan current directory
1192        cluster  = scan_directory( mode, cluster, name, &file_size, &lba );
1193
1194        if( cluster == END_OF_CHAIN_CLUSTER && last_name && creat )
1195        {
1196            cluster = fat_create( name, 1, dir_cluster );
1197        }
1198        else if ( cluster == END_OF_CHAIN_CLUSTER )
1199        {
1200            _printf("\n[FAT ERROR] in _fat_open() cannot found %s\n", name );
1201
1202            // release FAT lock
1203            _release_lock( &fat.fat_lock );
1204
1205            return -1;
1206        }
1207    }
1208
1209    // check the next value for cluster index found
1210    unsigned next = get_next_cluster_id( mode, cluster );
1211
1212    if ( (next != BAD_CLUSTER) && (next != FREE_CLUSTER) )
1213    {
1214        // Search an empty slot scanning open file descriptors array
1215        fd_id = 0;
1216        while ( fat.fd[fd_id].used != 0 && fd_id < GIET_OPEN_FILES_MAX )
1217        {
1218            fd_id++;
1219        }
1220
1221        // set file descriptor if found empty slot
1222        if ( fd_id < GIET_OPEN_FILES_MAX )
1223        {
1224            fat.fd[fd_id].used          = 1;
1225            fat.fd[fd_id].first_cluster = cluster;
1226            fat.fd[fd_id].file_size     = file_size;
1227            fat.fd[fd_id].lba_dir_entry = lba;
1228            _strcpy( fat.fd[fd_id].name, pathname );
1229
1230#if GIET_DEBUG_FAT
1231_printf("\n[FAT DEBUG] Processor[%d,%d,%d] open file %s with fd = %d\n",
1232        x, y, lpid, pathname, fd_id );
1233#endif
1234
1235            // release FAT lock
1236            _release_lock( &fat.fat_lock );
1237
1238            return fd_id;
1239        }
1240        else
1241        {
1242            _printf("\n[FAT ERROR] in _fat_open() for file %s : fd array full\n",
1243                    pathname );
1244
1245            // release FAT lock
1246            _release_lock( &fat.fat_lock );
1247
1248            return -1;
1249        }
1250    }
1251    else
1252    {
1253        _printf("\n[FAT ERROR] in _fat_open() for file %s : bad cluster\n",
1254                pathname );
1255
1256        // release FAT lock
1257        _release_lock( &fat.fat_lock );
1258
1259        return -1;
1260    }
1261} // end _fat_open()
1262
1263///////////////////////////////////////////////////////////////////////////////
1264// For an open file, identified by the file descriptor index, transfer
1265// an integer number of sectors from block device to a memory buffer.
1266// If the number of requested sectors exceeds the file size, it is reduced.
1267///////////////////////////////////////////////////////////////////////////////
1268// Returns number of sectors transfered if success, < 0 if error.
1269///////////////////////////////////////////////////////////////////////////////
1270int _fat_read( unsigned int mode,       // mode for IOC driver
1271               unsigned int fd_id,      // file descriptor
1272               void*        buffer,     // target buffer base address
1273               unsigned int count,      // number of sector to read
1274               unsigned int offset )    // nuber of sectors to skip in file
1275{
1276    unsigned int spc = fat.sectors_per_cluster;
1277
1278    unsigned int file_size;         // number of bytes in file
1279    unsigned int file_sectors;      // number of sectors in file
1280    unsigned int total_sectors;     // actual number of sectors to be transfered
1281    unsigned int cluster;           // cluster index
1282    unsigned int clusters_to_skip;  // number of clusters to skip because offset
1283    unsigned int sectors_to_skip;   // number of sectors to skip in first iteration
1284
1285    // compute file size as a number of sectors
1286    file_size    = fat.fd[fd_id].file_size;
1287    if ( file_size & 0x1FF ) file_sectors = (file_size >> 9) + 1;
1288    else                     file_sectors = (file_size >> 9); 
1289
1290    // arguments checking
1291    if ( fd_id >= GIET_OPEN_FILES_MAX )
1292    { 
1293        _printf("\n[FAT ERROR] in _fat_read() : illegal file descriptor index\n");
1294        return -1;
1295    }
1296    if ( fat.fd[fd_id].used != 1 )
1297    {
1298        _printf("\n[FAT ERROR] in _fat_read() : file not open\n");
1299        return -1;
1300    }
1301    if ( ((unsigned int)buffer & 0x1FF) != 0 )
1302    {
1303        _printf("\n[FAT ERROR] in _fat_read() : memory buffer not sector aligned\n");
1304        return -1;
1305    }
1306    if ( offset >= file_sectors )
1307    {
1308        _printf("\n[FAT ERROR] offset larger than number of sectors\n");
1309        return -1;
1310    }
1311
1312    // compute total number of sectors to read
1313    if ( file_sectors < (offset + count) ) total_sectors = file_sectors - offset;
1314    else                                   total_sectors = count;
1315
1316    // compute clusters and sectors to be skipped
1317    clusters_to_skip = offset / spc;
1318    sectors_to_skip  = offset % spc;
1319   
1320    // get first cluster index
1321    cluster = fat.fd[fd_id].first_cluster;
1322
1323#if GIET_DEBUG_FAT
1324unsigned int procid  = _get_procid();
1325unsigned int cid     = procid / NB_PROCS_MAX;
1326unsigned int lpid    = procid % NB_PROCS_MAX;
1327unsigned int x       = cid >> Y_WIDTH;
1328unsigned int y       = cid & ((1<<Y_WIDTH) - 1);
1329
1330_printf("\n[FAT DEBUG] Processor[%d,%d,%d] enters _fat_read() for file %s\n"
1331        " - buffer vbase    = %x\n"
1332        " - skipped sectors = %x\n"
1333        " - read sectors    = %x\n"
1334        " - first cluster   = %x\n"
1335        " - skiped clusters = %x\n",
1336        x, y, lpid, fat.fd[fd_id].name, 
1337        (unsigned int)buffer, offset, count, cluster, clusters_to_skip );   
1338#endif
1339
1340    // compute index of first cluster to be loaded
1341    // as we may need to scan the FAT, we use the kernel mode
1342    while ( clusters_to_skip )
1343    {
1344        cluster = get_next_cluster_id( IOC_KERNEL_MODE, cluster );
1345        clusters_to_skip--;
1346    }
1347
1348    // variables used in the loop on clusters
1349    int             todo_sectors;   // number of sectors still to be loaded
1350    unsigned int    lba;            // first sector index on device
1351    unsigned int    iter_sectors;   // number of sectors to load in iteration
1352    char*           dst;            // pointer on target buffer
1353
1354    // initialize these variables for the first iteration
1355    todo_sectors  = total_sectors;
1356    dst           = (char*)buffer;
1357    lba           = cluster_to_lba(cluster) + sectors_to_skip;
1358    if( total_sectors < (spc - sectors_to_skip) ) iter_sectors = total_sectors;
1359    else                                          iter_sectors = spc - sectors_to_skip; 
1360
1361    // loop on the clusters
1362    while ( todo_sectors > 0 )
1363    {
1364
1365#if GIET_DEBUG_FAT
1366_printf("\n[FAT DEBUG] Processor[%d,%d,%d] makes an IOC read :"
1367        " buf = %x / lba = %x / sectors = %d\n",
1368        x, y, lpid, (unsigned int)dst, lba, iter_sectors );
1369#endif
1370
1371        if( _ioc_read( 0,                 // channel
1372                       mode,              // mode for IOC driver
1373                       lba,               // first sector index
1374                       dst,               // buffer address
1375                       iter_sectors ) )   // number of sectors
1376        {
1377            _printf("\n[FAT ERROR] in _fat_read() cannot load block %x\n", lba );
1378            return -1;
1379        }
1380         
1381        // update variables for next iteration
1382        cluster      = get_next_cluster_id( mode, cluster );
1383        todo_sectors = todo_sectors - iter_sectors;
1384        dst          = dst + (iter_sectors << 9);
1385        lba          = cluster_to_lba(cluster);
1386        if ( todo_sectors > spc ) iter_sectors = spc;
1387        else                      iter_sectors = todo_sectors;
1388    }
1389         
1390    // returns number of sectors actually transfered
1391    return total_sectors;
1392
1393}  // end _fat_read()
1394
1395///////////////////////////////////////////////////////////////////////////////
1396// For an open file, identified by the file descriptor index, transfer
1397// an integer number of sectors from a memory buffer to block device.
1398// Allocate new clusters if the offset+count larger than current file size,
1399// but the offset should be smaller than the current file size...
1400// - fat    : pointer on FAT
1401// - mode   : mode for the IOC driver
1402// - fd_id  : open file descriptor index 
1403// - buffer : base address of the memory buffer (must be sector aligned)
1404// - offset : number of sectors to skip in file
1405// - count  : number of sectors to be written.
1406///////////////////////////////////////////////////////////////////////////////
1407// Returns number of sectors written if success, < 0 if error.
1408///////////////////////////////////////////////////////////////////////////////
1409int _fat_write( unsigned int mode,       // mode for IOC driver
1410                unsigned int fd_id,      // file descriptor
1411                void*        buffer,     // target buffer base address
1412                unsigned int count,      // number of sector to write
1413                unsigned int offset )    // nuber of sectors to skip in file
1414{
1415
1416    unsigned int spc = fat.sectors_per_cluster;
1417
1418    unsigned int file_size;         // number of bytes in file
1419    unsigned int file_sectors;      // number of sectors in file
1420    unsigned int cluster;           // cluster index
1421    unsigned int clusters_to_skip;  // number of clusters to skip because offset
1422    unsigned int sectors_to_skip;   // number of sectors to skip in first iteration
1423    unsigned int allocate;          // need allocate or not
1424    unsigned int current_cluster;   // number of cluster allocated to the file
1425    unsigned int required_cluster;  // number of cluster needed for the write
1426
1427    // compute file size as a number of sectors
1428    file_size    = fat.fd[fd_id].file_size;
1429    if ( file_size & 0x1FF ) file_sectors = (file_size >> 9) + 1;
1430    else                     file_sectors = (file_size >> 9); 
1431
1432    // Compute the number of clusters occupied by the file
1433    current_cluster = file_sectors / spc;
1434
1435    // Compute the number of clusters that will occupy the file (after fat_write)
1436    required_cluster = (count + offset) / spc;
1437
1438    // Check if we need to allocate new cluster(s) for the file 
1439    allocate = ( required_cluster > current_cluster );
1440
1441#if GIET_DEBUG_FAT
1442unsigned int procid  = _get_procid();
1443unsigned int cid     = procid / NB_PROCS_MAX;
1444unsigned int lpid    = procid % NB_PROCS_MAX;
1445unsigned int x       = cid >> Y_WIDTH;
1446unsigned int y       = cid & ((1<<Y_WIDTH) - 1);
1447
1448_printf("\n[FAT DEBUG] Processor[%d,%d,%d] enters _fat_write() for file %s\n",
1449        " - buffer vbase    = %x\n"
1450        " - skipped sectors = %x\n"
1451        " - write sectors   = %x\n" 
1452        " - file sectors    = %x\n" 
1453        " - need allocate   = %d\n", 
1454        x, y, lpid, fat.fd[fd_id].name, (unsigned int)buffer, 
1455        offset, count, file_sectors, allocate );
1456#endif
1457
1458    // arguments checking
1459    if ( fd_id >= GIET_OPEN_FILES_MAX )
1460    { 
1461        _printf("\n[FAT ERROR] in _fat_write() : illegal file descriptor index\n");
1462        return -1;
1463    }
1464    if ( fat.fd[fd_id].used != 1 )
1465    {
1466        _printf("\n[FAT ERROR] in _fat_write() : file not open\n");
1467        return -1;
1468    }
1469    if ( ((unsigned int)buffer & 0x1FF) != 0 )
1470    {
1471        _printf("\n[FAT ERROR] in _fat_write() : memory buffer not sector aligned\n");
1472        return -1;
1473    }
1474
1475    if ( allocate  )
1476    {
1477        if ( _fat_allocate( fd_id, (required_cluster - current_cluster) ) < 0 )
1478        {
1479            _printf("\n[FAT ERROR] in _fat_write() : fat_allocate failed\n");
1480            return -1;
1481        }
1482    }
1483
1484    // compute clusters and sectors to be skipped
1485    clusters_to_skip = offset / spc;
1486    sectors_to_skip  = offset % spc;
1487   
1488    // get first cluster index
1489    cluster = fat.fd[fd_id].first_cluster;
1490
1491#if GIET_DEBUG_FAT
1492_printf(" - first cluster   = %x\n"
1493        " - skiped clusters = %x\n",
1494        cluster, clusters_to_skip );   
1495#endif
1496
1497    // compute index of first cluster to be loaded
1498    // as we may need to scan the FAT, we use the kernel mode
1499    while ( clusters_to_skip )
1500    {
1501        cluster = get_next_cluster_id( IOC_KERNEL_MODE, cluster );
1502        clusters_to_skip--;
1503    }
1504
1505    // variables used in the loop on clusters
1506    int             todo_sectors;   // number of sectors still to be loaded
1507    unsigned int    lba;            // first sector index on device
1508    unsigned int    iter_sectors;   // number of sectors to load in iteration
1509    char*           src;            // pointer on target buffer
1510
1511    // initialize these variables for the first iteration
1512    todo_sectors  = count;
1513    src           = (char*)buffer;
1514    lba           = cluster_to_lba(cluster) + sectors_to_skip;
1515    if( count < (spc - sectors_to_skip) ) iter_sectors = count;
1516    else                                  iter_sectors = spc - sectors_to_skip; 
1517
1518    // loop on the clusters
1519    while ( todo_sectors > 0 )
1520    {
1521
1522#if GIET_DEBUG_FAT
1523_printf("\n[FAT DEBUG] Processor[%d,%d,%d] makes an IOC write : "
1524        "buf = %x / lba = %x / sectors = %x\n",
1525        x, y, lpid, (unsigned int)src, lba, iter_sectors );
1526#endif
1527
1528        if( _ioc_write( 0,                 // channel
1529                        mode,              // mode for IOC driver
1530                        lba,               // first sector index
1531                        src,               // source buffer address
1532                        iter_sectors ) )   // number of sectors
1533        {
1534            _printf("\n[FAT ERROR] in _fat_write() cannot write block %x\n", lba );
1535            return -1;
1536        }
1537         
1538        // update variables for next iteration
1539        cluster      = get_next_cluster_id( mode, cluster );
1540        todo_sectors = todo_sectors - iter_sectors;
1541        src          = src + (iter_sectors << 9);
1542        lba          = cluster_to_lba(cluster);
1543        if ( todo_sectors > spc ) iter_sectors = spc;
1544        else                      iter_sectors = todo_sectors;
1545    }
1546
1547    // Update structure file descriptor, field file_size with
1548    // the new file size if the file is bigger than the previous file
1549    if ( ( offset + count ) > file_sectors )
1550    {
1551        fat.fd[fd_id].file_size = (count + offset) << 9;
1552    }
1553
1554    // Update entry of directory with the new value
1555    // of file size (Field : DIR_FILE_SIZE)
1556    if ( update_entry(fd_id, DIR_FILE_SIZE, fat.fd[fd_id].file_size) )
1557    {
1558            _printf("\n[FAT ERROR] in _fat_write() update entry failed\n");
1559            return -1;
1560    }
1561         
1562    // returns number of sectors actually transfered
1563    return count;
1564}
1565
1566/////////////////////////////////////////////////////////////////////////////////
1567// Return stats of a file identified by "fd".
1568// (Only the file_size in sectors for this moment)
1569/////////////////////////////////////////////////////////////////////////////////
1570// Returns file size (on sectors) on success, -1 on failure.
1571/////////////////////////////////////////////////////////////////////////////////
1572int _fat_fstat( unsigned int fd_id )
1573{
1574    unsigned int file_size    = 0;
1575    unsigned int file_sectors = 0;
1576
1577    if( (fd_id < GIET_OPEN_FILES_MAX) )
1578    {
1579        file_size = fat.fd[fd_id].file_size;
1580
1581        if ( file_size & 0x1FF ) file_sectors = (file_size >> 9) + 1;
1582        else                     file_sectors = (file_size >> 9); 
1583
1584        return file_sectors;
1585    }
1586    else
1587    {
1588        _printf("\n[FAT ERROR] in _fat_fstat() : illegal file descriptor index\n");
1589        return -1;
1590    } 
1591} // end _fat_fstat()
1592
1593/////////////////////////////////////////////////////////////////////////////////
1594// Close the file identified by the file_descriptor index.
1595/////////////////////////////////////////////////////////////////////////////////
1596// Returns 0 on success, -1 on failure.
1597/////////////////////////////////////////////////////////////////////////////////
1598int _fat_close( unsigned int fd_id )
1599{
1600    if( (fd_id < GIET_OPEN_FILES_MAX) )
1601    {
1602        fat.fd[fd_id].used = 0;
1603        return 0;
1604    }
1605    else
1606    {
1607        _printf("\n[FAT ERROR] in _fat_close() : illegal file descriptor index\n");
1608        return -1;
1609    } 
1610} // end fat_close()
1611
1612/////////////////////////////////////////////////////////////////////////////////////
1613// The following function implement the user_level system call.
1614// The flags argument is nor used, as file access modes are not implemented yet.
1615/////////////////////////////////////////////////////////////////////////////////////
1616// Return the file descriptor index if success / return -1 if failure
1617/////////////////////////////////////////////////////////////////////////////////////
1618int _fat_user_open( char*  pathname,         // absolute pathname from root
1619                    unsigned int flags )     // unused: TODO
1620{
1621    return _fat_open( IOC_KERNEL_MODE,       // we use KERNEL_MODE, because
1622                      pathname,              // we need to write into FAT cache
1623                      0 );                   // no creation if not found
1624}
1625
1626/////////////////////////////////////////////////////////////////////////////////////
1627// The following function implement the user_level system call.
1628// This function should be modified to respect the UNIX specification
1629/////////////////////////////////////////////////////////////////////////////////////
1630// Return number of sectors actually transfered if success / return -1 if failure
1631/////////////////////////////////////////////////////////////////////////////////////
1632int _fat_user_read( unsigned int fd,        // file descriptor index
1633                    void*        buffer,    // destination buffer
1634                    unsigned int count,     // number of sectors to read
1635                    unsigned int offset )   // number of sectors to skip
1636{
1637    return _fat_read( IOC_USER_MODE,
1638                      fd,
1639                      buffer, 
1640                      count, 
1641                      offset );
1642}
1643
1644/////////////////////////////////////////////////////////////////////////////////////
1645// The following function implement the user_level system call.
1646// This function should be modified to respect the UNIX specification.
1647/////////////////////////////////////////////////////////////////////////////////////
1648// Return number of sectors actually transfered if success / return -1 if failure
1649/////////////////////////////////////////////////////////////////////////////////////
1650int _fat_user_write( unsigned int fd,       // file descriptor
1651                     void*        buffer,   // source buffer
1652                     unsigned int count,    // number of sectors to write
1653                     unsigned int offset )  // number of sectors to skip on file
1654{
1655    return _fat_write( IOC_USER_MODE,
1656                       fd,
1657                       buffer, 
1658                       count, 
1659                       offset );
1660}
1661
1662/////////////////////////////////////////////////////////////////////////////////////
1663int _fat_user_lseek( unsigned int fd_id,
1664                     unsigned int offset,
1665                     unsigned int whence )
1666{
1667    _printf("[GIET ERROR] _fat_user_lseek() not implemented\n");
1668    _exit();
1669    return 0;
1670}
1671
1672
1673// Local Variables:
1674// tab-width: 4
1675// c-basic-offset: 4
1676// c-file-offsets:((innamespace . 0)(inline-open . 0))
1677// indent-tabs-mode: nil
1678// End:
1679// vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
1680
Note: See TracBrowser for help on using the repository browser.