void getEmunandSect(u32 *off, u32 *head, u32 *emuNAND) { static u8 *const temp = (u8 *)0x24300000; const u32 nandSize = getMMCDevice(0)->total_size; u32 nandOffset = *emuNAND == 1 ? 0 : (nandSize > 0x200000 ? 0x400000 : 0x200000); //Check for RedNAND if(!sdmmc_sdcard_readsectors(nandOffset + 1, 1, temp) && *(u32 *)(temp + 0x100) == NCSD_MAGIC) { *off = nandOffset + 1; *head = nandOffset + 1; } //Check for Gateway emuNAND else if(!sdmmc_sdcard_readsectors(nandOffset + nandSize, 1, temp) && *(u32 *)(temp + 0x100) == NCSD_MAGIC) { *off = nandOffset; *head = nandOffset + nandSize; } /* Fallback to the first emuNAND if there's no second one, or to SysNAND if there isn't any */ else { (*emuNAND)--; if(*emuNAND) getEmunandSect(off, head, emuNAND); } }
void getEmunandSect(u32 *off, u32 *head, u32 *emuNAND) { u8 *const temp = (u8 *)0x24300000; const u32 nandSize = getMMCDevice(0)->total_size; u32 nandOffset = *emuNAND == 1 ? 0 : (nandSize > 0x200000 ? 0x400000 : 0x200000); //Check for RedNAND if(sdmmc_sdcard_readsectors(nandOffset + 1, 1, temp) == 0) { if(*(u32 *)(temp + 0x100) == NCSD_MAGIC) { *off = nandOffset + 1; *head = nandOffset + 1; } //Check for Gateway emuNAND else if(sdmmc_sdcard_readsectors(nandOffset + nandSize, 1, temp) == 0) { if(*(u32 *)(temp + 0x100) == NCSD_MAGIC) { *off = nandOffset; *head = nandOffset + nandSize; } //Fallback to the first emuNAND if there's no second one else if(*emuNAND == 2) { *emuNAND = 1; getEmunandSect(off, head, emuNAND); } else *emuNAND = 0; } } }
u32 CheckEmuNand(void) { u8* buffer = BUFFER_ADDRESS; u32 nand_size_sectors = getMMCDevice(0)->total_size; u32 nand_offset; if (emunand_no > 0) { if (nand_size_sectors > EMUNAND_MULTI_OFFSET_O3DS) { nand_offset = EMUNAND_MULTI_OFFSET_N3DS * (emunand_no - 1 ); } else { nand_offset = EMUNAND_MULTI_OFFSET_O3DS * (emunand_no - 1 ); } } else { nand_offset = 0; } // check the MBR for presence of EmuNAND sdmmc_sdcard_readsectors(0, 1, buffer); if (nand_offset+nand_size_sectors > getle32(buffer + 0x1BE + 0x8)) return EMUNAND_NOT_READY; // check for Gateway type EmuNAND sdmmc_sdcard_readsectors(nand_offset+nand_size_sectors, 1, buffer); if (memcmp(buffer + 0x100, "NCSD", 4) == 0) return EMUNAND_GATEWAY; // check for RedNAND type EmuNAND sdmmc_sdcard_readsectors(nand_offset + 1, 1, buffer); if (memcmp(buffer + 0x100, "NCSD", 4) == 0) return EMUNAND_REDNAND; // EmuNAND ready but not set up return EMUNAND_READY; }
int get_emunand_offsets(uint32_t location, uint32_t *offset, uint32_t *header) { if (sdmmc_sdcard_readsectors(location + 1, 1, fcram_temp) == 0) { if (*(uint32_t *)(fcram_temp + 0x100) == NCSD_MAGIC) { if (offset && header) { print("emuNAND detected: redNAND"); *offset = location + 1; *header = location + 1; } return 0; } } uint32_t nand_size = getMMCDevice(0)->total_size; if (sdmmc_sdcard_readsectors(location + nand_size, 1, fcram_temp) == 0) { if (*(uint32_t *)(fcram_temp + 0x100) == NCSD_MAGIC) { if (offset && header) { print("emuNAND detected: Gateway"); *offset = location; *header = location + nand_size; } return 0; } } return 1; }
static inline int ReadNandSectors(u32 sector_no, u32 numsectors, u8 *out) { if (emunand_header) { if (sector_no == 0) { int errorcode = sdmmc_sdcard_readsectors(emunand_header, 1, out); if (errorcode) return errorcode; sector_no = 1; numsectors--; out += 0x200; } return sdmmc_sdcard_readsectors(sector_no + emunand_offset, numsectors, out); } else return sdmmc_nand_readsectors(sector_no, numsectors, out); }
int checkEmuNAND(){ sdmmc_sdcard_readsectors(0x3AF00000/0x200, 1, 0x20000000); if(*((char*)0x20000100) == 'N' && *((char*)0x20000101) == 'C' && *((char*)0x20000102) == 'S' && *((char*)0x20000103) == 'D'){ return 0x3AF00000; }else{ sdmmc_sdcard_readsectors(0x3BA00000/0x200, 1, 0x20000000); if(*((char*)0x20000100) == 'N' && *((char*)0x20000101) == 'C' && *((char*)0x20000102) == 'S' && *((char*)0x20000103) == 'D'){ return 0x3BA00000; }else{ return 0; } } }
void NandDumper(){ File myFile; int isEmuNand = SYS_NAND; if(checkEmuNAND() && (isEmuNand = NandSwitch()) == UNK_NAND) return; isEmuNand--; ConsoleInit(); ConsoleSetTitle(L"%sNAND Dumper", isEmuNand ? "emu" : "sys"); unsigned char* buf = (void*)0x21000000; unsigned int nsectors = 0x200; //sectors in a row wchar_t ProgressBar[] = L"⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜ "; unsigned int progress = 0; /* int BACKCOLOR = */ConsoleGetBackgroundColor(); //can be removed, left only to keep binaries the same if(FileOpen(&myFile, isEmuNand ? "rxTools/nand/EMUNAND.bin" : "rxTools/nand/NAND.bin", 1)){ print(L"Dumping...\n\n"); ConsoleShow(); int x, y; ConsoleGetXY(&x, &y); y += FONT_HEIGHT * 6; x += FONT_HWIDTH * 2; DrawString(BOT_SCREEN, ProgressBar, x, y, ConsoleGetTextColor(), ConsoleGetBackgroundColor()); DrawString(BOT_SCREEN, L"Press Ⓑ anytime to abort", x, y + FONT_HEIGHT*2, ConsoleGetTextColor(), ConsoleGetBackgroundColor()); for(int count = 0; count < NAND_SIZE/NAND_SECTOR_SIZE/nsectors; count++){ if(isEmuNand) sdmmc_sdcard_readsectors(count*nsectors, nsectors, buf); else sdmmc_nand_readsectors(count*nsectors, nsectors, buf); FileWrite(&myFile, buf, nsectors*NAND_SECTOR_SIZE, count*NAND_SECTOR_SIZE*nsectors); TryScreenShot(); if((count % (int)(NAND_SIZE/NAND_SECTOR_SIZE/nsectors/16)) == 0 && count != 0){ DrawString(BOT_SCREEN, PROGRESS_OK, x+(FONT_WIDTH*(progress++)), y, ConsoleGetTextColor(), ConsoleGetBackgroundColor()); } unsigned int pad = GetInput(); if(pad & BUTTON_B) break; } if(isEmuNand){ sdmmc_sdcard_readsectors(checkEmuNAND()/0x200, 1, buf); FileWrite(&myFile, buf, 0x200, 0); } FileClose(&myFile); print(L"\nFinished dumping!\n"); ConsoleShow(); }else{ print(L"Failed to create the dump.\n"); ConsoleShow(); } print(L"\nPress Ⓐ to exit\n"); ConsoleShow(); WaitForButton(BUTTON_A); }
int checkEmuNAND() { u8 *check = (u8 *)0x26000000; sdmmc_sdcard_readsectors(0x3AF00000 / 0x200, 1, check); if (*((char *)check + 0x100) == 'N' && *((char *)check + 0x101) == 'C' && *((char *)check + 0x102) == 'S' && *((char *)check + 0x103) == 'D') { return 0x3AF00000; } else { sdmmc_sdcard_readsectors(0x3BA00000 / 0x200, 1, check); if (*((char *)check + 0x100) == 'N' && *((char *)check + 0x101) == 'C' && *((char *)check + 0x102) == 'S' && *((char *)check + 0x103) == 'D') { return 0x3BA00000; } else { return 0; } } }
void emunand_readsectors(uint32_t sector_no, uint32_t numsectors, uint8_t *out, unsigned int partition) { PartitionInfo info; u8 myCtr[16]; for (int i = 0; i < 16; i++) { myCtr[i] = NANDCTR[i]; } info.ctr = myCtr; info.buffer = out; info.size = numsectors * 0x200; info.keyY = NULL; add_ctr(info.ctr, partition / 16); switch (partition) { case TWLN : info.keyslot = 0x3; break; case TWLP : info.keyslot = 0x3; break; case AGB_SAVE : info.keyslot = 0x7; break; case FIRM0 : info.keyslot = 0x6; break; case FIRM1 : info.keyslot = 0x6; break; case CTRNAND : info.keyslot = 0x4; break; } add_ctr(info.ctr, sector_no * 0x20); sdmmc_sdcard_readsectors(sector_no + partition / 0x200, numsectors, out); DecryptPartition(&info); }
unsigned int checkEmuNAND() { uint8_t *check = (uint8_t *)0x26000000; int isn3ds = 0; if (getMpInfo() == MPINFO_KTR)isn3ds = 1; sdmmc_sdcard_readsectors(isn3ds ? 0x4D800000 /0x200 : 0x3AF00000 / 0x200, 1, check); if (*((char *)check + 0x100) == 'N' && *((char *)check + 0x101) == 'C' && *((char *)check + 0x102) == 'S' && *((char *)check + 0x103) == 'D') { return isn3ds ? 0x4D800000 : 0x3AF00000; } else { sdmmc_sdcard_readsectors(isn3ds ? 0x76000000 /0x200 : 0x3BA00000 / 0x200, 1, check); if (*((char *)check + 0x100) == 'N' && *((char *)check + 0x101) == 'C' && *((char *)check + 0x102) == 'S' && *((char *)check + 0x103) == 'D') { return isn3ds ? 0x76000000 : 0x3BA00000; } else { return 0; } } }
void getEmunandSect(u32 *off, u32 *head){ u32 nandSize = getMMCDevice(0)->total_size; if (sdmmc_sdcard_readsectors(nandSize, 1, temp) == 0) { if (*(u32*)(temp + 0x100) == NCSD_MAGIC) { *off = 0; *head = nandSize; } } }
int movefirstdirentry() { if ((curdirsect!=lba_addr(curdir.DIR_FstClus))|(curdirsectorcluster!=0)) { if (sdmmc_sdcard_readsectors(lba_addr(curdir.DIR_FstClus),1,(void*)§)) return -1; curdirsect=lba_addr(curdir.DIR_FstClus); curdirsectorcluster=0; } direntrycount=0; return movenextdirentry(); }
void NandDumper(){ File myFile; int isEmuNand = checkEmuNAND() ? NandSwitch() : 0; if(isEmuNand == -1) return; ConsoleInit(); ConsoleAddText(isEmuNand ? "EmuNAND Dumper\n" : "NAND Dumper\n"); unsigned char* buf = 0x21000000; unsigned int nsectors = 0x200; //sectors in a row char ProgressBar[] = "[ ]"; unsigned int progress = 1; int BACKCOLOR = ConsoleGetBackgroundColor(); if(FileOpen(&myFile, isEmuNand ? "/nand/EMUNAND.bin" : "/nand/NAND.bin", 1)){ ConsoleAddText("Dumping...\n"); ConsoleShow(); int x, y; ConsoleGetXY(&x, &y); y += CHAR_WIDTH * 6; x += CHAR_WIDTH*2; DrawString(TOP_SCREEN, ProgressBar, x, y, ConsoleGetTextColor(), ConsoleGetBackgroundColor()); DrawString(TOP_SCREEN, "Press B anytime to abort", x, y + CHAR_WIDTH*2, ConsoleGetTextColor(), ConsoleGetBackgroundColor()); for(int count = 0; count < NAND_SIZE/NAND_SECTOR_SIZE/nsectors; count++){ if(isEmuNand) sdmmc_sdcard_readsectors(count*nsectors, nsectors, buf); else sdmmc_nand_readsectors(count*nsectors, nsectors, buf); FileWrite(&myFile, buf, nsectors*NAND_SECTOR_SIZE, count*NAND_SECTOR_SIZE*nsectors); TryScreenShot(); if((count % (int)(NAND_SIZE/NAND_SECTOR_SIZE/nsectors/25)) == 0 && count != 0){ DrawString(TOP_SCREEN, "-", x+(CHAR_WIDTH*(progress++)), y, ConsoleGetTextColor(), ConsoleGetBackgroundColor()); } unsigned int pad = GetInput(); if(pad & BUTTON_B) break; } if(isEmuNand){ sdmmc_sdcard_readsectors(checkEmuNAND()/0x200, 1, buf); FileWrite(&myFile, buf, 0x200, 0); } FileClose(&myFile); ConsoleAddText("\nFinished dumping!"); ConsoleShow(); }else{ ConsoleAddText("Failed to create the dump"); ConsoleShow(); } ConsoleAddText("\nPress A to exit"); ConsoleShow(); WaitForButton(BUTTON_A); }
int REDNAND(void){ u8 buf[0x200]; sdmmc_sdcard_readsectors(1, 1, buf); //"rednand" if (strncmp((char *)(buf+0x100), "NCSD", 4) == 0){ emunand_code[22] = 1; emunand_code[23] = 1; return 0; } mmcdevice *nand = getMMCDevice(0); sdmmc_sdcard_readsectors(nand->total_size, 1, buf); //"emunand" if (strncmp((char *)(buf+0x100), "NCSD", 4) == 0){ emunand_code[22] = 0; emunand_code[23] = nand->total_size; return 0; } return -1; }
int changedir(char* buf) { // Change current directory uint8_t i; if ((buf[0]==0)) return -1; if ((buf[0]=='\\')&&(buf[1]==0)) { if (sdmmc_sdcard_readsectors(lba_addr(fat.BPB_RootClus),1,(void*)§)) return FAT_ERR_SDREAD; curdirsect = lba_addr(fat.BPB_RootClus); curdirsectorcluster=0; curdir.DIR_Name[0]='\\'; curdir.DIR_Name[1]=0x20; curdir.DIR_Name[2]=0x20; curdir.DIR_Name[3]=0x20; curdir.DIR_Name[4]=0x20; curdir.DIR_Name[5]=0x20; curdir.DIR_Name[6]=0x20; curdir.DIR_Name[7]=0x20; curdir.DIR_Name[8]=0x20; curdir.DIR_Name[9]=0x20; curdir.DIR_Name[10]=0x20; curdir.DIR_Attr = 17; curdir.DIR_FstClus = fat.BPB_RootClus; curdir.DIR_FileSize = 0; direntrycount=0; return 0; } if ((buf[0]=='.')&&(buf[1]==0)) return (direntrycount=0); // note: ".." can be searched like any other dir if (movefirstdirentry()) return -1; while(cmpname(buf,curdirentry.DIR_Name)) if (movenextdirentry()) return -2; if (curdirentry.DIR_Attr & ATT_DIRECTORY) { if (sdmmc_sdcard_readsectors(lba_addr(curdirentry.DIR_FstClus),1,(void*)§)) return FAT_ERR_SDREAD; curdirsect = lba_addr(curdirentry.DIR_FstClus); curdirsectorcluster=0; for (i=0; i<11; i++) curdir.DIR_Name[i]=curdirentry.DIR_Name[i]; curdir.DIR_Attr = curdirentry.DIR_Attr; curdir.DIR_FstClus = curdirentry.DIR_FstClus; curdir.DIR_FileSize = curdirentry.DIR_FileSize;; return (direntrycount=0); } return -1; }
static int movedirnextsect() { uint32_t nextsect; if (++curdirsectorcluster == fat.BPB_SecPerClus) { nextsect = getnextsect(curdirsect); if (nextsect==0) return -1; curdirsect=nextsect; curdirsectorcluster=0; } if (sdmmc_sdcard_readsectors(curdirsect+curdirsectorcluster,1,(void*)§)) return -1; else return (direntrycount=0); }
int readf() { // Read the next cluster of a file uint32_t nextsect; if (endoffile()) return -1; filesectorcount++; if (++curfilesectorcluster == fat.BPB_SecPerClus) { if ((nextsect = getnextsect(curfilesect))==0) return -1; curfilesect=nextsect; curfilesectorcluster=0; } if (sdmmc_sdcard_readsectors(curfilesect+curfilesectorcluster,1,(void*)&filesect)) return -1; else return 0; }
DRESULT disk_read ( BYTE pdrv, /* Physical drive nmuber (0..) */ BYTE *buff, /* Data buffer to store read data */ DWORD sector, /* Sector address (LBA) */ UINT count /* Number of sectors to read (1..128) */ ) { if (sdmmc_sdcard_readsectors(sector,count,buff)) return RES_PARERR; return RES_OK; }
int openf(char* buf) { // Load first cluster of a file in buffer if (movefirstdirentry()) return -1; while(cmpname(buf,curdirentry.DIR_Name)) if (movenextdirentry()) return -2; if (!(curdirentry.DIR_Attr & ATT_DIRECTORY)) { if (sdmmc_sdcard_readsectors(lba_addr(curdirentry.DIR_FstClus),1,(void*)&filesect)) return FAT_ERR_SDREAD; curfilesect = lba_addr(curdirentry.DIR_FstClus); curfile.DIR_Attr = curdirentry.DIR_Attr; curfile.DIR_FstClus = curdirentry.DIR_FstClus; curfile.DIR_FileSize = curdirentry.DIR_FileSize;; return (filesectorcount=curfilesectorcluster=0); } return -1; }
void menu_emunand() { char emunands[MAX_OPTIONS][0x20]; // We have a max size for the strings... char unnamed[] = "emuNAND #"; uint32_t gap; if (getMMCDevice(0)->total_size > 0x200000) { gap = 0x400000; } else { gap = 0x200000; } // Scan for available emuNANDS. Assume they're placed right behind eachother. int count; for (count = 0; count <= MAX_OPTIONS; count++) { if (get_emunand_offsets(count * gap, NULL, NULL) == 0) { if (sdmmc_sdcard_readsectors(count * gap, 1, fcram_temp) == 0 && memcmp(fcram_temp + 11, "NAME", 4) == 0) { memcpy(emunands[count], fcram_temp + 15, 0x1F); emunands[count][0x1F] = 0; } else { memcpy(emunands[count], unnamed, sizeof(unnamed)); emunands[count][sizeof(unnamed) - 1] = '1' + count; emunands[count][sizeof(unnamed)] = 0; } continue; } break; } if (count <= 0) { print("Failed to find any emuNAND"); draw_message("Failed to find any emuNAND", "There's 3 possible causes for this error:\n" " - You don't even have an emuNAND installed\n" " - Your SD card can't be read\n" " - You're using an unsupported emuNAND format"); return; } // Make the pointer array char *options[count]; for (int x = 0; x <= count; x++) options[x] = emunands[x]; int result = draw_menu("Select emuNAND", 1, count, options); if (result == -1) return; config->emunand_location = result * gap; patches_modified = 1; }
u32 CheckEmuNand(void) { u8* buffer = BUFFER_ADDRESS; u32 nand_size_sectors = getMMCDevice(0)->total_size; // check the MBR for presence of EmuNAND sdmmc_sdcard_readsectors(0, 1, buffer); if (nand_size_sectors > getle32(buffer + 0x1BE + 0x8)) return EMUNAND_NOT_READY; // check for Gateway type EmuNAND sdmmc_sdcard_readsectors(nand_size_sectors, 1, buffer); if (memcmp(buffer + 0x100, "NCSD", 4) == 0) return EMUNAND_GATEWAY; // check for RedNAND type EmuNAND sdmmc_sdcard_readsectors(1, 1, buffer); if (memcmp(buffer + 0x100, "NCSD", 4) == 0) return EMUNAND_REDNAND; // EmuNAND ready but not set up return EMUNAND_READY; }
//--------------------------------------------------------------------------------- void sdmmcMsgHandler(int bytes, void *user_data) { //--------------------------------------------------------------------------------- FifoMessage msg; int retval; fifoGetDatamsg(FIFO_SDMMC, bytes, (u8*)&msg); switch (msg.type) { case SDMMC_SD_READ_SECTORS: sdmmc_sdcard_readsectors(msg.sdParams.startsector, msg.sdParams.numsectors, msg.sdParams.buffer); break; case SDMMC_SD_WRITE_SECTORS: sdmmc_sdcard_writesectors(msg.sdParams.startsector, msg.sdParams.numsectors, msg.sdParams.buffer); break; } }
int mount() { uint8_t i; uint32_t temp; int8_t partition; sdmmc_controller_init(); temp = sdmmc_sdcard_init() ; if (sdmmc_sdcard_readsectors(0,1,(void*)§)) return FAT_ERR_SDREAD; // Error reading MBR else { temp=sect[510] + (sect[511]<<8); if(temp!=0xAA55) return FAT_ERR_MBR; // Check failed else { partition=-1; for(i=0; i<4; i++) { // Max four partition to check switch (sect[450+i*16]) { // Partition type case 0x06: // FAT 16 CHS temp=sect[447+i*16]*63+sect[448+i*16]-1; if ((partition==-1) && temp) { partition=i; fat.LBA_Begin=temp; fat.FAT_RecordLen=16; } break; case 0x0B: // FAT 32 CHS temp=sect[447+i*16]*63+sect[448+i*16]-1; if ((partition==-1) && temp) { partition=i; fat.LBA_Begin=temp; fat.FAT_RecordLen=32; } break; case 0x0C: //FAT 32 LBA temp=sect[454+i*16]+(sect[455+i*16]<<8)+(sect[456+i*16]<<16)+(sect[457+i*16]<<24); if ((partition==-1) && temp) { partition=i; fat.LBA_Begin=temp; fat.FAT_RecordLen=32; } break; case 0x0E: // FAT 16 LBA temp=sect[454+i*16]+(sect[455+i*16]<<8)+(sect[456+i*16]<<16)+(sect[457+i*16]<<24); if ((partition==-1) && temp) { partition=i; fat.LBA_Begin=temp; fat.FAT_RecordLen=16; } break; default: break; } if (partition==-1) return FAT_ERR_PARTITION; // No valid partition found else { if (sdmmc_sdcard_readsectors(fat.LBA_Begin,1,(void*)§)) return FAT_ERR_SDREAD; // Error reading FAT ID else { temp=sect[510]+(sect[511]<<8); if(temp!=0xAA55) return FAT_ERR_FATID; // Check failed else { fat.BPB_BytsPerSec=sect[11]+(sect[12]<<8); fat.BPB_SecPerClus=sect[13]; fat.BPB_RsvdSecCnt=sect[14]+(sect[15]<<8); fat.BPB_NumFATs=sect[16]; fat.BPB_RootDirEnt=sect[17] + (sect[18]<<8); if (fat.FAT_RecordLen==16) { fat.BPB_RootDirEnt=sect[17] + (sect[18]<<8); fat.BPB_FATS=sect[22]+(sect[23]<<8); fat.BPB_RootClus=2; } else { fat.BPB_RootDirEnt=0; fat.BPB_FATS=sect[36]+(sect[37]<<8)+(sect[38]<<16)+(sect[39]<<24); fat.BPB_RootClus=sect[44]+(sect[45]<<8)+(sect[46]<<16)+(sect[47]<<24); } curfatsect=fat_begin_lba(fat); if (sdmmc_sdcard_readsectors(curfatsect,1,(void*)&fatsect)) return -1; rootdirsect = lba_addr(fat.BPB_RootClus); return changedir("\\"); } } } } } } }
void NandDumper(){ ConsoleSetTitle(strings[STR_DUMP], strings[STR_NAND]); File myFile; int isEmuNand = SYS_NAND; if(checkEmuNAND() && (isEmuNand = NandSwitch()) == UNK_NAND) return; isEmuNand--; ConsoleInit(); ConsoleSetTitle(strings[STR_DUMP], strings[STR_NAND]); unsigned char* buf = (void*)0x21000000; unsigned int nsectors = 0x200; //sectors in a row wchar_t tmpstr[STR_MAX_LEN]; wchar_t ProgressBar[41] = {0,}; for(int i=0; i<PROGRESS_WIDTH; i++) wcscat(ProgressBar, strings[STR_PROGRESS]); unsigned int progress = 0; wchar_t filename[_MAX_LFN]; swprintf(filename, _MAX_LFN, L"rxTools/nand/%sNAND.bin", isEmuNand ? L"EMU" : L""); if(FileOpen(&myFile, filename, 1)){ print(strings[STR_DUMPING], isEmuNand ? strings[STR_EMUNAND] : strings[STR_SYSNAND], filename); ConsoleShow(); int x, y; ConsoleGetXY(&x, &y); y += FONT_HEIGHT * 6; x += FONT_HWIDTH * 2; DrawString(BOT_SCREEN, ProgressBar, x, y, ConsoleGetTextColor(), ConsoleGetBackgroundColor()); swprintf(tmpstr, STR_MAX_LEN, strings[STR_PRESS_BUTTON_ACTION], strings[STR_BUTTON_B], strings[STR_CANCEL]); DrawString(BOT_SCREEN, tmpstr, x, y + FONT_HEIGHT*2, ConsoleGetTextColor(), ConsoleGetBackgroundColor()); for(int count = 0; count < getNandSize()/NAND_SECTOR_SIZE/nsectors; count++){ if(isEmuNand) sdmmc_sdcard_readsectors(count*nsectors, nsectors, buf); else sdmmc_nand_readsectors(count*nsectors, nsectors, buf); FileWrite(&myFile, buf, nsectors*NAND_SECTOR_SIZE, count*NAND_SECTOR_SIZE*nsectors); TryScreenShot(); if((count % (int)(getNandSize()/NAND_SECTOR_SIZE/nsectors/PROGRESS_WIDTH)) == 0 && count != 0){ DrawString(BOT_SCREEN, strings[STR_PROGRESS_OK], x+(FONT_WIDTH*(progress++)), y, ConsoleGetTextColor(), ConsoleGetBackgroundColor()); } unsigned int pad = GetInput(); if (pad & BUTTON_B) { FileClose(&myFile); goto end; } } if(isEmuNand){ sdmmc_sdcard_readsectors(checkEmuNAND()/0x200, 1, buf); FileWrite(&myFile, buf, 0x200, 0); } FileClose(&myFile); print(strings[STR_COMPLETED]); ConsoleShow(); }else{ print(strings[STR_FAILED]); ConsoleShow(); } end: print(strings[STR_PRESS_BUTTON_ACTION], strings[STR_BUTTON_A], strings[STR_CONTINUE]); ConsoleShow(); WaitForButton(BUTTON_A); }