#include #include "types.h" #include "imports.h" #include "devices.h" #include "sdio.h" #include "text.h" extern unsigned char io_buffer[0x40000]; #define PARTITION_TYPE_FAT32 0x0c #define MAX_PARTITIONS 32 /* Maximum number of partitions that can be found */ #define MAX_MOUNTS 10 /* Maximum number of mounts available at one time */ #define MAX_SYMLINK_DEPTH 10 /* Maximum search depth when resolving symbolic links */ #define MBR_SIGNATURE 0x55AA #define EBR_SIGNATURE MBR_SIGNATURE #define PARTITION_BOOTABLE 0x80 /* Bootable (active) */ #define PARTITION_NONBOOTABLE 0x00 /* Non-bootable */ #define PARTITION_TYPE_GPT 0xEE /* Indicates that a GPT header is available */ typedef struct _PARTITION_RECORD { u8 status; /* Partition status; see above */ u8 chs_start[3]; /* Cylinder-head-sector address to first block of partition */ u8 type; /* Partition type; see above */ u8 chs_end[3]; /* Cylinder-head-sector address to last block of partition */ u32 lba_start; /* Local block address to first sector of partition */ u32 block_count; /* Number of blocks in partition */ } __attribute__((__packed__)) PARTITION_RECORD; typedef struct _MASTER_BOOT_RECORD { u8 code_area[446]; /* Code area; normally empty */ PARTITION_RECORD partitions[4]; /* 4 primary partitions */ u16 signature; /* MBR signature; 0xAA55 */ } __attribute__((__packed__)) MASTER_BOOT_RECORD; typedef struct tagFAT_BOOTSECTOR32 { // Common fields. u8 sJmpBoot[3]; u8 sOEMName[8]; u16 wBytsPerSec; u8 bSecPerClus; u16 wRsvdSecCnt; u8 bNumFATs; u16 wRootEntCnt; u16 wTotSec16; u8 bMedia; u16 wFATSz16; u16 wSecPerTrk; u16 wNumHeads; u32 dHiddSec; u32 dTotSec32; // Fat 32/16 only u32 dFATSz32; u16 wExtFlags; u16 wFSVer; u32 dRootClus; u16 wFSInfo; u16 wBkBootSec; u8 Reserved[12]; u8 bDrvNum; u8 Reserved1; u8 bBootSig; // == 0x29 if next three fields are ok u32 dBS_VolID; u8 sVolLab[11]; u8 sBS_FilSysType[8]; } __attribute__((__packed__)) FAT_BOOTSECTOR32; typedef struct { u32 dLeadSig; u8 sReserved1[480]; u32 dStrucSig; u32 dFree_Count; u32 dNxt_Free; u8 sReserved2[12]; u32 dTrailSig; } __attribute__((__packed__)) FAT_FSINFO; static inline u8 get_sectors_per_cluster (u64 DiskSizeBytes) { u8 ret = 0x01; // 1 sector per cluster u32 DiskSizeMB = DiskSizeBytes/(1024*1024); // 512 MB to 8,191 MB 4 KB if (DiskSizeMB > 512) ret = 0x8; // 8,192 MB to 16,383 MB 8 KB if (DiskSizeMB > 8192) ret = 0x10; // 16,384 MB to 32,767 MB 16 KB if (DiskSizeMB > 16384) ret = 0x20; // ret = 0x20; // Larger than 32,768 MB 32 KB if (DiskSizeMB > 32768) ret = 0x40; // ret = 0x40; return ret; } static inline u32 MakeVolumeID() { // we dont have time yet so for now its fixed //time_t rawtime = time(0); //struct tm * timeinfo = localtime(&rawtime); //u16 hi = le16(timeinfo->tm_mday + (timeinfo->tm_mon << 8) + (timeinfo->tm_sec << 8)); //u16 lo = le16((timeinfo->tm_hour << 8) + timeinfo->tm_min + timeinfo->tm_year + 1900); u16 hi = 0x0BAD; u16 lo = 0xBABE; return (lo + (hi << 16)); } int FormatToFAT32(u32 lba, u32 sec_count) { if(sec_count < 0xFFFF) { _printf(20, 40, "Not enough sectors for FAT32"); return -1; } int BytesPerSect = SDIO_BYTES_PER_SECTOR; u16 ReservedSectCount = 32; u8 NumFATs = 2; memset(io_buffer, 0, BytesPerSect*18); FAT_BOOTSECTOR32 * FAT32BootSect = (FAT_BOOTSECTOR32 *) (io_buffer+16*BytesPerSect); FAT_FSINFO * FAT32FsInfo = (FAT_FSINFO*) (io_buffer+17*BytesPerSect); // fill out the boot sector and fs info FAT32BootSect->sJmpBoot[0] = 0xEB; FAT32BootSect->sJmpBoot[1] = 0x5A; FAT32BootSect->sJmpBoot[2] = 0x90; memcpy(FAT32BootSect->sOEMName, "MSWIN4.1", 8); FAT32BootSect->wBytsPerSec = le16(BytesPerSect); u8 SectorsPerCluster = get_sectors_per_cluster((u64) sec_count * (u64) BytesPerSect); FAT32BootSect->bSecPerClus = SectorsPerCluster; FAT32BootSect->wRsvdSecCnt = le16(ReservedSectCount); FAT32BootSect->bNumFATs = NumFATs; FAT32BootSect->wRootEntCnt = 0; FAT32BootSect->wTotSec16 = 0; FAT32BootSect->bMedia = 0xF8; FAT32BootSect->wFATSz16 = 0; FAT32BootSect->wSecPerTrk = le16(63); //SectorsPerTrack; FAT32BootSect->wNumHeads = le16(255); //TracksPerCylinder; FAT32BootSect->dHiddSec = le32(lba); //HiddenSectors; FAT32BootSect->dTotSec32 = le32(sec_count); // This is based on // http://hjem.get2net.dk/rune_moeller_barnkob/filesystems/fat.html u32 FatSize = (4*(sec_count-ReservedSectCount)/((SectorsPerCluster*BytesPerSect)+(4*NumFATs)))+1; FAT32BootSect->dFATSz32 = le32(FatSize); FAT32BootSect->wExtFlags = 0; FAT32BootSect->wFSVer = 0; FAT32BootSect->dRootClus = le32(2); FAT32BootSect->wFSInfo = le16(1); FAT32BootSect->wBkBootSec = le16(6); //BackupBootSect FAT32BootSect->bDrvNum = 0x80; FAT32BootSect->Reserved1 = 0; FAT32BootSect->bBootSig = 0x29; FAT32BootSect->dBS_VolID = MakeVolumeID(); memcpy(FAT32BootSect->sVolLab, "NO NAME ", 11); memcpy(FAT32BootSect->sBS_FilSysType, "FAT32 ", 8); ((u8 *)FAT32BootSect)[510] = 0x55; //Boot Record Signature ((u8 *)FAT32BootSect)[511] = 0xAA; //Boot Record Signature // FSInfo sect signatures FAT32FsInfo->dLeadSig = le32(0x41615252); FAT32FsInfo->dStrucSig = le32(0x61417272); FAT32FsInfo->dTrailSig = le32(0xaa550000); ((u8 *)FAT32FsInfo)[510] = 0x55; //Boot Record Signature ((u8 *)FAT32FsInfo)[511] = 0xAA; //Boot Record Signature // First FAT Sector u32 FirstSectOfFat[3]; FirstSectOfFat[0] = le32(0x0ffffff8); // Reserved cluster 1 media id in low byte FirstSectOfFat[1] = le32(0x0fffffff); // Reserved cluster 2 EOC FirstSectOfFat[2] = le32(0x0fffffff); // end of cluster chain for root dir u32 UserAreaSize = sec_count - ReservedSectCount - (NumFATs*FatSize); u32 ClusterCount = UserAreaSize/SectorsPerCluster; if (ClusterCount > 0x0FFFFFFF) { _printf(20, 40, "This drive has more than 2^28 clusters. Partition might be too small."); return -1; } if (ClusterCount < 65536) { _printf(20, 40, "FAT32 must have at least 65536 clusters"); return -1; } u32 FatNeeded = (ClusterCount * 4 + (BytesPerSect-1))/BytesPerSect; if (FatNeeded > FatSize) { _printf(20, 40, "This drive is too big, %u > %u", FatNeeded, FatSize); return -1; } // fix up the FSInfo sector FAT32FsInfo->dFree_Count = le32((UserAreaSize/SectorsPerCluster)-1); FAT32FsInfo->dNxt_Free = le32(3); // clusters 0-1 resered, we used cluster 2 for the root dir /** Now all is done and we start writting **/ // First zero out ReservedSect + FatSize * NumFats + SectorsPerCluster u32 SystemAreaSize = (ReservedSectCount+(NumFATs*FatSize) + SectorsPerCluster); u32 done = 0; // Read the first sector on the device while(SystemAreaSize > 0) { int write = SystemAreaSize < 16 ? SystemAreaSize : 16; int result = sdcard_readwrite(SDIO_WRITE, io_buffer, write, SDIO_BYTES_PER_SECTOR, lba+done, NULL, DEVICE_ID_SDCARD_PATCHED); if(result != 0) { _printf(20, 40, "Cannot write to the drive."); return -1; } SystemAreaSize -= write; done += write; } for (int i = 0; i < 2; i++) { u32 SectorStart = (i == 0) ? lba : lba+6; //BackupBootSect int result = sdcard_readwrite(SDIO_WRITE, FAT32BootSect, 1, SDIO_BYTES_PER_SECTOR, SectorStart, NULL, DEVICE_ID_SDCARD_PATCHED); if(result != 0) { _printf(20, 40, "Cannot write to the drive."); return -1; } result = sdcard_readwrite(SDIO_WRITE, FAT32FsInfo, 1, SDIO_BYTES_PER_SECTOR, SectorStart+1, NULL, DEVICE_ID_SDCARD_PATCHED); if(result != 0) { _printf(20, 40, "Cannot write to the drive."); return -1; } } memcpy(io_buffer, FirstSectOfFat, sizeof(FirstSectOfFat)); // Write the first fat sector in the right places for (int i = 0; i < NumFATs; i++) { u32 SectorStart = lba + ReservedSectCount + (i * FatSize); int result = sdcard_readwrite(SDIO_WRITE, io_buffer, 1, SDIO_BYTES_PER_SECTOR, SectorStart, NULL, DEVICE_ID_SDCARD_PATCHED); if(result != 0) { _printf(20, 40, "Cannot write to the drive."); return -1; } } return 0; } int CheckFAT32PartitionOffset(u8 * mbr_buf, u32 partition_offset) { MASTER_BOOT_RECORD *mbr = (MASTER_BOOT_RECORD*)mbr_buf; return (mbr->signature == MBR_SIGNATURE) && (le32(mbr->partitions[0].lba_start) >= partition_offset); } int FormatSDCard(u32 partition_offset, u32 total_sectors) { _printf(20, 40, "Formatting SD card...."); MASTER_BOOT_RECORD *mbr = (MASTER_BOOT_RECORD*)io_buffer; memset(mbr, 0, SDIO_BYTES_PER_SECTOR); int result = sdcard_readwrite(SDIO_READ, mbr, 1, SDIO_BYTES_PER_SECTOR, 0, NULL, DEVICE_ID_SDCARD_PATCHED); if(result != 0) { _printf(20, 40, "SD card read failed %i", result); return result; } u32 lba_start = partition_offset; result = FormatToFAT32(lba_start, total_sectors - partition_offset); if(result != 0) return result; memset(mbr, 0, sizeof(MASTER_BOOT_RECORD)); mbr->signature = MBR_SIGNATURE; // setup primary FAT32 partition mbr->partitions[0].status = PARTITION_BOOTABLE; // set activate mbr->partitions[0].chs_start[0] = mbr->partitions[0].chs_end[0] = 0xFE; mbr->partitions[0].chs_start[1] = mbr->partitions[0].chs_end[1] = 0xFF; mbr->partitions[0].chs_start[2] = mbr->partitions[0].chs_end[2] = 0xFF; mbr->partitions[0].type = PARTITION_TYPE_FAT32; mbr->partitions[0].lba_start = le32(lba_start); mbr->partitions[0].block_count = le32((total_sectors - partition_offset)); result = sdcard_readwrite(SDIO_WRITE, mbr, 1, SDIO_BYTES_PER_SECTOR, 0, NULL, DEVICE_ID_SDCARD_PATCHED); if(result != 0) { _printf(20, 40, "SD card write failed %i", result); } else { _printf(20, 40, "Format of SD card finished successfully", result); } return result; }