diff --git a/source/fatfs/ffconf.h b/source/fatfs/ffconf.h index d4c0ea6..830daac 100644 --- a/source/fatfs/ffconf.h +++ b/source/fatfs/ffconf.h @@ -55,7 +55,7 @@ /* This option switches fast seek feature. (0:Disable or 1:Enable) */ -#define _USE_LABEL 0 +#define _USE_LABEL 1 /* This option switches volume label functions, f_getlabel() and f_setlabel(). / (0:Disable or 1:Enable) */ @@ -154,7 +154,7 @@ / the drive ID strings are: A-Z and 0-9. */ -#define _MULTI_PARTITION 0 +#define _MULTI_PARTITION 1 /* This option switches multi-partition feature. By default (0), each logical drive / number is bound to the same physical drive number and only an FAT volume found on / the physical drive will be mounted. When multi-partition feature is enabled (1), diff --git a/source/fs.c b/source/fs.c index ca7216e..15250e0 100644 --- a/source/fs.c +++ b/source/fs.c @@ -3,6 +3,7 @@ #include "virtual.h" #include "image.h" #include "sha.h" +#include "sdmmc.h" #include "ff.h" #define MAIN_BUFFER ((u8*)0x21200000) @@ -11,6 +12,12 @@ #define NORM_FS 10 #define VIRT_FS 4 +// Volume2Partition resolution table +PARTITION VolToPart[] = { + {0, 1}, {1, 0}, {2, 0}, {3, 0}, {4, 0}, + {5, 0}, {6, 0}, {7, 0}, {8, 0}, {9, 0} +}; + // don't use this area for anything else! static FATFS* fs = (FATFS*)0x20316000; @@ -78,6 +85,63 @@ bool IsMountedFS(const char* path) { return ((fsnum >= 0) && (fsnum < NORM_FS)) ? fs_mounted[fsnum] : false; } +uint64_t GetSDCardSize() { + if (sdmmc_sdcard_init() != 0) return 0; + return (u64) getMMCDevice(1)->total_size * 512; +} + +bool FormatSDCard(u32 hidden_mb) { + u8 mbr[0x200] = { 0 }; + u8 mbrdata[0x42] = { + 0x80, 0x01, 0x01, 0x00, 0x0C, 0xFE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x01, 0x01, 0x00, 0x1C, 0xFE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x55, 0xAA + }; + u32 sd_size = getMMCDevice(1)->total_size; + u32* fat_sector = (u32*) (mbrdata + 0x08); + u32* fat_size = (u32*) (mbrdata + 0x0C); + u32* emu_sector = (u32*) (mbrdata + 0x18); + u32* emu_size = (u32*) (mbrdata + 0x1C); + + *emu_sector = 1; + *emu_size = hidden_mb * (1024 * 1024) / 512; + *fat_sector = align(*emu_sector + *emu_size, 0x2000); // align to 4MB + if (sd_size < *fat_sector + 0x80000) { // minimum free space: 256MB + ShowPrompt(false, "ERROR: SD card is too small"); + return false; + } + *fat_size = sd_size - *fat_sector; + sd_size = *fat_size; + + // build the MBR + memcpy(mbr + 0x1BE, mbrdata, 0x42); + if (hidden_mb) memcpy(mbr, "GATEWAYNAND", 12); + else memset(mbr + 0x1CE, 0, 0x10); + + // one last warning.... + if (!ShowUnlockSequence(3, "!WARNING!\n \nProceeding will format this SD.\nThis will irreversibly delete\nALL data on it.\n")) + return false; + ShowString("Formatting SD, please wait...", hidden_mb); + + // write the MBR to disk + // !this assumes a fully deinitialized file system! + if ((sdmmc_sdcard_init() != 0) || (sdmmc_sdcard_writesectors(0, 1, mbr) != 0)) { + ShowPrompt(false, "ERROR: SD card i/o failure"); + return false; + } + + // format the SD card + // cluster size: auto (<= 4GB) / 32KiB (<= 8GB) / 64 KiB (> 8GB) + InitSDCardFS(); + UINT c_size = (sd_size < 0x800000) ? 0 : (sd_size < 0x1000000) ? 32768 : 65536; + bool ret = (f_mkfs("0:", 0, c_size) == FR_OK) && (f_setlabel("0:GM9SD") == FR_OK); + DeinitSDCardFS(); + + return ret; +} + bool CheckWritePermissions(const char* path) { char area_name[16]; int pdrv = PathToNumFS(path); diff --git a/source/fs.h b/source/fs.h index 18217ea..8dd26cc 100644 --- a/source/fs.h +++ b/source/fs.h @@ -39,6 +39,12 @@ bool InitExtFS(); void DeinitExtFS(); void DeinitSDCardFS(); +/** Return total size of SD card **/ +uint64_t GetSDCardSize(); + +/** Format the SD card **/ +bool FormatSDCard(u32 hidden_mb); + /** Check if writing to this path is allowed **/ bool CheckWritePermissions(const char* path); diff --git a/source/godmode.c b/source/godmode.c index 1ff8b58..d615cc5 100644 --- a/source/godmode.c +++ b/source/godmode.c @@ -7,7 +7,7 @@ #include "virtual.h" #include "image.h" -#define VERSION "0.5.8" +#define VERSION "0.5.9" #define N_PANES 2 #define IMG_DRV "789I" @@ -166,6 +166,36 @@ void DrawDirContents(DirStruct* contents, u32 cursor, u32* scroll) { } else DrawRectangle(BOT_SCREEN, SCREEN_WIDTH_BOT - bar_width, 0, bar_width, SCREEN_HEIGHT, COLOR_STD_BG); } +u32 SdFormatMenu(void) { + const u32 emunand_size_table[6] = { 0x0, 0x0, 0x3AF, 0x4D8, 0x400, 0x800 }; + const char* optionstr[6] = { "No EmuNAND", "O3DS NAND size", "N3DS NAND size", "1GB (legacy size)", "2GB (legacy size)", "User input..." }; + u64 sdcard_size_mb = 0; + u64 emunand_size_mb = (u64) -1; + + // check actual SD card size + sdcard_size_mb = GetSDCardSize() / 0x100000; + if (!sdcard_size_mb) { + ShowPrompt(false, "ERROR: SD card not detected."); + return 1; + } + + u32 user_select = ShowSelectPrompt(6, optionstr, "Format SD card (%lluGB)?\nChoose EmuNAND size:", sdcard_size_mb / 1024); + if (user_select && (user_select < 6)) { + emunand_size_mb = emunand_size_table[user_select]; + } else if (user_select == 6) do { + emunand_size_mb = ShowNumberPrompt(0, "SD card size is %lluMB.\nEnter EmuNAND size (MB) below:", sdcard_size_mb); + if (emunand_size_mb == (u64) -1) break; + } while (emunand_size_mb > sdcard_size_mb); + if (emunand_size_mb == (u64) -1) return 1; + + if (!FormatSDCard((u32) emunand_size_mb)) { + ShowPrompt(false, "Format SD: failed!"); + return 1; + } + + return 0; +} + u32 HexViewer(const char* path) { static const u32 max_data = (SCREEN_HEIGHT / 8) * 16; static u32 mode = 0; @@ -588,11 +618,17 @@ u32 GodMode() { DeinitSDCardFS(); clipboard->n_entries = 0; memset(panedata, 0x00, N_PANES * sizeof(PaneData)); - ShowPrompt(false, "SD card unmounted, you can eject now.\nPut it back in before you press ."); - while (!InitSDCardFS()) { - if (!ShowPrompt(true, "Reinitialising SD card failed! Retry?")) - return exit_mode; + ShowString("SD card unmounted, you can eject now.\n \n for format menu\n to remount SD card"); + while (true) { + u32 pad_choice = InputWait(); + if ((pad_choice & (BUTTON_R1|BUTTON_Y|BUTTON_LEFT)) == (BUTTON_R1|BUTTON_Y|BUTTON_LEFT)) + SdFormatMenu(); + else if (pad_choice & (BUTTON_B|BUTTON_START)) return exit_mode; + else if (!(pad_choice & BUTTON_A)) continue; + if (InitSDCardFS()) break; + ShowString("Reinitialising SD card failed!\n \n for format menu\n to retry, to reboot"); } + ClearScreenF(true, false, COLOR_STD_BG); InitEmuNandBase(); InitExtFS(); GetDirContents(current_dir, current_path); diff --git a/source/ui.c b/source/ui.c index 5a50582..7f4b21b 100644 --- a/source/ui.c +++ b/source/ui.c @@ -469,6 +469,23 @@ u64 ShowHexPrompt(u64 start_val, u32 n_digits, const char *format, ...) { return ret; } +u64 ShowNumberPrompt(u64 start_val, const char *format, ...) { + const char* alphabet = "0123456789"; + char inputstr[20 + 1] = { 0 }; + u64 ret = 0; + va_list va; + + snprintf(inputstr, 20 + 1, "%llu", start_val); + + va_start(va, format); + if (ShowInputPrompt(inputstr, 20 + 1, 1, alphabet, format, va)) { + sscanf(inputstr, "%llu", &ret); + } else ret = (u64) -1; + va_end(va); + + return ret; +} + bool ShowDataPrompt(u8* data, u32* size, const char *format, ...) { const char* alphabet = "0123456789ABCDEF"; char inputstr[128 + 1] = { 0 }; // maximum size of data: 64 byte diff --git a/source/ui.h b/source/ui.h index 21f2e2b..ca1dc97 100644 --- a/source/ui.h +++ b/source/ui.h @@ -73,5 +73,6 @@ bool ShowUnlockSequence(u32 seqlvl, const char *format, ...); u32 ShowSelectPrompt(u32 n, const char** options, const char *format, ...); bool ShowStringPrompt(char* inputstr, u32 max_size, const char *format, ...); u64 ShowHexPrompt(u64 start_val, u32 n_digits, const char *format, ...); +u64 ShowNumberPrompt(u64 start_val, const char *format, ...); bool ShowDataPrompt(u8* data, u32* size, const char *format, ...); bool ShowProgress(u64 current, u64 total, const char* opstr);