mirror of
https://github.com/wiiu-env/wiiu-nanddumper-payload.git
synced 2024-11-05 11:15:09 +01:00
327 lines
9.6 KiB
C
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;
|
||
|
}
|