/****************************************************************************
 * This file defines the implementation of a simplified FAT32 file system   *
 * supported by the ALMOS-MKH boot-loader.                                   *
 *                                                                          *
 * This implementation only supports block devices with block (sector)      *
 * size of 512 bytes (value stored in BPB_BYTSPERSEC, see below). The       *
 * max size for a single file is 4Gb - 1.                                   *
 *                                                                          *
 * A cluster is a smallest storage allocatable unit on the block device:    *
 * any file (or directory) occupies at least one cluster, and a given       *
 * cluster cannot be shared by 2 different files. This implementation       *
 * supports cluster size of 4Kb (8 sectors, value stored in                 *
 * BPB_SECPERCLUS, see below).                                              *
 *                                                                          *
 * For partitioned devices such as hard drives, the first sector of the     *
 * drive is the Master Boot Record defining partitions, while the first     *
 * sector of partitions formatted with a FAT file system is the boot        *
 * sector (Volume Boot Record).                                             *
 *                                                                          *
 * Here is the layout of a partition formatted with a FAT32 file system:    *
 *  +--------------------------------------------------------------------+  *
 *  |   Reserved Region, composed of:                                    |  *
 *  |       - Boot Sector (i.e VBR, logical sector 0),                   |  *
 *  |       - FS Information Sector (logical sector 1, value stored in   |  *
 *  |         BPB_FSINFO, see below),                                    |  *
 *  |       - Other reserved sectors (optional).                         |  *
 *  |--------------------------------------------------------------------|  *
 *  |   FAT Region: contains the File Allocation Table which are maps    |  *
 *  |   of the Data Region, indicating which clusters are used by files  |  *
 *  |   and directories.                                                 |  *
 *  |   This may contains two copies of the FAT data structure (value    |  *
 *  |   stored in BPB_NUMFATS, see below) for the sake of redundancy     |  *
 *  |   checking, although rarely used.                                  |  *
 *  |--------------------------------------------------------------------|  *
 *  |   Data Region: this is where the actual file and directory data    |  *
 *  |   stored. The Root Directory Table is stored in the first cluster  |  *
 *  |   of the Data Region (value stored in BPB_ROOTCLUS, see below).    |  *
 *  +--------------------------------------------------------------------+  *
 ****************************************************************************/

#ifndef BOOT_FAT32_H
#define BOOT_FAT32_H

/****************************************************************************
 *                         Various signature values.                        *
 * Warning: don't forget that little-endian representation must be assumed  *
 ****************************************************************************/

#define BOOT_SIGNATURE          0xAA55
#define FSI_SIGNATURE1          0x41615252
#define FSI_SIGNATURE2          0x61417272
#define FSI_SIGNATURE3          0xAA550000

/****************************************************************************
 *                      Master Boot Record structure.                       *
 ****************************************************************************/

/* Boot code (first 446 bytes). */

/* Partition table (64 bytes). */
/*                         offset | size (both in bytes)                    */
#define FIRST_ENTRY_ACTIVE    446,  1   /* Status of first partition.       */
#define FIRST_ENTRY_CHSFRST   447,  3   /* CHS address of first sector.     */
#define FIRST_ENTRY_TYPE      450,  1   /* First partition type.            */
#define FIRST_ENTRY_CHSLST    451,  3   /* CHS address of last sector.      */
#define FIRST_ENTRY_LBAFRST   454,  4   /* LBA of first sector.             */
#define FIRST_ENTRY_SIZE      458,  4   /* Count of sectors in partition.   */

#define SECOND_ENTRY_ACTIVE   462,  1   /* Status of second partition.      */
#define SECOND_ENTRY_CHSFRST  463,  3   /* CHS address of first sector.     */
#define SECOND_ENTRY_TYPE     466,  1   /* Second partition type.           */
#define SECOND_ENTRY_CHSLST   467,  3   /* CHS address of last sector.      */
#define SECOND_ENTRY_LBAFRST  470,  4   /* LBA of first sector.             */
#define SECOND_ENTRY_SIZE     474,  4   /* Count of sectors in partition.   */

#define THIRD_ENTRY_ACTIVE    478,  1   /* Status of third partition.       */
#define THIRD_ENTRY_CHSFRST   479,  3   /* CHS address of first sector.     */
#define THIRD_ENTRY_TYPE      482,  1   /* Third partition type.            */
#define THIRD_ENTRY_CHSLST    483,  3   /* CHS address of last sector.      */
#define THIRD_ENTRY_LBAFRST   486,  4   /* LBA of first sector.             */
#define THIRD_ENTRY_SIZE      490,  4   /* Count of sectors in partition.   */

#define FOURTH_ENTRY_ACTIVE   494,  1   /* Status of fourth partition.      */
#define FOURTH_ENTRY_CHSFRST  495,  3   /* CHS address of first sector.     */
#define FOURTH_ENTRY_TYPE     498,  1   /* Fourth partition type.           */
#define FOURTH_ENTRY_CHSLST   499,  3   /* CHS address of last sector.      */
#define FOURTH_ENTRY_LBAFRST  502,  4   /* LBA of first sector.             */
#define FOURTH_ENTRY_SIZE     506,  4   /* Count of sectors in partition.   */

/* Signature (last 2 bytes). */
/*                         offset | size (both in bytes)                    */
#define MBR_SIGNATURE_POS     510,  2   /* Boot signature.                  */

/****************************************************************************
 *                          Boot Sector structure.                          *
 ****************************************************************************/

/* First 11 bytes. */
/*                         offset | size (both in bytes)                    */
#define BS_JMPBOOT              0,  3   /* Jump instruction to boot code.   */
#define BS_OEMNAME              3,  8   /* OEM identifier (meaningless).    */

/* BIOS Parameter Block (next 25 bytes). */
/*                         offset | size (both in bytes)                    */
#define BPB_BYTSPERSEC         11,  2   /* Bytes per logical sector.        */
#define BPB_SECPERCLUS         13,  1   /* Logical sectors per cluster.     */
#define BPB_RSVDSECCNT         14,  2   /* Count of reserved sectors.       */
#define BPB_NUMFATS            16,  1   /* Count of File Allocation Tables. */
#define BPB_ROOTENTCNT         17,  2   /* Must be 0 for FAT32.             */
#define BPB_TOTSEC16           19,  2   /* Total sectors count on 16 bits.  */
#define BPB_MEDIA              21,  1   /* Media descriptor.                */
#define BPB_FATSZ16            22,  2   /* Must be 0 for FAT32.             */
#define BPB_SECPERTRK          24,  2   /* Sectors per track for INT 0x13.  */
#define BPB_NUMHEADS           26,  2   /* Number of heads for INT 0x13.    */
#define BPB_HIDDSEC            28,  2   /* Hidden sectors preceding the 
                                           partition that contains this FAT
                                           volume.                          */
#define BPB_TOTSEC32           32,  4   /* Total sectors count on 32 bits.  */
    
/* FAT32 Extended BIOS Parameter Block (next 28 bytes). */
/*                         offset | size (both in bytes)                    */
#define BPB_FATSZ32            36,  4   /* Sectors per FAT on 32 bits.      */
#define BPB_EXTFLAGS           40,  2   /* Mirroring flags.                 */
#define BPB_FSVER              42,  2   /* Version.                         */
#define BPB_ROOTCLUS           44,  4   /* Number of first cluster of the 
                                           root directory.                  */
#define BPB_FSINFO             48,  2   /* Logical sector number of FS 
                                           Information Sector.              */
#define BPB_BKBOOTSEC          50,  2   /* Logical sector of Backup Boot 
                                           Sector.                          */
#define BPB_RESERVED           52, 12   /* Reserved for future expansion.   */

/* FAT12/FAT16 Extended BIOS Parameter Block (next 26 bytes). */
/*                         offset | size (both in bytes)                    */
#define BS_DRVNUM              64,  1   /* INT 0x13 drive number.           */   
#define BS_RESERVED1           65,  1   /* Reserved.                        */
#define BS_BOOTSIG             66,  1   /* Extended boot signature.         */
#define BS_VOLID               67,  4   /* Volume ID (serial number).       */
#define BS_VOLLAB              71, 11   /* Volume label.                    */
#define BS_FILSYSTYPE          82,  8   /* File system type: "FAT12   ", 
                                           "FAT16   " or "FAT     "         */

/* File system and operating system specific boot code (next 420 bytes). */
/*                         offset | size (both in bytes)                    */
#define BS_CODE                90, 420  /* Executable code.                 */

/* Signature (last 2 bytes). */
/*                         offset | size (both in bytes)                    */
#define BS_SIGNATURE          510,  2   /* Boot signature.                  */

/****************************************************************************
 *                    FS Information Sector structure.                      *
 * This sector is used for speeding up access times of certain operations.  *
 ****************************************************************************/

/*                         offset | size (both in bytes)                    */
#define FSI_LEADSIG             0,  4   /* Lead signature.                  */
#define FSI_RESERVED1           4, 480  /* Reserved.                        */
#define FSI_STRUCSIG          484,  4   /* Another signature.               */
#define FSI_FREE_COUNT        488,  4   /* Number of free clusters.         */
#define FSI_NXT_FREE          492,  4   /* Most recently allocated cluster. */
#define FSI_RESERVED2         496, 12   /* Reserved.                        */
#define FSI_TRAILSIG          508,  4   /* Trail signature.                 */

/****************************************************************************
 *                      File Allocation Table.                              *
 * The File Allocation Table is a table that indicates the status and       *
 * location of all data clusters on the disk. It can be                     *
 * considered the "table of contents" of a disk. The cluster may be         *
 * available for use, it may be reserved by the operating system, it may    *
 * be unavailable due to a bad sector on the disk, or it may be in use      *
 * by a file. The clusters of a file need not to be right next to each      *
 * other on the disk. The FAT allows the operating system to follow the     *
 * chain of clusters in a file.                                             *
 *                                                                          *
 * Since the first cluster of the Data Region is cluster #2, the first 2    *
 * entries of the FAT are unused.                                           *
 *                                                                          *
 * Note that despite its name FAT32 uses only 28 bits of the 32 possible    *
 * bits to address the clusters on the disk: the upper 4 bits should be     *
 * left untouched.                                                          *
 ****************************************************************************/

#define FAT_ENTRY_SIZE      4           /* Size of a FAT entry (in bytes)   */

/* FAT entry values. */
#define FREE                0x00000000  /* Free cluster.                    */
#define RESERVED            0x00000001  /* Reserved for internal purposes.  */
#define BAD                 0x0FFFFFF7  /* Bad sector in cluster.           */

// Value in this range should be interpreted as next cluster number.
#define USED_MIN            0x00000002  /* Minimum value to be considered
                                           as used for data clusters.       */
#define USED_MAX            0x0FFFFFEF  /* Maximum value to be considered 
                                           as used for data clusters.       */
                                           
// Value in this range means this is the last cluster in file.
#define EOC_MIN             0x0FFFFFF8  /* Minimum value to be considered
                                           as end-of-chain marker.          */
#define EOC_MAX             0x0FFFFFFF  /* Maximum value to be considered
                                           as end-of-chain marker.          */

/****************************************************************************
 *                            Directory table.                              *
 * A directory table is a special type of file that represents a directory. *
 * Each file or subdirectory stored within it is represented by a 32-byte   *
 * entry in the table. All directory tables are stored in the Data Region.  *
 * The actual number of entries in a directory stored in the Data Region    *
 * can grow by adding another cluster to the chain in the FAT.              *
 *                                                                          *
 * A directory entry simply stores the information needed to know where     *
 * a file's data or a folder's children are stored on the disk.             *
 *                                                                          *
 * The only special directory which must always be present is the root      *
 * directory. For FAT32, it can be of variable size and is a cluster,       *
 * just like any other directory is (this is not true for FAT12/FAT16).     *
 * The first cluster of the root directory on a FAT32 volume is stored in   *
 * BPB_ROOTCLUS.                                                            *
 *                                                                          *
 * Each entry can be preceded by "fake entries" to support a VFAT long      *
 * filename (LFN, see further below). When such a directory entry is        *
 * encountered, it is given special treatment by the file system.           *
 ****************************************************************************/

#define DIR_ENTRY_SIZE         32       /* Directory entry size (in bytes)  */
#define PATH_MAX_SIZE         260       /* Max file path length (bytes)     */
#define NAME_MAX_SIZE         256       /* Max file/dir name length (bytes) */

/****************************************************************************
 *                          Standard 8.3 format.                            *
 * For a classic 8.3 filename entry, the DIR_NAME field is actually broken  *
 * in 2 parts: the 8-characters main part of the name and the 3-characters  *
 * extension. These 2 parts are "trailing space padded".                    *
 *                                                                          *
 * Furthermore, all classic 8.3 filenames are uppercase.                    *
 ****************************************************************************/

/*                         offset | size (both in bytes)                    */
#define DIR_NAME                0, 11   /* Short file name.                 */
#define DIR_ATTR               11,  1   /* File attributes.                 */
#define DIR_NTRES              12,  1   /* Reserved for use by WINDOWS NT.  */
#define DIR_CRTTIMETENTH       13,  1   /* Millisecond stamp at file 
                                           creation time.                   */
#define DIR_CRTTIME            14,  2   /* Time file was created.           */
#define DIR_CRTDATE            16,  2   /* Date file was created.           */
#define DIR_LSTACCDATE         18,  2   /* Last access date.                */
#define DIR_FSTCLUSHI          20,  2   /* High 16 bits of this entry's 
                                           first cluster number.            */
#define DIR_WRTTIME            22,  2   /* Time of last write.              */
#define DIR_WRTDATE            24,  2   /* Date of last write.              */
#define DIR_FSTCLUSLO          26,  2   /* Low 16 bits of this entry's 
                                           first cluster number.            */
#define DIR_FILESIZE           28,  4   /* This file's size in bytes.       */

/* File attributes (DIR_ATTR values). */
#define ATTR_READ_ONLY          0x01    /* Writes to file should fail.      */
#define ATTR_HIDDEN             0x02    /* Normal directory listings should
                                           not show this file.              */
#define ATTR_SYSTEM             0x04    /* File belongs to the system, must
                                           not be physically moved.         */
#define ATTR_VOLUME_ID          0x08    /* Volume label.                    */
#define ATTR_DIRECTORY          0x10    /* Container for other files.       */
#define ATTR_ARCHIVE            0x20    /* Archive (file marked as dirty).  */
#define ATTR_LONG_NAME          0x0F    /* The file is part of the long 
                                           long entry for some other file.  */ 

/* Special values of the first byte DIR_NAME[0] of a FAT directory entry. */
#define FREE_ENTRY              0xE5    /* Directory entry is free.         */
#define LAST_ENTRY              0x00    /* No subsequent entry in use.      */

/****************************************************************************
 *                          Long File Name format.                          *
 * Long File Names are stored on FAT file system using a trick: adding      *
 * (possibly multiple) additional entries to the directory before the       *
 * normal file entry. This means that long file name entries is always      *
 * associated with a regular 8.3 entry that they always immediately         *
 * precede (this because only short directory entries are visible to        *
 * previous versions of MS-DOS).                                            *
 *                                                                          *
 * Note 1: every member of a set of long entries is uniquely numbered and   *
 * the LDIR_ORD field of the last member of the set is or'd with a flag     *
 * indicating that it is in fact the last member of the set. On the other   *
 * hand, this field cannot have values of 0xE5 or 0x00 (see above).         *
 *                                                                          *
 * Note 2: an 8-bit checksum is computed on the name contained in the       *
 * short directory entry at the time the short and long directory entries   *
 * are created. This checksum is then placed in every long entry. All 11    *
 * characters of the name in the short entry are used in the checksum       *
 * calculation.                                                             *
 *                                                                          *
 * Note 3: if there are multiple LFN entries, firstly comes the LAST LFN    *
 * entry (the last part of the file name).                                  *
 ****************************************************************************/

/*                         offset | size (both in bytes)                    */
#define LDIR_ORD                0,  1   /* Order of this entry in the
                                           sequence of long directory
                                           entries.                         */
#define LDIR_NAME1              1, 10   /* Characters 1-5 of the long name
                                           sub-component in this entry.     */
#define LDIR_ATTR              11,  1   /* Must be ATTR_LONG_NAME.          */
#define LDIR_TYPE              12,  1   /* Always 0.                        */
#define LDIR_CHKSUM            13,  1   /* Checksum of name in the short
                                           directory entry at the end of 
                                           the long directory set.          */
#define LDIR_NAME2             14, 12   /* Characters 6-11 of the long name
                                           sub-component in this entry.     */
#define LDIR_FSTCLUSLO         26,  2   /* Must be 0.                       */
#define LDIR_NAME3             28,  4   /* Characters 12-13 of the long name
                                           sub-component in this entry.     */

/* Last long directory entry mask. */
#define LAST_LONG_ENTRY         0x40
                                           

/****************************************************************************
 * This structure defines a FAT32 File System descriptor.                   *
 ****************************************************************************/

#include <hal_kernel_types.h>

typedef struct fat_desc_s
{
    unsigned char   block_buffer[512];  /* Buffer for FS Information.       */
    uint32_t        block_buffer_lba;   /* LBA of block_buffer.             */
    uint32_t        initialized;        /* Status of the FAT32 File System. */
    uint32_t        sector_size;        /* Must be 512 bytes.               */
    uint32_t        cluster_size;       /* Must be 4096 bytes.              */
    uint32_t        fat_sectors;        /* Count of sectors in FAT Region.  */
    uint32_t        fat_lba;            /* LBA of first FAT sector.         */
    uint32_t        data_sectors;       /* Count of sectors in Data Region. */
    uint32_t        data_lba;           /* LBA of first data sector.        */
    uint32_t        root_cluster;       /* first cluster of root directory. */
    uint32_t        fsi_lba;            /* LBA of FS Information.           */
    uint32_t        free_cluster_hint;  /* Start point for free cluster     */
    uint32_t        free_clusters_nr;   /* Total number of free clusters.   */
}
fat_desc_t;

/****************************************************************************
 *                   Basic operations of FAT32 File System.                 *
 ****************************************************************************/

extern fat_desc_t   boot_fat;

/****************************************************************************
 * This function initializes the FAT32 File System.                         *
 *                                                                          *
 * @ returns 0 on success, -1 on error.                                     *
 ****************************************************************************/
int boot_fat32_init();

/****************************************************************************
 * This function loads the 'pathname' file into the memory buffer at base   *
 * address 'buff_addr' of 'buff_size'. It uses the 512-byte buffer defined  *
 * in the FAT32 descriptor.                                                 *
 * @ pathname   : file to be loaded pathname.                               *
 * @ buff_addr  : memory address of file containing buffer.                 *
 * @ buff_size  : size of file containing buffer (in bytes).                *
 *                                                                          *
 * @ returns 0 on success, -1 on error.                                     *
 ****************************************************************************/
int boot_fat32_load( char*    pathname,
                     uint32_t buff_addr,
                     uint32_t buff_size );

#endif // BOOT_FAT32_H
