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

Last change on this file since 499 was 474, checked in by viala@…, 6 years ago

[boot] Add void type to function prototypes with no parameter

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