source: trunk/tools/bootloader_tsar/boot_fat32.c @ 346

Last change on this file since 346 was 23, checked in by alain, 8 years ago

Introduce syscalls.

File size: 37.1 KB
RevLine 
[1]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{
52    return offset;
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{
67    return size;
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 ****************************************************************************/
147static int set_fsi()
148{
149#if DEBUG_BOOT_FAT32   
[6]150    boot_printf("\n[BOOT INFO] %s enters at cycle %d\n",
[1]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   
[6]165    boot_printf("\n[BOOT INFO] %s : FSI Sector loaded at cycle %d\n",
[1]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   
[6]199    boot_printf("\n[BOOT INFO] %s : free_clusters_nr = %x / free_cluster_hint = %x\n",
[1]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
213static void fat32_desc_display()
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   
[6]432    boot_printf("\n[BOOT INFO] %s : returns <%s> from <%s> at cycle %d\n",
[1]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    /* Initializing the variables. */
542    entry_offset    = 0;
543    buffer_offset   = 0;
544
545    /* Getting the file name. */
546    while ((entry_offset < 8) && (entry[entry_offset] != ' '))
547        buffer[buffer_offset++] = boot_to_lower(entry[entry_offset++]);
548   
549    /* Appending the dot to the name buffer. */
550    buffer[buffer_offset++] = '.';
551
552    /* Getting the file extension. */
553    while ((entry_offset < 11) && (entry[entry_offset] != ' '))
554        buffer[buffer_offset++] = boot_to_lower(entry[entry_offset++]);
555   
556    /* Appending the trailing NUL to the buffer. */
557    buffer[buffer_offset++] = '\0';
558       
559} // get_name_from_short()
560
561/****************************************************************************
562 * This function searches for the a file identifid by its pathname.         *
563 * It returns the first cluster index and the file size.                    *
564 * @ pathname       : searched file pathname.                               *
565 * @ first_cluster  : pointer to the first cluster index                    *
566 * @ file_size      : pointer to the file size.                             *
567 * @ returns 0 on success, -1 on error.                                     *
568 ****************************************************************************/
569static int fat_file_search(char*     pathname,
570                           uint32_t* first_cluster,
571                           uint32_t* file_size)
572{
573    char       path_comp[PATH_MAX_SIZE];    // Buffer for a path component
574    char       buffer_lfn[16];              // Buffer for a portion of the LFN
575    char       name[NAME_MAX_SIZE];         // Buffer for a full name
576    uint32_t   nb_read;                     // Number of characters already read
577    uint32_t   parent_cluster;              // Cluster of the parent directory
578    uint32_t   next_cluster;                // Next cluster number
579    uint32_t   child_cluster;               // Cluster of searched file/directory
580    uint32_t   child_size;                  // Size of searched file/directory
581    uint32_t   child_is_dir;                // Type of searched file/directory 
582    uint32_t   cluster_lba;                 // LBA of current cluster
583    uint32_t   offset;                      // Offset in cluster buffer
584    uint32_t   ord;                         // First byte of a directory entry
585    uint32_t   attr;                        // Attribute of a directory entry
586    uint32_t   lfn_seq_elem_nr;             // Number of elements in a LFN
587    uint32_t   lfn_seq_order;               // Order of this entry in LFN
588
589    uint32_t   found;             
590
591    unsigned char* entry;               
592
593#if DEBUG_BOOT_FAT32   
[6]594    boot_printf("\n[BOOT INFO] %s enters for <%s> file at cycle %d\n",
[1]595                __FUNCTION__ , pathname, boot_get_proctime());
596#endif
597
598    // Initialize some variables before getting into the search loop
599    nb_read         = 0;
600    child_cluster   = 0;
601    child_size      = 0;
602    child_is_dir    = 0;
603    parent_cluster  = boot_fat.root_cluster;
604
605    // this first loop is on components in the pathname
606    while ( pathname[nb_read] != '\0' )
607    {
608        // Parse the file pathname.
609        if ( get_path_component( pathname, path_comp, &nb_read) ) return -1;
610       
611        // scan one directory for one component in pathname
612        // this second loop is on clusters 
613        // (found = 1 if success / found = 2 if failure)
614        found = 0;
615        while ( found == 0 )
616        {
617            cluster_lba = cluster_to_lba( parent_cluster );
618           
619            // Load the cluster containing the parent directory
620            if (buffer_dir_lba != cluster_lba)
621            {
622                if ( fat_ioc_access( cluster_lba,
623                                     XPTR( BOOT_CORE_CXY , buffer_dir ),
624                                     boot_fat.cluster_size / boot_fat.sector_size ) ) 
625                {
626                    boot_printf("\n[BOOT ERROR] %s: Cannot load cluster at lba %x\n", 
627                                __FUNCTION__ , cluster_lba);
628                    return -1;
629                }
630
631                buffer_dir_lba = cluster_lba;
632            }
633
634            // this third loop is on entries in this cluster
635            for ( offset = 0, lfn_seq_elem_nr = 0;
636                 (offset < boot_fat.cluster_size) && (found == 0);
637                  offset += DIR_ENTRY_SIZE)
638            {
639                entry = buffer_dir + offset;
640                ord   = read_field(LDIR_ORD, entry, 1);
641                attr  = read_field(DIR_ATTR, entry, 1);
642
643                if (ord == LAST_ENTRY)             // no more entry in this directory
644                {
645                    found = 2;
646                }
647
648                else if (ord == FREE_ENTRY)        // unused, check the next entry
649                {
650                    continue;
651                }
652
653                else if (attr == ATTR_LONG_NAME)   // LFN entry
654                {
655                    // Get the order of this entry in the long file name
656                    // as well as its number of elements.
657                    lfn_seq_order   = ord & 0x3F;
658                    lfn_seq_elem_nr = (ord & LAST_LONG_ENTRY) ?
659                                      lfn_seq_order           :
660                                      lfn_seq_elem_nr;
661
662                    // Load the portion of the long file name into temporary buffer
663                    get_name_from_long(entry, buffer_lfn);
664
665                    // Append this portion of the name to the full name buffer
666                    boot_strcpy(name + 13 * (lfn_seq_order-1) , buffer_lfn);
667
668                    // Append the trailing NUL if last LFN entry
669                    if (lfn_seq_order == lfn_seq_elem_nr)
670                        name[13 * (lfn_seq_order-1) + boot_strlen(buffer_lfn)] = '\0';
671                }
672                else                              // Normal entry (standard 8.3 entry)
673                {
674                    if (lfn_seq_elem_nr == 0) get_name_from_short(entry, name);
675
676                    // check if the full name is what we are looking for.
677                    if (boot_strcmp(name, path_comp) == 0)
678                    {
679                        found = 1;
680
681                        // Get the first cluster for this entry.
682                        child_cluster = (read_field(DIR_FSTCLUSHI, entry, 1) << 16) |
683                                        (read_field(DIR_FSTCLUSLO, entry, 1));
684
685                        // Test if this entry is a directory.
686                        child_is_dir  = (attr & ATTR_DIRECTORY);
687   
688                        // Get its size.
689                        child_size    = read_field(DIR_FILESIZE, entry, 1);
690                    }
691                   
692                    // Reset lfn_seq_elem_nr for the next LFN
693                    lfn_seq_elem_nr = 0;
694                }
695            }  // end loop on entries in current cluster
696
697            // Compute next cluster index if not found in current cluster
698            if ( found == 0 )
699            {
700                if ( get_next_cluster_hard( parent_cluster, &next_cluster ) )
701                {
702                    boot_printf("\n[BOOT ERROR] %s: Cannot get next cluster for cluster %x\n", 
703                                __FUNCTION__ , parent_cluster );
704                    return -1;
705                }
706
707                parent_cluster = next_cluster;
708            }
709
710        } // end second while for one component in pathname
711       
712        // Check the result of this path component search.
713        if (found == 2)
714        {
715            boot_printf("\n[BOOT ERROR] %s: <%s> not found\n",
716                        path_comp);
717            return -1;
718        }
719
720        // check type for each pathname component
721        if (((pathname[nb_read] == '\0') && (child_is_dir != 0)) ||
722            ((pathname[nb_read] != '\0') && (child_is_dir == 0)))
723        {
724            boot_printf("\n[BOOT ERROR] %s: Illegal type for <%s>"
725                        "  nb_read = %d / last_char = %x / child_is_dir = %x\n",
726                        path_comp , nb_read , pathname[nb_read] , child_is_dir );
727            return -1;
728        }
729
730        // prepare for the next iteration.
731        parent_cluster = child_cluster;
732
733    }  // end first while on the complete pathname
734
735    // return file information
736    *first_cluster  = child_cluster;
737    *file_size      = child_size;
738
739#if DEBUG_BOOT_FAT32   
[6]740    boot_printf("\n[BOOT INFO] %s : <%s> file found at cycle %d\n"
741                "    fat_cluster = %x / size = %x\n",
742                __FUNCTION__ , pathname , boot_get_proctime() , *first_cluster , *file_size );
[1]743#endif
744
745    return 0;
746
747} // fat_file_search()
748
749/****************************************************************************
750 *                               API functions.                             *
751 ****************************************************************************/
752
753/////////////////////
754int boot_fat32_init()
755{
756    // FAT32 initialization should be done only once
757    if (boot_fat.initialized == FAT_MAGIC_VALUE)
758    {
759        boot_printf("\n[BOOT WARNING] %s: FAT32 already initialized\n",
760                   __FUNCTION__ );
761        return 0;
762    }
763
764#if DEBUG_BOOT_FAT32   
[6]765boot_printf("\n[BOOT INFO] %s: Enters at cycle %d\n",
[1]766            __FUNCTION__ , boot_get_proctime() );
767#endif
768
769    // Load Boot Sector (VBR) into FAT buffer
770    if ( fat_ioc_access( 0, 
771                         XPTR( BOOT_CORE_CXY , boot_fat.block_buffer ), 
772                         1 ) )
773    {
774        boot_printf("\n[BOOT ERROR] %s: Cannot load VBR\n",
775                    __FUNCTION__ );
776        return -1;
777    }
778    boot_fat.block_buffer_lba = 0;
779
780#if DEBUG_BOOT_FAT32   
[6]781boot_printf("\n[BOOT INFO] %s: Boot Sector loaded at cycle %d\n",
[1]782            __FUNCTION__ , boot_get_proctime() );
783#endif
784
785    // Check assumptions on the Boot Sector
786    uint32_t bytes_per_sector = read_field( BPB_BYTSPERSEC, boot_fat.block_buffer, 1 );
787    if ( bytes_per_sector != 512 ) 
788    {
789        boot_printf("\n[BOOT ERROR] boot_fat32_init(): sector size = %x / must be Ox200\n",
790                    bytes_per_sector );
791        return -1;
792    }
793
794    uint32_t sectors_per_cluster = read_field(BPB_SECPERCLUS, boot_fat.block_buffer, 1);
795    if ( sectors_per_cluster != 8 )
796    {
797        boot_printf("\n[BOOT ERROR] boot_fat32_init(): Cluster size = %d / must be 8 sectors \n");
798        return -1;
799    }
800
801    uint32_t nb_fat_copies = read_field(BPB_NUMFATS, boot_fat.block_buffer, 1);
802    if ( nb_fat_copies != 1 )
803    {
804        boot_printf("\n[BOOT ERROR] boot_fat32_init(): number of FAT copies must be 1 \n");
805        return -1;
806    }
807
808    uint32_t nb_fat_sectors = read_field(BPB_FATSZ32, boot_fat.block_buffer, 1);
809    if ( (nb_fat_sectors & 0xF) != 0 )
810    {
811        boot_printf("\n[BOOT ERROR] boot_fat32_init(): FAT size must be multiple of 16 sectors\n");
812        return -1;
813    }
814
815    uint32_t root_cluster = read_field(BPB_ROOTCLUS, boot_fat.block_buffer, 1);
816    if ( root_cluster != 2 )
817    {
818        boot_printf("\n[BOOT ERROR] boot_fat32_init(): Root directory must be at cluster #2\n");
819        return -1;
820    }
821
822    uint32_t fs_info_sector = read_field(BPB_FSINFO, boot_fat.block_buffer, 1);
823    if ( fs_info_sector != 1 )
824    {
825        boot_printf("\n[BOOT ERROR] boot_fat32_init(): FS Information Sector must be 1\n");
826        return -1;
827    }
828
829    uint32_t reserved_sectors = read_field(BPB_RSVDSECCNT, boot_fat.block_buffer, 1);
830
831    uint32_t nb_total_sectors = read_field(BPB_TOTSEC32, boot_fat.block_buffer, 1);
832
833    // Initialize FAT32  descriptor from Boot Sector
834    boot_fat.sector_size    = bytes_per_sector;
835    boot_fat.cluster_size   = bytes_per_sector * sectors_per_cluster;
836    boot_fat.fat_sectors    = nb_fat_sectors;
837    boot_fat.fat_lba        = reserved_sectors;
838    boot_fat.data_sectors   = nb_total_sectors - (nb_fat_sectors + reserved_sectors);
839    boot_fat.data_lba       = nb_fat_sectors + boot_fat.fat_lba;
840    boot_fat.root_cluster   = root_cluster;
841    boot_fat.fsi_lba        = fs_info_sector;
842    boot_fat.initialized    = FAT_MAGIC_VALUE;
843
844    // Set information from FS Information Sector
845    if (set_fsi()) return -1;
846
847    // Initialize FAT and DIR buffers
848    buffer_fat_lba = 0xFFFFFFFF;
849    buffer_dir_lba = 0xFFFFFFFF;
850
851#if DEBUG_BOOT_FAT32   
852    fat32_desc_display();
[6]853    boot_printf("\n[BOOT INFO] %s : FAT32 File System initialized at cycle %d\n",
854                __FUNCTION__ , boot_get_proctime() );
[1]855#endif
856
857    return 0;
858
859} // boot_fat32_init()
860
861///////////////////////////////////////
862int boot_fat32_load( char*    pathname, 
863                     uint32_t buff_addr, 
864                     uint32_t buff_size )
865{
866    uint32_t cur_cluster;
867    uint32_t nxt_cluster;
868    uint32_t size;   
869    uint32_t nb_clusters;
870    uint32_t buff_offset;
871    uint32_t cluster_lba;
872
873    // Checking FAT32 initialization
874    if (boot_fat.initialized != FAT_MAGIC_VALUE)
875    {
876        boot_printf("\n[BOOT ERROR] %s: FAT not initialized\n",
877                    __FUNCTION__ );
878        return -1;
879    }
880
881#if DEBUG_BOOT_FAT32   
[6]882    boot_printf("\n[BOOT INFO] %s enters for file <%s> at cycle %d\n",
[1]883                __FUNCTION__ , pathname, boot_get_proctime() );
884#endif
885
886    // Search file
887    if (fat_file_search(pathname, 
888                        &cur_cluster,
889                        &size))
890    {
[23]891        boot_printf("\n[BOOT ERROR] in %s : File <%s> not found\n", 
892                    __FUNCTION__ , pathname);
[1]893        return -1;
894    }
895   
896    /* Checking buffer size. */
897    if (size > buff_size)
898    {
[23]899        boot_printf("\n[BOOT ERROR] in %s : file <%s> is too large (%x bytes) / "
[1]900                    "buffer size = %x bytes\n",
[23]901                    __FUNCTION__ , pathname , size , buff_size );
[1]902        return -1;
903    }
904   
905    /* Computing number of clusters to read. */
906    // nb_clusters = size / boot_fat.cluster_size
907    nb_clusters = size >> 12;
908
909    // if ((size % boot_fat.cluster_size) != 0)
910    if (size & 0xFFF)
911        nb_clusters++;
912
913    /* Following the cluster chains in the FAT. */
914    buff_offset = buff_addr;
915    while (nb_clusters > 0)
916    {
917        cluster_lba = cluster_to_lba(cur_cluster);
918
919        /* Loading the current cluster. */
920        if ( fat_ioc_access( cluster_lba,
921                             XPTR( BOOT_CORE_CXY , buff_offset ),
922                             boot_fat.cluster_size / boot_fat.sector_size ) )
923        {
[23]924            boot_printf("\n[BOOT ERROR] in %s : cannot load cluster at LBA %x\n", 
925                        __FUNCTION__ , cluster_lba );
[1]926            return -1;
927        }
928       
929        /* Computing next cluster number. */
930        if ( get_next_cluster_hard( cur_cluster , &nxt_cluster ) )
931        {
[23]932            boot_printf("\n[BOOT ERROR] in %s : cannot get next cluster for cluster %x\n", 
933                        __FUNCTION__ , cur_cluster );
[1]934            return -1;
935        }
936       
937        /* Getting prepared for the next iteration. */
938        nb_clusters--;
939        buff_offset += boot_fat.cluster_size;
940        cur_cluster    = nxt_cluster;
941    }
942
943#if DEBUG_BOOT_FAT32   
[6]944    boot_printf("\n[BOOT INFO] %s : file <%s> loaded at cycle %d\n"
945                "    address = %x , size = %x\n",
946                __FUNCTION__ , pathname , boot_get_proctime() , buff_addr , size );
[1]947#endif
948
949    return 0;
950
951} // boot_fat32_load()
Note: See TracBrowser for help on using the repository browser.