source: trunk/boot/tsar_mips32/boot_fat32.c @ 578

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

Introduce the cluster_info[x][y] in the boot_info.h structure for the TSAR architecture.

  • Property svn:executable set to *
File size: 36.8 KB
Line 
1#include "boot_fat32.h"
2
3#include <boot_config.h>
4#include <boot_utils.h>
5
6#include <boot_tty_driver.h>
7#include <boot_bdv_driver.h>
8#include <boot_hba_driver.h>
9#include <boot_mmc_driver.h>
10
11/*
12#include <boot_spi_driver.h>
13#include <boot_sdc_driver.h>
14#include <boot_rdk_driver.h>
15*/
16
17#define FAT_MAGIC_VALUE  0x12345678   // FAT descriptor initialized
18
19/****************************************************************************
20 *                            Global variables.                             *
21 ****************************************************************************/
22
23// FAT32 descriptor
24fat_desc_t      boot_fat            __attribute__((aligned(64)));
25
26// Buffer used for FAT scanning
27uint32_t        buffer_fat[1024]    __attribute__((aligned(64)));
28
29// Buffer used for directory scanning
30unsigned char   buffer_dir[4096]    __attribute__((aligned(64)));
31
32// LBA of cluster currently stored in buffer_fat
33uint32_t    buffer_fat_lba;
34
35// LBA of cluster currently stored in buffer_dir
36uint32_t    buffer_dir_lba;
37
38/****************************************************************************
39 *                           Internal functions & macros.                   *
40 ****************************************************************************/
41
42/****************************************************************************
43 * These functions return the first or second argument from a couple        *
44 * of arguments ( offset , size ) used to define a data field               *         
45 * in a buffer of bytes: offset is the first byte index in buffer,          *
46 * size is the field length in bytes.                                       *
47 ****************************************************************************/
48
49static inline int get_offset( int offset, int size __attribute__((unused)) ) { return offset; }
50
51static inline int get_size( int offset __attribute__((unused)) , int size ) { return size; }
52
53/****************************************************************************
54 * This function reads a data field (less than 4 bytes) from 'buffer',      *
55 * taking endianness into account. The field to be analyzed is defined by   *
56 * 'offset' and 'size'.                                                     *
57 * @ offset         : offset (in bytes) from the beginning of the buffer    *
58 * @ size           : size (in bytes) of the field to be read               *
59 * @ buffer         : base address of the buffer                            *
60 * @ little_endian  : 1 if buffer is in little-endian format / 0 otherwise  *
61 *                                                                          *
62 * @ returns the value read from the data field.                            *
63 ****************************************************************************/
64static uint32_t read_field( uint32_t         offset,
65                            uint32_t         size,
66                            unsigned char*   buffer,
67                            uint32_t         little_endian )
68{
69    uint32_t res = 0; 
70    uint32_t i; 
71
72    for (i = 0; i < size; i++)
73    {
74        if (little_endian)       // Least significant bytes are stored first
75        {
76            res |= buffer[offset+i] << (8*i);
77        }
78        else                     // Most significant bytes are stored first
79        {
80            res |= buffer[offset+i] << 8*(size - i - 1);
81        }
82    }
83
84    return res;
85
86} // read_field()
87
88/****************************************************************************
89 * This function transfers 'count' sectors from the block device and a      *
90 * memory buffer by calling the relevant driver.                            *
91 * @ lba        : first sector address on the block device.                 *
92 * @ buff_addr  : memory buffer physical address.                           *
93 * @ count      : number of sectors to be transfered.                       *
94 * @ returns 0 on success, -1 on error.                                     *
95 ****************************************************************************/
96static int fat_ioc_access( uint32_t lba, 
97                           xptr_t   buf_paddr,
98                           uint32_t count)
99{
100    // Call the appropriate driver
101
102#if     USE_IOC_BDV
103    return ( boot_bdv_access( lba, buf_paddr, count) );
104#elif   USE_IOC_HBA
105    return ( boot_hba_access( lba, buf_paddr, count) );
106#elif   USE_IOC_SPI
107    return ( boot_spi_access( lba, buf_paddr, count) );
108/*
109#elif   USE_IOC_SDC
110    return ( boot_sdc_access( lba, buf_paddr, count) );
111#elif   USE_IOC_RDK
112    return ( boot_rdk_access( lba, buf_paddr, count) );
113*/
114
115#else
116    boot_printf("\n[BOOT ERROR] in fat_ioc_access(): IOC driver not defined\n");
117    return 1;
118#endif
119
120} // fat_ioc_access()
121
122/****************************************************************************
123 * This function directly accesses the FS Information Sector on the block   *
124 * device to set the free_cluster_hint and free_clusters_nr fields of       *
125 * the FAT32 descriptor.                                                    *
126 * @ returns 0 on success, -1 on error.                                     *
127 ****************************************************************************/
128static int set_fsi( void )
129{
130#if DEBUG_BOOT_FAT32   
131    boot_printf("\n[BOOT INFO] %s enters at cycle %d\n",
132                __FUNCTION__ , boot_get_proctime() );
133#endif
134
135    // Load FS Information Sector into the FAT buffer
136    if ( fat_ioc_access( boot_fat.fsi_lba,
137                         XPTR( BOOT_CORE_CXY , boot_fat.block_buffer ),
138                         1 ) )
139    {
140        boot_printf("\n[BOOT ERROR] %s: Cannot load FS Information Sector\n",
141                    __FUNCTION__ );
142        return -1;
143    }
144
145#if DEBUG_BOOT_FAT32   
146    boot_printf("\n[BOOT INFO] %s : FSI Sector loaded at cycle %d\n",
147                __FUNCTION__ , boot_get_proctime() );
148#endif
149
150    boot_fat.block_buffer_lba = boot_fat.fsi_lba;
151
152    // Get free_clusters_nr field from FS Information Sector
153    boot_fat.free_clusters_nr = read_field(FSI_FREE_COUNT,
154                                           boot_fat.block_buffer,
155                                           1);
156
157    // check free clusters number no larger than total number of clusters
158    if (boot_fat.free_clusters_nr >= (boot_fat.data_sectors >> 3))
159    {
160        boot_printf("\n[BOOT ERROR] %s: FSI_FREE_COUNT in FSI sector (%x)\n",
161                    "\texceeds number of data clusters (%x)\n",
162                    __FUNCTION__ , boot_fat.free_clusters_nr , (boot_fat.data_sectors >> 3));
163        return -1;
164    }
165
166    // Get free_cluster_hint field from FS Information Sector
167    boot_fat.free_cluster_hint = read_field(FSI_NXT_FREE,
168                                            boot_fat.block_buffer,
169                                            1);
170    // check free_cluster_hint no larger than total number of clusters
171    if (boot_fat.free_cluster_hint >= (boot_fat.data_sectors >> 3))
172    {
173        boot_printf("\n[BOOT ERROR] %s: FSI_NXT_FREE in FSI sector (%x)\n",
174                    "\texceeds number of data clusters (%x)\n",
175                    __FUNCTION__ , boot_fat.free_cluster_hint , (boot_fat.data_sectors >> 3));
176        return -1;
177    }
178
179#if DEBUG_BOOT_FAT32   
180    boot_printf("\n[BOOT INFO] %s : free_clusters_nr = %x / free_cluster_hint = %x\n",
181                __FUNCTION__ , boot_fat.free_clusters_nr , boot_fat.free_cluster_hint );
182#endif
183
184    return 0;
185
186} // set_fsi()
187
188/****************************************************************************
189 * This debug function displays the FAT32 File System descriptor content.   *
190 ****************************************************************************/
191
192#if DEBUG_BOOT_FAT32   
193
194static void fat32_desc_display( void )
195{
196    boot_printf("\n############### FAT32 DESCRIPTOR ####################"
197                "\nFAT initialized:                         %x"
198                "\nSector size (in bytes):                  %x"
199                "\nCluster size (in bytes):                 %x"
200                "\nFAT Region LBA:                          %x"
201                "\nFAT Region size (in sectors):            %x"
202                "\nDATA Region LBA:                         %x"
203                "\nDATA Region size (in sectors):           %x"
204                "\nCount of free clusters:                  %x"
205                "\nMost recently allocated cluster number:  %x"
206                "\n#####################################################\n",
207                 boot_fat.initialized,
208                 boot_fat.sector_size,
209                 boot_fat.cluster_size,
210                 boot_fat.fat_lba,
211                 boot_fat.fat_sectors,
212                 boot_fat.data_lba,
213                 boot_fat.data_sectors,
214                 boot_fat.free_clusters_nr,
215                 boot_fat.free_cluster_hint
216               );
217
218} // fat32_desc_display()
219
220#endif
221
222/****************************************************************************
223 * This function computes the logical block address (LBA) of the data       *
224 * cluster whose number is 'cluster_number'. It exits if 'cluster_number'   *
225 * value is smaller than 2.                                                 *
226 * @ cluster_number : number of the cluster whose LBA is desired.           *
227 *                                                                          *
228 * @ returns the LBA of the cluster.                                        *
229 ***************************************************************************/
230static uint32_t cluster_to_lba(uint32_t cluster_number)
231{
232    /*
233     * The clusters begin their numbering at 2, so there is no cluster #0
234     * or cluster #1.
235     */
236    if (cluster_number < 2)
237    {
238        boot_printf("\n[BOOT ERROR] cluster_to_lba(): "
239                    "Cluster number smaller than 2\n");
240        boot_exit();
241    }
242
243    /*
244     * LBA = boot_fat.data_lba + ((cluster_number - 2) *
245     *       (boot_fat.cluster_size /boot_fat.sector_size));
246     */
247    return (boot_fat.data_lba + ((cluster_number - 2) << 3));
248
249} // cluster_to_lba()
250
251/****************************************************************************
252 * This function directly looks up the FAT to find the entry corresponding  *
253 * to 'cur_cluster' and return the value stored in this entry (usually the  *
254 * index of the next cluster in the cluster chain).                         *
255 * @ cur_cluster    : index of current cluster.                             *
256 * @ nxt_cluster    : pointer to the Rbuffer for the next cluster index.    *
257 * @ returns 0 on success, -1 on error.                                     *
258 ****************************************************************************
259 * Implementation note
260 * There is two versions:
261 * - In the "software engineer" version, the FAT is seen as a set of sectors
262 *   containing 128 FAT entries each.
263 *   + : buffer of only 512 bytes is needed (we only read a sector).
264 *   - : nonetheless, I find it less elegant than the other one:
265 *       divisions and multiplications using MULT and DIV instructions are
266 *       usually slower.
267 * - In the "hardware engineer" version, the FAT is seen as a set of clusters
268 *   containing 1024 FAT entries each.
269 *   + : divisions and multiplications are actually performed via SHIFT
270 *       operations, which are much faster on 2s complement architectures.
271 *       Personally, I pretty like this "hardware" approach.
272 *   - : on current Intel X86 processors, MULT and DIV instructions are
273 *       heavily optimized for multiplication and division by powers of 2.
274 *       Moreover, since we read a cluster of FAT entries, the buffer needs
275 *       to be of 4096 bytes.
276 ****************************************************************************/
277
278/*
279static int get_next_cluster_soft(uint32_t    cur_cluster,
280                                 uint32_t*   nxt_cluster)
281{
282    uint32_t fat_region_offset;     // Offset of 'cur_cluster' in the
283                                        // FAT Region (in bytes)
284    uint32_t fat_sec_lba;           // LBA of the FAT sector that
285                                        // contains the entry for
286                                        // 'cur_cluster' in the FAT
287    uint32_t fat_entry_offset;      // Offset of the entry
288                                        // corresponding to 'cur_cluster'
289                                        // in 'fat_sec_num'
290
291    // Initialize the variables
292    fat_region_offset   = cur_cluster * FAT_ENTRY_SIZE;
293    fat_sec_lba         = boot_fat.fat_lba +
294                          fat_region_offset / boot_fat.sector_size;
295    fat_entry_offset    = fat_region_offset % boot_fat.sector_size;
296
297    // Read the FAT sector containing the FAT entry for 'cur_cluster'
298    if (buffer_fat_lba != fat_sec_lba)
299    {
300        if ( fat_ioc_access( fat_sec_lba,
301                             (uint32_t)buffer_fat,
302                             1 ) )
303        {
304            boot_printf("\n[BOOT ERROR] get_next_cluster_soft(): "
305                        "Cannot load sector of LBA %x into buffer_fat\n",
306                        fat_sec_lba);
307            return -1;
308        }
309
310        buffer_fat_lba = fat_sec_lba;
311    }
312
313    // Fetch the content of the entry
314    *nxt_cluster = *(uint32_t*)&buffer_fat[fat_entry_offset] & 0x0FFFFFFF;
315
316    // Check the previously read value of the next cluster number
317    if ((*nxt_cluster < USED_MIN) || (*nxt_cluster > USED_MAX))
318    {
319        boot_printf("\n[BOOT ERROR] get_next_cluster_soft(): "
320                    "Illegal next cluster number (%x)\n",
321                    *nxt_cluster);
322        return -1;
323    }
324
325    return 0;
326
327} // get_next_cluster_soft()
328*/
329
330/////////////////////////////////////////////////////////
331static int get_next_cluster_hard(uint32_t    cur_cluster,
332                                 uint32_t *  nxt_cluster)
333{
334    uint32_t fat_cluster;           // Index of cluster containing the FAT entry
335    uint32_t fat_cluster_offset;    // Offset of FAT entry in fat_cluster
336    uint32_t fat_cluster_lba;       // LBA for fat_cluster
337
338    // Compute the reqired variables
339    fat_cluster         = cur_cluster >> 10;
340    fat_cluster_offset  = cur_cluster & 0x3FF;
341    fat_cluster_lba     = boot_fat.fat_lba + (fat_cluster << 3);
342
343    // Read the FAT cluster containing the FAT entry if required
344    if (buffer_fat_lba != fat_cluster_lba)
345    {
346        if ( fat_ioc_access( fat_cluster_lba,
347                             XPTR( BOOT_CORE_CXY , buffer_fat ),
348                             8 ) )
349        {
350            boot_printf("\n[BOOT ERROR] get_next_cluster_hard(): "
351                        "Cannot load cluster of LBA %x into buffer_fat\n",
352                        fat_cluster_lba);
353            return -1;
354        }
355
356        buffer_fat_lba = fat_cluster_lba;
357    }
358
359    // returns the FAT entry
360    *nxt_cluster = buffer_fat[fat_cluster_offset] & 0x0FFFFFFF;
361
362    return 0;
363
364} // get_next_cluster_hard()
365
366/****************************************************************************
367 * This function breaks a 'pathname' pathname into a sequence of path       *
368 * components which are separated by the delimiting character "/". Each     *
369 * call to the function gets the next path component and places it in the   *
370 * buffer pointed to by 'path_component'. The result does not include the   *
371 * "/" separator.                                                           *
372 * A sequence of calls to the function that operate on the same pathname    *
373 * maintains a pointer 'nb_read' that determines the point from which to    *
374 * start searching for the next path component.                             *
375 * @ pathname       : pathname to be analyzed.                              *
376 * @ path_component : pointer to the buffer for a path component.           *
377 * @ nb_read        : number of characters already read from the pathname.  *
378 * @ returns 0 on success, -1 on error.                                     *
379 ****************************************************************************/
380static int get_path_component( const char * pathname,
381                               char       * path_component,
382                               uint32_t   * nb_read)
383{
384    uint32_t pathname_offset;   // index used to scan the LFN entry
385    uint32_t path_comp_offset;  // index used to write to the buffer
386
387    // Initialize the variables
388    pathname_offset     = *nb_read;
389    path_comp_offset    = 0;
390
391    // Skip the delimiting character
392    if (pathname[pathname_offset] == '/') pathname_offset++;
393
394    // Get a path component
395    while ((pathname[pathname_offset] != '/') && 
396           (pathname[pathname_offset] != '\0'))
397    {
398        path_component[path_comp_offset++] = pathname[pathname_offset++];
399        if (path_comp_offset > NAME_MAX_SIZE)
400        {
401            boot_printf("\n[BOOT ERROR] get_path_component(): "
402                        "File/directory name is too long\n");
403            return -1;
404        }
405    }
406
407    path_component[path_comp_offset] = '\0';
408   
409    // Update 'nb_read' for the next path component
410    *nb_read = pathname_offset;
411
412#if DEBUG_BOOT_FAT32   
413    boot_printf("\n[BOOT INFO] %s : returns <%s> from <%s> at cycle %d\n",
414                __FUNCTION__ , path_component , pathname , boot_get_proctime() );
415#endif
416
417    return 0;
418
419} // get_path_component()
420
421/****************************************************************************
422 * This function analyzes a Long File Name entry pointed to by 'lfn_entry'  *
423 * to get a portion of a file name and stores it in the temporary buffer    *
424 * pointed to by 'lfn_buffer'.                                              *
425 * @ lfn_entry  : pointer to a LFN entry.                                   *
426 * @ lfn_buffer : pointer to the temporary buffer for a portion of the      *
427 *                full long name.                                           *
428 ****************************************************************************/
429static void get_name_from_long(unsigned char*   lfn_entry,
430                               char*            lfn_buffer)
431{
432    uint32_t entry_offset;      /* Index used to scan the LFN entry.    */
433    uint32_t buffer_offset;     /* Index used to write to the buffer.   */
434    uint32_t lfn_name1_end;     /* End of the first part of this
435                                       entry name portion.                  */
436    uint32_t lfn_name2_end;     /* End of the second part of this
437                                       entry name portion.                  */
438    uint32_t lfn_name3_end;     /* End of the third part of this
439                                       entry name portion.                  */
440
441    /* Initializing the variables. */
442    buffer_offset   = 0;
443    entry_offset    = get_offset(LDIR_NAME1);
444    lfn_name1_end   = get_offset(LDIR_ATTR);
445    lfn_name2_end   = get_offset(LDIR_FSTCLUSLO);
446    lfn_name3_end   = DIR_ENTRY_SIZE;
447   
448    /* Iterating through the first part of this entry name portion. */
449    while (entry_offset != lfn_name1_end)
450    {
451        // If this is the last portion of a file name (file names are also NUL
452        // terminated), we can stop the LFN entry analyzing process.
453        if (lfn_entry[entry_offset] == '\0')
454            goto exit;
455
456        // Writing to the name buffer.
457        lfn_buffer[buffer_offset] = lfn_entry[entry_offset];
458
459        // Preparing variables for the next iteration.
460        buffer_offset++;
461        entry_offset += 2;
462    }
463
464    /* Getting to the next part of the name portion. */
465    entry_offset = get_offset(LDIR_NAME2);
466
467    /* Iterating through the second part of this entry name portion. */
468    while (entry_offset != lfn_name2_end)
469    {
470        // If this is the last portion of a file name (file names are also NUL
471        // terminated), we can stop the LFN entry analyzing process.
472        if (lfn_entry[entry_offset] == '\0')
473            goto exit;
474
475        // Writing to the name buffer.
476        lfn_buffer[buffer_offset] = lfn_entry[entry_offset];
477
478        // Preparing variables for the next iteration.
479        buffer_offset++;
480        entry_offset += 2;
481    }
482
483    /* Getting to the next part of the name portion. */
484    entry_offset = get_offset(LDIR_NAME3);
485
486    /* Iterating through the last part of this entry name portion. */
487    while (entry_offset != lfn_name3_end)
488    {
489        // If this is the last portion of a file name (file names are also NUL
490        // terminated), we can stop the LFN entry analyzing process.
491        if (lfn_entry[entry_offset] == '\0')
492            break;
493
494        // Writing to the name buffer.
495        lfn_buffer[buffer_offset] = lfn_entry[entry_offset];
496
497        // Preparing variables for the next iteration.
498        buffer_offset++;
499        entry_offset += 2;
500    }
501
502exit:
503
504    /* Appending the trailing NUL to the buffer. */
505    lfn_buffer[buffer_offset] = '\0';           
506
507} // get_name_from_long()
508
509/****************************************************************************
510 * This function analyzes a standard 8.3 entry pointed to by 'entry' to     *
511 * get the name of the file/directory corresponding to this entry and       *
512 * stores it in the buffer pointed to by 'buffer'.                          *
513 * @ entry  : pointer to a standard 8.3 entry.                              *
514 * @ buffer : pointer to the buffer for the entry name.                     *
515 ****************************************************************************/
516static void get_name_from_short(unsigned char*  entry,
517                                char*           buffer)
518{
519    uint32_t entry_offset;      /* Index used to scan the 8.3 entry.    */
520    uint32_t buffer_offset;     /* Index used to write to the buffer.   */
521
522    entry_offset    = 0;
523    buffer_offset   = 0;
524
525    // get the file name without suffix
526    while ((entry_offset < 8) && (entry[entry_offset] != ' '))
527    {
528        buffer[buffer_offset++] = boot_to_lower(entry[entry_offset++]);
529    }
530
531    // set entry to first suffix character
532    entry_offset = 8;
533
534    if( entry[entry_offset] == ' ' )        // no suffix in name
535    {
536        // append the trailing NUL in buffer
537        buffer[buffer_offset] = '\0';
538    }
539    else                                    // there is a suffix
540    {
541        // append the '.' in buffer   
542        buffer[buffer_offset++] = '.';
543
544        // get the file extension
545        while ((entry_offset < 11) && (entry[entry_offset] != ' '))
546        {
547            buffer[buffer_offset++] = boot_to_lower(entry[entry_offset++]);
548        }
549   
550        // append the trailing NUL in buffer
551        buffer[buffer_offset] = '\0';
552    }
553       
554} // get_name_from_short()
555
556/****************************************************************************
557 * This function searches for the a file identifid by its pathname.         *
558 * It returns the first cluster index and the file size.                    *
559 * @ pathname       : searched file pathname.                               *
560 * @ first_cluster  : pointer to the first cluster index                    *
561 * @ file_size      : pointer to the file size.                             *
562 * @ returns 0 on success, -1 on error.                                     *
563 ****************************************************************************/
564static int fat_file_search( const char * pathname,
565                            uint32_t   * first_cluster,
566                            uint32_t   * file_size)
567{
568    char       path_comp[PATH_MAX_SIZE];    // Buffer for a path component
569    char       buffer_lfn[16];              // Buffer for a portion of the LFN
570    char       name[NAME_MAX_SIZE];         // Buffer for a full name
571    uint32_t   nb_read;                     // Number of characters already read
572    uint32_t   parent_cluster;              // Cluster of the parent directory
573    uint32_t   next_cluster;                // Next cluster number
574    uint32_t   child_cluster;               // Cluster of searched file/directory
575    uint32_t   child_size;                  // Size of searched file/directory
576    uint32_t   child_is_dir;                // Type of searched file/directory 
577    uint32_t   cluster_lba;                 // LBA of current cluster
578    uint32_t   offset;                      // Offset in cluster buffer
579    uint32_t   ord;                         // First byte of a directory entry
580    uint32_t   attr;                        // Attribute of a directory entry
581    uint32_t   lfn_seq_elem_nr;             // Number of elements in a LFN
582    uint32_t   lfn_seq_order;               // Order of this entry in LFN
583
584    uint32_t   found;             
585
586    unsigned char* entry;               
587
588#if DEBUG_BOOT_FAT32   
589    boot_printf("\n[BOOT INFO] %s enters for <%s> file at cycle %d\n",
590                __FUNCTION__ , pathname, boot_get_proctime());
591#endif
592
593    // Initialize some variables before getting into the search loop
594    nb_read         = 0;
595    child_cluster   = 0;
596    child_size      = 0;
597    child_is_dir    = 0;
598    parent_cluster  = boot_fat.root_cluster;
599
600    // this first loop is on components in the pathname
601    while ( pathname[nb_read] != '\0' )
602    {
603        // Parse the file pathname.
604        if ( get_path_component( pathname, path_comp, &nb_read) ) return -1;
605       
606        // scan one directory for one component in pathname
607        // this second loop is on clusters 
608        // (found = 1 if success / found = 2 if failure)
609        found = 0;
610        while ( found == 0 )
611        {
612            cluster_lba = cluster_to_lba( parent_cluster );
613           
614            // Load the cluster containing the parent directory
615            if (buffer_dir_lba != cluster_lba)
616            {
617                if ( fat_ioc_access( cluster_lba,
618                                     XPTR( BOOT_CORE_CXY , buffer_dir ),
619                                     boot_fat.cluster_size / boot_fat.sector_size ) ) 
620                {
621                    boot_printf("\n[BOOT ERROR] %s: Cannot load cluster at lba %x\n", 
622                                __FUNCTION__ , cluster_lba);
623                    return -1;
624                }
625
626                buffer_dir_lba = cluster_lba;
627            }
628
629            // this third loop is on entries in this cluster
630            for ( offset = 0, lfn_seq_elem_nr = 0;
631                 (offset < boot_fat.cluster_size) && (found == 0);
632                  offset += DIR_ENTRY_SIZE)
633            {
634                entry = buffer_dir + offset;
635                ord   = read_field(LDIR_ORD, entry, 1);
636                attr  = read_field(DIR_ATTR, entry, 1);
637
638                if (ord == LAST_ENTRY)             // no more entry in this directory
639                {
640                    found = 2;
641                }
642
643                else if (ord == FREE_ENTRY)        // unused, check the next entry
644                {
645                    continue;
646                }
647
648                else if (attr == ATTR_LONG_NAME)   // LFN entry
649                {
650                    // Get the order of this entry in the long file name
651                    // as well as its number of elements.
652                    lfn_seq_order   = ord & 0x3F;
653                    lfn_seq_elem_nr = (ord & LAST_LONG_ENTRY) ?
654                                      lfn_seq_order           :
655                                      lfn_seq_elem_nr;
656
657                    // Load the portion of the long file name into temporary buffer
658                    get_name_from_long(entry, buffer_lfn);
659
660                    // Append this portion of the name to the full name buffer
661                    boot_strcpy(name + 13 * (lfn_seq_order-1) , buffer_lfn);
662
663                    // Append the trailing NUL if last LFN entry
664                    if (lfn_seq_order == lfn_seq_elem_nr)
665                        name[13 * (lfn_seq_order-1) + boot_strlen(buffer_lfn)] = '\0';
666                }
667                else                              // Normal entry (standard 8.3 entry)
668                {
669                    if (lfn_seq_elem_nr == 0) get_name_from_short(entry, name);
670
671
672#if DEBUG_BOOT_FAT32   
673    boot_printf("\n[BOOT INFO] in %s : name = %s / entry = %s \n",
674                __FUNCTION__ , name , entry );
675#endif
676
677
678
679                    // check if the full name is what we are looking for.
680                    if (boot_strcmp(name, path_comp) == 0)
681                    {
682                        found = 1;
683
684                        // Get the first cluster for this entry.
685                        child_cluster = (read_field(DIR_FSTCLUSHI, entry, 1) << 16) |
686                                        (read_field(DIR_FSTCLUSLO, entry, 1));
687
688                        // Test if this entry is a directory.
689                        child_is_dir  = (attr & ATTR_DIRECTORY);
690   
691                        // Get its size.
692                        child_size    = read_field(DIR_FILESIZE, entry, 1);
693                    }
694                   
695                    // Reset lfn_seq_elem_nr for the next LFN
696                    lfn_seq_elem_nr = 0;
697                }
698            }  // end loop on entries in current cluster
699
700            // Compute next cluster index if not found in current cluster
701            if ( found == 0 )
702            {
703                if ( get_next_cluster_hard( parent_cluster, &next_cluster ) )
704                {
705                    boot_printf("\n[BOOT ERROR] %s: Cannot get next cluster for cluster %x\n", 
706                                __FUNCTION__ , parent_cluster );
707                    return -1;
708                }
709
710                parent_cluster = next_cluster;
711            }
712
713        } // end second while for one component in pathname
714       
715        // Check the result of this path component search.
716        if (found == 2)
717        {
718            boot_printf("\n[BOOT ERROR] %s: <%s> not found\n",
719                        path_comp);
720            return -1;
721        }
722
723        // check type for each pathname component
724        if (((pathname[nb_read] == '\0') && (child_is_dir != 0)) ||
725            ((pathname[nb_read] != '\0') && (child_is_dir == 0)))
726        {
727            boot_printf("\n[BOOT ERROR] %s: Illegal type for <%s>"
728                        "  nb_read = %d / last_char = %x / child_is_dir = %x\n",
729                        path_comp , nb_read , pathname[nb_read] , child_is_dir );
730            return -1;
731        }
732
733        // prepare for the next iteration.
734        parent_cluster = child_cluster;
735
736    }  // end first while on the complete pathname
737
738    // return file information
739    *first_cluster  = child_cluster;
740    *file_size      = child_size;
741
742#if DEBUG_BOOT_FAT32   
743    boot_printf("\n[BOOT INFO] %s : <%s> file found at cycle %d\n"
744                "    fat_cluster = %x / size = %x\n",
745                __FUNCTION__ , pathname , boot_get_proctime() , *first_cluster , *file_size );
746#endif
747
748    return 0;
749
750} // fat_file_search()
751
752/****************************************************************************
753 *                               API functions.                             *
754 ****************************************************************************/
755
756/////////////////////
757int boot_fat32_init( void )
758{
759    // FAT32 initialization should be done only once
760    if (boot_fat.initialized == FAT_MAGIC_VALUE)
761    {
762        boot_printf("\n[BOOT WARNING] %s: FAT32 already initialized\n",
763                   __FUNCTION__ );
764        return 0;
765    }
766
767#if DEBUG_BOOT_FAT32   
768boot_printf("\n[BOOT INFO] %s: Enters at cycle %d\n",
769            __FUNCTION__ , boot_get_proctime() );
770#endif
771
772    // Load Boot Sector (VBR) into FAT buffer
773    if ( fat_ioc_access( 0, 
774                         XPTR( BOOT_CORE_CXY , boot_fat.block_buffer ), 
775                         1 ) )
776    {
777        boot_printf("\n[BOOT ERROR] %s: Cannot load VBR\n",
778                    __FUNCTION__ );
779        return -1;
780    }
781    boot_fat.block_buffer_lba = 0;
782
783#if DEBUG_BOOT_FAT32   
784boot_printf("\n[BOOT INFO] %s: Boot Sector loaded at cycle %d\n",
785            __FUNCTION__ , boot_get_proctime() );
786#endif
787
788    // Check assumptions on the Boot Sector
789    uint32_t bytes_per_sector = read_field( BPB_BYTSPERSEC, boot_fat.block_buffer, 1 );
790    if ( bytes_per_sector != 512 ) 
791    {
792        boot_printf("\n[BOOT ERROR] boot_fat32_init(): sector size = %x / must be Ox200\n",
793                    bytes_per_sector );
794        return -1;
795    }
796
797    uint32_t sectors_per_cluster = read_field(BPB_SECPERCLUS, boot_fat.block_buffer, 1);
798    if ( sectors_per_cluster != 8 )
799    {
800        boot_printf("\n[BOOT ERROR] boot_fat32_init(): Cluster size = %d / must be 8 sectors \n");
801        return -1;
802    }
803
804    uint32_t nb_fat_copies = read_field(BPB_NUMFATS, boot_fat.block_buffer, 1);
805    if ( nb_fat_copies != 1 )
806    {
807        boot_printf("\n[BOOT ERROR] boot_fat32_init(): number of FAT copies must be 1 \n");
808        return -1;
809    }
810
811    uint32_t nb_fat_sectors = read_field(BPB_FATSZ32, boot_fat.block_buffer, 1);
812    if ( (nb_fat_sectors & 0xF) != 0 )
813    {
814        boot_printf("\n[BOOT ERROR] boot_fat32_init(): FAT size must be multiple of 16 sectors\n");
815        return -1;
816    }
817
818    uint32_t root_cluster = read_field(BPB_ROOTCLUS, boot_fat.block_buffer, 1);
819    if ( root_cluster != 2 )
820    {
821        boot_printf("\n[BOOT ERROR] boot_fat32_init(): Root directory must be at cluster #2\n");
822        return -1;
823    }
824
825    uint32_t fs_info_sector = read_field(BPB_FSINFO, boot_fat.block_buffer, 1);
826    if ( fs_info_sector != 1 )
827    {
828        boot_printf("\n[BOOT ERROR] boot_fat32_init(): FS Information Sector must be 1\n");
829        return -1;
830    }
831
832    uint32_t reserved_sectors = read_field(BPB_RSVDSECCNT, boot_fat.block_buffer, 1);
833
834    uint32_t nb_total_sectors = read_field(BPB_TOTSEC32, boot_fat.block_buffer, 1);
835
836    // Initialize FAT32  descriptor from Boot Sector
837    boot_fat.sector_size    = bytes_per_sector;
838    boot_fat.cluster_size   = bytes_per_sector * sectors_per_cluster;
839    boot_fat.fat_sectors    = nb_fat_sectors;
840    boot_fat.fat_lba        = reserved_sectors;
841    boot_fat.data_sectors   = nb_total_sectors - (nb_fat_sectors + reserved_sectors);
842    boot_fat.data_lba       = nb_fat_sectors + boot_fat.fat_lba;
843    boot_fat.root_cluster   = root_cluster;
844    boot_fat.fsi_lba        = fs_info_sector;
845    boot_fat.initialized    = FAT_MAGIC_VALUE;
846
847    // Set information from FS Information Sector
848    if (set_fsi()) return -1;
849
850    // Initialize FAT and DIR buffers
851    buffer_fat_lba = 0xFFFFFFFF;
852    buffer_dir_lba = 0xFFFFFFFF;
853
854#if DEBUG_BOOT_FAT32   
855    fat32_desc_display();
856    boot_printf("\n[BOOT INFO] %s : FAT32 File System initialized at cycle %d\n",
857                __FUNCTION__ , boot_get_proctime() );
858#endif
859
860    return 0;
861
862} // boot_fat32_init()
863
864///////////////////////////////////////
865int boot_fat32_load( const char * pathname,
866                     uint32_t     buff_addr,
867                     uint32_t     buff_size )
868{
869    uint32_t cur_cluster;
870    uint32_t nxt_cluster;
871    uint32_t size;   
872    uint32_t nb_clusters;
873    uint32_t buff_offset;
874    uint32_t cluster_lba;
875
876    // Checking FAT32 initialization
877    if (boot_fat.initialized != FAT_MAGIC_VALUE)
878    {
879        boot_printf("\n[BOOT ERROR] %s: FAT not initialized\n",
880                    __FUNCTION__ );
881        return -1;
882    }
883
884#if DEBUG_BOOT_FAT32   
885    boot_printf("\n[BOOT INFO] %s enters for file <%s> at cycle %d\n",
886                __FUNCTION__ , pathname, boot_get_proctime() );
887#endif
888
889    // Search file
890    if (fat_file_search(pathname, 
891                        &cur_cluster,
892                        &size))
893    {
894        boot_printf("\n[BOOT ERROR] in %s : File <%s> not found\n", 
895                    __FUNCTION__ , pathname);
896        return -1;
897    }
898   
899    /* Checking buffer size. */
900    if (size > buff_size)
901    {
902        boot_printf("\n[BOOT ERROR] in %s : file <%s> is too large (%x bytes) / "
903                    "buffer size = %x bytes\n",
904                    __FUNCTION__ , pathname , size , buff_size );
905        return -1;
906    }
907   
908    /* Computing number of clusters to read. */
909    // nb_clusters = size / boot_fat.cluster_size
910    nb_clusters = size >> 12;
911
912    // if ((size % boot_fat.cluster_size) != 0)
913    if (size & 0xFFF)
914        nb_clusters++;
915
916    /* Following the cluster chains in the FAT. */
917    buff_offset = buff_addr;
918    while (nb_clusters > 0)
919    {
920#if DEBUG_BOOT_FAT32
921boot_printf("[BOOT INFO] in %s : Loading cluster %d\n", __FUNCTION__, nb_clusters);
922#endif
923        cluster_lba = cluster_to_lba(cur_cluster);
924
925        /* Loading the current cluster. */
926        if ( fat_ioc_access( cluster_lba,
927                             XPTR( BOOT_CORE_CXY , buff_offset ),
928                             boot_fat.cluster_size / boot_fat.sector_size ) )
929        {
930            boot_printf("\n[BOOT ERROR] in %s : cannot load cluster at LBA %x\n", 
931                        __FUNCTION__ , cluster_lba );
932            return -1;
933        }
934       
935        /* Computing next cluster number. */
936        if ( get_next_cluster_hard( cur_cluster , &nxt_cluster ) )
937        {
938            boot_printf("\n[BOOT ERROR] in %s : cannot get next cluster for cluster %x\n", 
939                        __FUNCTION__ , cur_cluster );
940            return -1;
941        }
942       
943        /* Getting prepared for the next iteration. */
944        nb_clusters--;
945        buff_offset += boot_fat.cluster_size;
946        cur_cluster    = nxt_cluster;
947    }
948
949#if DEBUG_BOOT_FAT32   
950    boot_printf("\n[BOOT INFO] %s : file <%s> loaded at cycle %d\n"
951                "    address = %x , size = %x\n",
952                __FUNCTION__ , pathname , boot_get_proctime() , buff_addr , size );
953#endif
954
955    return 0;
956
957} // boot_fat32_load()
Note: See TracBrowser for help on using the repository browser.