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

Last change on this file since 1 was 1, checked in by alain, 7 years ago

First import

File size: 37.9 KB
Line 
1#include "boot_fat32.h"
2
3#include <boot_config.h>
4#include <boot_utils.h>
5
6#include <boot_tty_driver.h>
7#include <boot_bdv_driver.h>
8#include <boot_hba_driver.h>
9#include <boot_mmc_driver.h>
10
11/*
12#include <boot_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   
150    boot_printf("\n[BOOT] %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] %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] %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
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   
432    boot_printf("\n[BOOT] %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    /* 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   
594    boot_printf("\n[BOOT] %s: Enters for <%s> file at cycle %d\n",
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
618boot_printf("\n!!! enter second while for <%s> path_comp\n", path_comp );
619
620            cluster_lba = cluster_to_lba( parent_cluster );
621           
622            // Load the cluster containing the parent directory
623            if (buffer_dir_lba != cluster_lba)
624            {
625                if ( fat_ioc_access( cluster_lba,
626                                     XPTR( BOOT_CORE_CXY , buffer_dir ),
627                                     boot_fat.cluster_size / boot_fat.sector_size ) ) 
628                {
629                    boot_printf("\n[BOOT ERROR] %s: Cannot load cluster at lba %x\n", 
630                                __FUNCTION__ , cluster_lba);
631                    return -1;
632                }
633
634                buffer_dir_lba = cluster_lba;
635            }
636
637            // this third loop is on entries in this cluster
638            for ( offset = 0, lfn_seq_elem_nr = 0;
639                 (offset < boot_fat.cluster_size) && (found == 0);
640                  offset += DIR_ENTRY_SIZE)
641            {
642                entry = buffer_dir + offset;
643                ord   = read_field(LDIR_ORD, entry, 1);
644                attr  = read_field(DIR_ATTR, entry, 1);
645
646                if (ord == LAST_ENTRY)             // no more entry in this directory
647                {
648
649boot_printf("\n@@@ for <%s> component / offset = %d : last entry\n", path_comp , offset );
650
651                    found = 2;
652                }
653
654                else if (ord == FREE_ENTRY)        // unused, check the next entry
655                {
656
657boot_printf("\n@@@ for <%s> component / offset = %d : free entry\n", path_comp , offset );
658
659                    continue;
660                }
661
662                else if (attr == ATTR_LONG_NAME)   // LFN entry
663                {
664                    // Get the order of this entry in the long file name
665                    // as well as its number of elements.
666                    lfn_seq_order   = ord & 0x3F;
667                    lfn_seq_elem_nr = (ord & LAST_LONG_ENTRY) ?
668                                      lfn_seq_order           :
669                                      lfn_seq_elem_nr;
670
671                    // Load the portion of the long file name into temporary buffer
672                    get_name_from_long(entry, buffer_lfn);
673
674boot_printf("\n@@@ for <%s> component / offset = %d : LFN entry = %s\n", 
675            path_comp , offset , buffer_lfn );
676
677                    // Append this portion of the name to the full name buffer
678                    boot_strcpy(name + 13 * (lfn_seq_order-1) , buffer_lfn);
679
680                    // Append the trailing NUL if last LFN entry
681                    if (lfn_seq_order == lfn_seq_elem_nr)
682                        name[13 * (lfn_seq_order-1) + boot_strlen(buffer_lfn)] = '\0';
683                }
684                else                              // Normal entry (standard 8.3 entry)
685                {
686                    if (lfn_seq_elem_nr == 0) get_name_from_short(entry, name);
687
688boot_printf("\n@@@ for <%s> component / offset = %d : SFN entry = %s\n", 
689            path_comp , offset , name );
690
691                    // check if the full name is what we are looking for.
692                    if (boot_strcmp(name, path_comp) == 0)
693                    {
694                        found = 1;
695
696                        // Get the first cluster for this entry.
697                        child_cluster = (read_field(DIR_FSTCLUSHI, entry, 1) << 16) |
698                                        (read_field(DIR_FSTCLUSLO, entry, 1));
699
700                        // Test if this entry is a directory.
701                        child_is_dir  = (attr & ATTR_DIRECTORY);
702   
703                        // Get its size.
704                        child_size    = read_field(DIR_FILESIZE, entry, 1);
705                    }
706                   
707                    // Reset lfn_seq_elem_nr for the next LFN
708                    lfn_seq_elem_nr = 0;
709                }
710            }  // end loop on entries in current cluster
711
712            // Compute next cluster index if not found in current cluster
713            if ( found == 0 )
714            {
715                if ( get_next_cluster_hard( parent_cluster, &next_cluster ) )
716                {
717                    boot_printf("\n[BOOT ERROR] %s: Cannot get next cluster for cluster %x\n", 
718                                __FUNCTION__ , parent_cluster );
719                    return -1;
720                }
721
722                parent_cluster = next_cluster;
723            }
724
725        } // end second while for one component in pathname
726       
727boot_printf("\n### exit hwile fpr component <%s>\n", path_comp );
728
729        // Check the result of this path component search.
730        if (found == 2)
731        {
732            boot_printf("\n[BOOT ERROR] %s: <%s> not found\n",
733                        path_comp);
734            return -1;
735        }
736
737        // check type for each pathname component
738        if (((pathname[nb_read] == '\0') && (child_is_dir != 0)) ||
739            ((pathname[nb_read] != '\0') && (child_is_dir == 0)))
740        {
741            boot_printf("\n[BOOT ERROR] %s: Illegal type for <%s>"
742                        "  nb_read = %d / last_char = %x / child_is_dir = %x\n",
743                        path_comp , nb_read , pathname[nb_read] , child_is_dir );
744            return -1;
745        }
746
747        // prepare for the next iteration.
748        parent_cluster = child_cluster;
749
750    }  // end first while on the complete pathname
751
752    // return file information
753    *first_cluster  = child_cluster;
754    *file_size      = child_size;
755
756#if DEBUG_BOOT_FAT32   
757    boot_printf("\n[BOOT] fat_file_search(): "
758                "<%s> file of size %x found at cluster %x at cycle %d\n",
759                pathname, *file_size, *first_cluster, boot_get_proctime());
760#endif
761
762    return 0;
763
764} // fat_file_search()
765
766/****************************************************************************
767 *                               API functions.                             *
768 ****************************************************************************/
769
770/////////////////////
771int boot_fat32_init()
772{
773
774boot_printf("@@@ BEFORE_VALUE = %x\n", FAT_MAGIC_VALUE);
775
776    // FAT32 initialization should be done only once
777    if (boot_fat.initialized == FAT_MAGIC_VALUE)
778    {
779        boot_printf("\n[BOOT WARNING] %s: FAT32 already initialized\n",
780                   __FUNCTION__ );
781        return 0;
782    }
783
784#if DEBUG_BOOT_FAT32   
785boot_printf("\n[BOOT] %s: Enters at cycle %d\n",
786            __FUNCTION__ , boot_get_proctime() );
787#endif
788
789    // Load Boot Sector (VBR) into FAT buffer
790    if ( fat_ioc_access( 0, 
791                         XPTR( BOOT_CORE_CXY , boot_fat.block_buffer ), 
792                         1 ) )
793    {
794        boot_printf("\n[BOOT ERROR] %s: Cannot load VBR\n",
795                    __FUNCTION__ );
796        return -1;
797    }
798    boot_fat.block_buffer_lba = 0;
799
800#if DEBUG_BOOT_FAT32   
801boot_printf("\n[BOOT] %s: Boot Sector loaded at cycle %d\n",
802            __FUNCTION__ , boot_get_proctime() );
803// unsigned char * data = boot_fat.block_buffer;
804// uint32_t   byte;
805// for( byte = 0 ; byte < 16 ; byte++ ) boot_printf("%d : %x\n", byte , data[byte] );
806#endif
807
808    // Check assumptions on the Boot Sector
809    uint32_t bytes_per_sector = read_field( BPB_BYTSPERSEC, boot_fat.block_buffer, 1 );
810    if ( bytes_per_sector != 512 ) 
811    {
812        boot_printf("\n[BOOT ERROR] boot_fat32_init(): sector size = %x / must be Ox200\n",
813                    bytes_per_sector );
814        return -1;
815    }
816
817    uint32_t sectors_per_cluster = read_field(BPB_SECPERCLUS, boot_fat.block_buffer, 1);
818    if ( sectors_per_cluster != 8 )
819    {
820        boot_printf("\n[BOOT ERROR] boot_fat32_init(): Cluster size = %d / must be 8 sectors \n");
821        return -1;
822    }
823
824    uint32_t nb_fat_copies = read_field(BPB_NUMFATS, boot_fat.block_buffer, 1);
825    if ( nb_fat_copies != 1 )
826    {
827        boot_printf("\n[BOOT ERROR] boot_fat32_init(): number of FAT copies must be 1 \n");
828        return -1;
829    }
830
831    uint32_t nb_fat_sectors = read_field(BPB_FATSZ32, boot_fat.block_buffer, 1);
832    if ( (nb_fat_sectors & 0xF) != 0 )
833    {
834        boot_printf("\n[BOOT ERROR] boot_fat32_init(): FAT size must be multiple of 16 sectors\n");
835        return -1;
836    }
837
838    uint32_t root_cluster = read_field(BPB_ROOTCLUS, boot_fat.block_buffer, 1);
839    if ( root_cluster != 2 )
840    {
841        boot_printf("\n[BOOT ERROR] boot_fat32_init(): Root directory must be at cluster #2\n");
842        return -1;
843    }
844
845    uint32_t fs_info_sector = read_field(BPB_FSINFO, boot_fat.block_buffer, 1);
846    if ( fs_info_sector != 1 )
847    {
848        boot_printf("\n[BOOT ERROR] boot_fat32_init(): FS Information Sector must be 1\n");
849        return -1;
850    }
851
852    uint32_t reserved_sectors = read_field(BPB_RSVDSECCNT, boot_fat.block_buffer, 1);
853
854    uint32_t nb_total_sectors = read_field(BPB_TOTSEC32, boot_fat.block_buffer, 1);
855
856    // Initialize FAT32  descriptor from Boot Sector
857    boot_fat.sector_size    = bytes_per_sector;
858    boot_fat.cluster_size   = bytes_per_sector * sectors_per_cluster;
859    boot_fat.fat_sectors    = nb_fat_sectors;
860    boot_fat.fat_lba        = reserved_sectors;
861    boot_fat.data_sectors   = nb_total_sectors - (nb_fat_sectors + reserved_sectors);
862    boot_fat.data_lba       = nb_fat_sectors + boot_fat.fat_lba;
863    boot_fat.root_cluster   = root_cluster;
864    boot_fat.fsi_lba        = fs_info_sector;
865    boot_fat.initialized    = FAT_MAGIC_VALUE;
866
867boot_printf("@@@ AFTER_VALUE = %x\n", FAT_MAGIC_VALUE);
868
869fat32_desc_display();
870   
871    // Set information from FS Information Sector
872    if (set_fsi()) return -1;
873
874    // Initialize FAT and DIR buffers
875    buffer_fat_lba = 0xFFFFFFFF;
876    buffer_dir_lba = 0xFFFFFFFF;
877
878#if DEBUG_BOOT_FAT32   
879    fat32_desc_display();
880    boot_printf("\n[BOOT] boot_fat32_init(): FAT32 File System initialized at cycle %d\n",
881                boot_get_proctime());
882#endif
883
884    return 0;
885
886} // boot_fat32_init()
887
888///////////////////////////////////////
889int boot_fat32_load( char*    pathname, 
890                     uint32_t buff_addr, 
891                     uint32_t buff_size )
892{
893    uint32_t cur_cluster;
894    uint32_t nxt_cluster;
895    uint32_t size;   
896    uint32_t nb_clusters;
897    uint32_t buff_offset;
898    uint32_t cluster_lba;
899
900    // Checking FAT32 initialization
901    if (boot_fat.initialized != FAT_MAGIC_VALUE)
902    {
903        boot_printf("\n[BOOT ERROR] %s: FAT not initialized\n",
904                    __FUNCTION__ );
905        return -1;
906    }
907
908#if DEBUG_BOOT_FAT32   
909    boot_printf("\n[BOOT] %s: Enters for file <%s> at cycle %d\n",
910                __FUNCTION__ , pathname, boot_get_proctime() );
911#endif
912
913    // Search file
914    if (fat_file_search(pathname, 
915                        &cur_cluster,
916                        &size))
917    {
918        boot_printf("\n[BOOT ERROR] boot_fat32_load(): "
919                    "File <%s> not found\n", 
920                    pathname);
921        return -1;
922    }
923   
924    /* Checking buffer size. */
925    if (size > buff_size)
926    {
927        boot_printf("\n[BOOT ERROR] boot_fat32_load(): "
928                    "File <%s> is too large (%x bytes) / "
929                    "buffer size = %x bytes\n",
930                    pathname, size, buff_size);
931        return -1;
932    }
933   
934    /* Computing number of clusters to read. */
935    // nb_clusters = size / boot_fat.cluster_size
936    nb_clusters = size >> 12;
937
938    // if ((size % boot_fat.cluster_size) != 0)
939    if (size & 0xFFF)
940        nb_clusters++;
941
942    /* Following the cluster chains in the FAT. */
943    buff_offset = buff_addr;
944    while (nb_clusters > 0)
945    {
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] boot_fat32_load(): "
954                        "Cannot load cluster at LBA %x\n", 
955                        cluster_lba);
956            return -1;
957        }
958       
959        /* Computing next cluster number. */
960        if ( get_next_cluster_hard( cur_cluster , &nxt_cluster ) )
961        {
962            boot_printf("\n[BOOT ERROR] boot_fat32_load(): "
963                        "Cannot get next cluster for cluster %x\n", 
964                        cur_cluster);
965            return -1;
966        }
967       
968        /* Getting prepared for the next iteration. */
969        nb_clusters--;
970        buff_offset += boot_fat.cluster_size;
971        cur_cluster    = nxt_cluster;
972    }
973
974#if DEBUG_BOOT_FAT32   
975    boot_printf("\n[BOOT] boot_fat32_load(): "
976                "File <%s> of size %x loaded at address %x at cycle %d\n",
977                pathname, size, buff_addr, boot_get_proctime());
978#endif
979
980    return 0;
981
982} // boot_fat32_load()
Note: See TracBrowser for help on using the repository browser.