wiiu-nanddumper-payload/ios_fs/source/dumper.c

322 lines
11 KiB
C

#include <stdio.h>
#include "types.h"
#include "imports.h"
#include "devices.h"
#include "sdio.h"
#include "mlcio.h"
#include "fat32_format.h"
#include "text.h"
#include "hardware_registers.h"
#include "svc.h"
// the IO buffer is put behind everything else because there is no access to this region from IOS-FS it seems
unsigned char io_buffer[0x40000] __attribute__((aligned(0x40))) __attribute__((section(".io_buffer")));
//! this one is required for the read function
static void slc_read_callback(int result, int priv)
{
int *private_data = (int*)priv;
private_data[1] = result;
FS_SVC_RELEASEMUTEX(private_data[0]);
}
static int srcRead(void* deviceHandle, void *data_ptr, u32 offset, u32 sectors, int * result_array)
{
int readResult = slcRead1_original(deviceHandle, 0, offset, sectors, SLC_BYTES_PER_SECTOR, data_ptr, slc_read_callback, (int)result_array);
if(readResult == 0)
{
// wait for process to finish
FS_SVC_ACQUIREMUTEX(result_array[0], 0);
readResult = result_array[1];
}
return readResult;
}
void slc_dump(void *deviceHandle, const char* device, u32 base_sectors, int y_offset)
{
//also create a mutex for synchronization with end of operation...
int sync_mutex = FS_SVC_CREATEMUTEX(1, 1);
FS_SVC_ACQUIREMUTEX(sync_mutex, 0);
int result_array[2];
result_array[0] = sync_mutex;
u32 offset = 0;
int readResult = 0;
int writeResult = 0;
int retry = 0;
u32 readSize = sizeof(io_buffer) / SLC_BYTES_PER_SECTOR;
FS_SLEEP(1000);
do
{
// don't print single steps in between, just if they have an error or every 0x80 sectors
if((readSize == (sizeof(io_buffer) / SLC_BYTES_PER_SECTOR)) || (retry > 0))
{
_printf(20, y_offset, "%s = %08X / 40000, read code %08X, write code %08X, retry %d", device, offset, readResult, writeResult, retry);
}
//! set flash erased byte to buffer
FS_MEMSET(io_buffer, 0xff, sizeof(io_buffer));
//readResult = readSlc(io_buffer, offset, (sizeof(io_buffer) / SLC_BYTES_PER_SECTOR), deviceHandle);
readResult = srcRead(deviceHandle, io_buffer, offset, readSize, result_array);
//! retry 2 times as there are read failures in several places
if((readResult != 0) && (retry < 2))
{
readSize = 1;
FS_SLEEP(10);
retry++;
}
else
{
retry = 0;
while(1)
{
FS_SLEEP(10);
writeResult = sdcard_readwrite(SDIO_WRITE, io_buffer, (readSize * (SLC_BYTES_PER_SECTOR / SDIO_BYTES_PER_SECTOR)), SDIO_BYTES_PER_SECTOR, base_sectors, NULL, DEVICE_ID_SDCARD_PATCHED);
if((writeResult == 0) || (retry >= 2))
{
retry = 0;
base_sectors += (readSize * (SLC_BYTES_PER_SECTOR / SDIO_BYTES_PER_SECTOR));
offset += readSize;
// if we did single sector reads and got to a point where we can do multiple reads -> switch to multiple sector reads
if((offset % (sizeof(io_buffer) / SLC_BYTES_PER_SECTOR)) == 0)
{
readSize = sizeof(io_buffer) / SLC_BYTES_PER_SECTOR;
}
break;
}
else
{
retry++;
}
}
}
}
while (offset < SLC_SECTOR_COUNT);
FS_SVC_DESTROYMUTEX(sync_mutex);
// last print to show "done"
_printf(20, y_offset, "%s = %08X / 40000, read code %08X, write code %08X, retry %d", device, offset, readResult, writeResult, retry);
}
void mlc_dump(u32 base_sector, u32 mlc_end)
{
u32 offset = 0;
int retry = 0;
int mlc_result = 0;
int callback_result = 0;
int write_result = 0;
int print_counter = 0;
do
{
//! print only every 4th time
if(print_counter == 0)
{
print_counter = 4;
_printf(20, 70, "mlc = %08X / %08X, mlc res %08X, sd res %08X, retry %d", offset, mlc_end, mlc_result, write_result, retry);
}
else
{
--print_counter;
}
//! set flash erased byte to buffer
FS_MEMSET(io_buffer, 0xff, sizeof(io_buffer));
mlc_result = sdcard_readwrite(SDIO_READ, io_buffer, (sizeof(io_buffer) / MLC_BYTES_PER_SECTOR), MLC_BYTES_PER_SECTOR, offset, &callback_result, DEVICE_ID_MLC);
if((mlc_result == 0) && (callback_result != 0))
{
mlc_result = callback_result;
}
//! retry 5 times as there are read failures in several places
if((mlc_result != 0) && (retry < 5))
{
FS_SLEEP(100);
retry++;
print_counter = 0; // print errors directly
}
else
{
write_result = sdcard_readwrite(SDIO_WRITE, io_buffer, (sizeof(io_buffer) / MLC_BYTES_PER_SECTOR), SDIO_BYTES_PER_SECTOR, base_sector + offset, NULL, DEVICE_ID_SDCARD_PATCHED);
if((write_result == 0) || (retry >= 5))
{
retry = 0;
offset += (sizeof(io_buffer) / MLC_BYTES_PER_SECTOR);
}
else
{
FS_SLEEP(100);
retry++;
print_counter = 0; // print errors directly
}
}
}
while(offset < mlc_end); //! TODO: make define MLC32_SECTOR_COUNT
// last print to show "done"
_printf(20, 70, "mlc = %08X / %08X, mlc res %08X, sd res %08X, retry %d", offset, mlc_end, mlc_result, write_result, retry);
}
int check_nand_type(void)
{
//! check if MLC size is > 8GB
if( FS_MMC_MLC_STRUCT[0x30/4] > 0x1000000)
{
return MLC_NAND_TYPE_32GB;
}
else
{
return MLC_NAND_TYPE_8GB;
}
}
int check_nand_dump(void)
{
u32 mlc_sector_count = FS_MMC_MLC_STRUCT[0x30/4];
int signature_correct = 0;
sdio_nand_signature_sector_t * sign_sect = (sdio_nand_signature_sector_t*)io_buffer;
memset(sign_sect, 0, SDIO_BYTES_PER_SECTOR);
sdcard_readwrite(SDIO_READ, sign_sect, 1, SDIO_BYTES_PER_SECTOR, NAND_DUMP_SIGNATURE_SECTOR, NULL, DEVICE_ID_SDCARD_PATCHED);
signature_correct = (sign_sect->signature == NAND_DUMP_SIGNATURE);
memset(io_buffer, 0, SDIO_BYTES_PER_SECTOR);
sdcard_readwrite(SDIO_READ, io_buffer, 1, SDIO_BYTES_PER_SECTOR, 0, NULL, DEVICE_ID_SDCARD_PATCHED);
return signature_correct && CheckFAT32PartitionOffset(io_buffer, MLC_BASE_SECTORS + mlc_sector_count);
}
static void wait_format_confirmation(void)
{
int timeout = 600;
//"Press the POWER button SD then , else the console will reboot in %u seconds."
while(1)
{
_printf(20, 30, "No NAND dump detected. SD Format and complete NAND dump required.");
_printf(20, 40, "Press the POWER button to format SD card otherwise the console will reboot in %d seconds.", timeout/10);
if(svcRead32(LT_GPIO_IN) & GPIO_IN_POWER_BUTTON)
{
break;
}
if(--timeout == 0)
{
FS_SLEEP(1000);
svcShutdown(SHUTDOWN_TYPE_REBOOT);
}
FS_SLEEP(100);
}
// clear the lines
clearLine(30, 0x000000FF);
clearLine(40, 0x000000FF);
}
void dump_nand_complete()
{
wait_format_confirmation();
mlc_init();
FS_SLEEP(1000);
int nand_type = check_nand_type();
u32 sdio_sector_count = FS_MMC_SDCARD_STRUCT[0x30/4];
u32 mlc_sector_count = FS_MMC_MLC_STRUCT[0x30/4];
u32 fat32_partition_offset = (MLC_BASE_SECTORS + mlc_sector_count);
_printf(20, 30, "Detected %d GB MLC NAND type.", (nand_type == MLC_NAND_TYPE_8GB) ? 8 : 32);
if(sdio_sector_count < fat32_partition_offset)
{
_printf(20, 40, "SD card too small! Required sectors %u > available %u.", fat32_partition_offset, sdio_sector_count);
FS_SLEEP(3000);
svcShutdown(SHUTDOWN_TYPE_REBOOT);
}
if( FormatSDCard(fat32_partition_offset, sdio_sector_count) < 0 )
{
FS_SLEEP(3000);
svcShutdown(SHUTDOWN_TYPE_REBOOT);
}
slc_dump(FS_SLC_PHYS_DEV_STRUCT, "slc ", SLC_BASE_SECTORS, 50);
slc_dump(FS_SLCCMPT_PHYS_DEV_STRUCT, "slccmpt", SLCCMPT_BASE_SECTORS, 60);
mlc_dump(MLC_BASE_SECTORS, mlc_sector_count);
//! write marker to SD card from which we can auto detect NAND dump
//! we can actually use that for settings
sdio_nand_signature_sector_t * sign_sect = (sdio_nand_signature_sector_t*)io_buffer;
memset(sign_sect, 0, SDIO_BYTES_PER_SECTOR);
sign_sect->signature = NAND_DUMP_SIGNATURE;
sign_sect->nand_descriptions[0].nand_type = NAND_DESC_TYPE_SLC;
sign_sect->nand_descriptions[0].base_sector = SLC_BASE_SECTORS;
sign_sect->nand_descriptions[0].sector_count = SLC_SECTOR_COUNT * (SLC_BYTES_PER_SECTOR / SDIO_BYTES_PER_SECTOR);
sign_sect->nand_descriptions[1].nand_type = NAND_DESC_TYPE_SLCCMPT;
sign_sect->nand_descriptions[1].base_sector = SLCCMPT_BASE_SECTORS;
sign_sect->nand_descriptions[1].sector_count = SLC_SECTOR_COUNT * (SLC_BYTES_PER_SECTOR / SDIO_BYTES_PER_SECTOR);
sign_sect->nand_descriptions[2].nand_type = NAND_DESC_TYPE_MLC;
sign_sect->nand_descriptions[2].base_sector = MLC_BASE_SECTORS;
sign_sect->nand_descriptions[2].sector_count = mlc_sector_count * (MLC_BYTES_PER_SECTOR / SDIO_BYTES_PER_SECTOR);
sdcard_readwrite(SDIO_WRITE, io_buffer, 1, SDIO_BYTES_PER_SECTOR, NAND_DUMP_SIGNATURE_SECTOR, NULL, DEVICE_ID_SDCARD_PATCHED);
_printf(20, 80, "Complete! -> rebooting into sysNAND...");
FS_SLEEP(3000);
svcShutdown(SHUTDOWN_TYPE_REBOOT);
}
#if 0
// debug and not used at the moment
void dump_data(void* data_ptr, u32 size)
{
static u32 dumpdata_offset = 0;
u32 num_sectors = size >> 9; // size / SDIO_BYTES_PER_SECTOR but faster ;)
if (num_sectors == 0)
num_sectors = 1;
sdcard_readwrite(SDIO_WRITE, data_ptr, num_sectors, SDIO_BYTES_PER_SECTOR, DUMPDATA_BASE_SECTORS + dumpdata_offset, NULL, DEVICE_ID_SDCARD_PATCHED);
dumpdata_offset += num_sectors;
}
void dump_lots_data(u8* addr, u32 size)
{
u32 cur_size;
u32 size_remaining = size;
u8* cur_addr = addr;
do
{
cur_size = sizeof(io_buffer);
if (cur_size > size_remaining)
cur_size = size_remaining;
FS_MEMCPY(io_buffer, cur_addr, cur_size);
dump_data(io_buffer, cur_size);
cur_addr += cur_size;
size_remaining -= cur_size;
}
while (cur_size != 0);
}
void dump_syslog()
{
FS_MEMCPY(io_buffer, *(void**)0x05095ECC, sizeof(io_buffer));
sdcard_readwrite(SDIO_WRITE, io_buffer, sizeof(io_buffer) / SDIO_BYTES_PER_SECTOR, SDIO_BYTES_PER_SECTOR, SYSLOG_BASE_SECTORS, NULL, DEVICE_ID_SDCARD_PATCHED);
}
#endif