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

Last change on this file since 562 was 547, checked in by nicolas.van.phan@…, 6 years ago

Implement bootloader SPI SD card driver (VERY SLOW)

Rectify boot_spi_driver frequency

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