wiiu-nanddumper-payload/ios_fs/source/fat32_format.c
2016-12-12 19:31:02 +01:00

327 lines
9.6 KiB
C

#include <stdio.h>
#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;
}