diff --git a/arm9/source/common/common.h b/arm9/source/common/common.h index e64e09f..19b682d 100644 --- a/arm9/source/common/common.h +++ b/arm9/source/common/common.h @@ -49,10 +49,6 @@ // used in several places #define STD_BUFFER_SIZE 0x100000 // must be a multiple of 0x200 -// buffer area defines (in use by vgame.c) -#define VGAME_BUFFER ((u8*)0x20000000) -#define VGAME_BUFFER_SIZE (0x200000) // 2MB, big RomFS - // buffer area defines (in use by image.c, for RAMdrive) #define RAMDRV_BUFFER ((u8*)0x22800000) // top of STACK #define RAMDRV_SIZE_O3DS (0x5800000) // 88MB diff --git a/arm9/source/system/memmap.h b/arm9/source/system/memmap.h index afbf0e9..0a74823 100644 --- a/arm9/source/system/memmap.h +++ b/arm9/source/system/memmap.h @@ -18,11 +18,11 @@ #define __RAMDRV_ADDR (__FCRAM0_ADDR + 0x2800000) #define __RAMDRV_END __FCRAM0_END // can be bigger on N3DS -#define __STACK_TOP __RAMDRV_ADDR -#define __STACK_SIZE 0x7F0000 +#define __STACK_ABT_TOP __RAMDRV_ADDR +#define __STACK_ABT_LEN 0x10000 -#define __STACKABT_TOP (__STACK_TOP - __STACK_SIZE) -#define __STACKABT_SIZE 0x10000 +#define __STACK_TOP (__STACK_ABT_TOP - __STACK_ABT_LEN) +#define __STACK_LEN 0x7F0000 -#define __HEAP_ADDR (__FCRAM0_ADDR + 0x0200000) -#define __HEAP_END (__STACKABT_TOP - __STACKABT_SIZE) +#define __HEAP_ADDR (__FCRAM0_ADDR) +#define __HEAP_END (__STACK_TOP - __STACK_LEN) diff --git a/arm9/source/virtual/vgame.c b/arm9/source/virtual/vgame.c index 765cc3f..2c7cad6 100644 --- a/arm9/source/virtual/vgame.c +++ b/arm9/source/virtual/vgame.c @@ -3,6 +3,8 @@ #include "game.h" #include "aes.h" +#define VGAME_BUFFER_SIZE 0x200000 // at least 2MB, multiple of 0x200 + #define VFLAG_NO_CRYPTO (1UL<<18) #define VFLAG_TAD (1UL<<19) #define VFLAG_CIA_CONTENT (1UL<<20) @@ -74,13 +76,15 @@ static u64 vgame_type = 0; static u32 base_vdir = 0; -static VirtualFile* templates_cia = (VirtualFile*) VGAME_BUFFER; // first 56kb reserved (enough for 1024 entries) -static VirtualFile* templates_tad = (VirtualFile*) (VGAME_BUFFER + 0xDC00); // 1kb reserved (enough for 18 entries) -static VirtualFile* templates_firm = (VirtualFile*) (VGAME_BUFFER + 0xE000); // 2kb reserved (enough for 36 entries) -static VirtualFile* templates_ncsd = (VirtualFile*) (VGAME_BUFFER + 0xE800); // 2kb reserved (enough for 36 entries) -static VirtualFile* templates_ncch = (VirtualFile*) (VGAME_BUFFER + 0xF000); // 1kb reserved (enough for 18 entries) -static VirtualFile* templates_nds = (VirtualFile*) (VGAME_BUFFER + 0xF400); // 1kb reserved (enough for 18 entries) -static VirtualFile* templates_exefs = (VirtualFile*) (VGAME_BUFFER + 0xF800); // 2kb reserved (enough for 36 entries) +static void* vgame_buffer = NULL; + +static VirtualFile* templates_cia = NULL; +static VirtualFile* templates_tad = NULL; +static VirtualFile* templates_firm = NULL; +static VirtualFile* templates_ncsd = NULL; +static VirtualFile* templates_ncch = NULL; +static VirtualFile* templates_nds = NULL; +static VirtualFile* templates_exefs = NULL; static int n_templates_cia = -1; static int n_templates_tad = -1; static int n_templates_firm = -1; @@ -104,15 +108,15 @@ static u64 offset_ccnt = (u64) -1; static u64 offset_tad = (u64) -1; static u32 index_ccnt = (u32) -1; -static CiaStub* cia = (CiaStub*) (void*) (VGAME_BUFFER + 0x10000); // 61kB reserved - should be enough by far -static TwlHeader* twl = (TwlHeader*) (void*) (VGAME_BUFFER + 0x1F400); // 512 byte reserved (not the full thing) -static FirmA9LHeader* a9l = (FirmA9LHeader*) (void*) (VGAME_BUFFER + 0x1F600); // 512 byte reserved -static FirmHeader* firm = (FirmHeader*) (void*) (VGAME_BUFFER + 0x1F800); // 512 byte reserved -static NcsdHeader* ncsd = (NcsdHeader*) (void*) (VGAME_BUFFER + 0x1FA00); // 512 byte reserved -static NcchHeader* ncch = (NcchHeader*) (void*) (VGAME_BUFFER + 0x1FC00); // 512 byte reserved -static ExeFsHeader* exefs = (ExeFsHeader*) (void*) (VGAME_BUFFER + 0x1FE00); // 512 byte reserved -static u8* romfslv3 = (u8*) (VGAME_BUFFER + 0x20000); // 1920kB reserved -static u8* nitrofs = (u8*) (VGAME_BUFFER + 0x20000); // 1920kB reserved (FNT+FAT combined) +static CiaStub* cia = NULL; +static TwlHeader* twl = NULL; +static FirmA9LHeader* a9l = NULL; +static FirmHeader* firm = NULL; +static NcsdHeader* ncsd = NULL; +static NcchHeader* ncch = NULL; +static ExeFsHeader* exefs = NULL; +static u8* romfslv3 = NULL; +static u8* nitrofs = NULL; static RomFsLv3Index lv3idx; static u8 cia_titlekey[16]; @@ -726,10 +730,17 @@ bool BuildVGameTadDir(void) { return true; } +void DeinitVGameDrive(void) { + if (vgame_buffer) free(vgame_buffer); + vgame_buffer = NULL; +} + u64 InitVGameDrive(void) { // prerequisite: game file mounted as image u64 type = GetMountState(); vgame_type = 0; + DeinitVGameDrive(); + offset_firm = (u64) -1; offset_a9bin = (u64) -1; offset_cia = (u64) -1; @@ -754,12 +765,33 @@ u64 InitVGameDrive(void) { // prerequisite: game file mounted as image (type & GAME_TAD ) ? VFLAG_TAD : 0; if (!base_vdir) return 0; + // set up vgame buffer + vgame_buffer = (void*) malloc(VGAME_BUFFER_SIZE); + if (!vgame_buffer) return 0; + + templates_cia = (VirtualFile*) ((u8*) vgame_buffer); // first 56kb reserved (enough for 1024 entries) + templates_firm = (VirtualFile*) (((u8*) vgame_buffer) + 0xE000); // 2kb reserved (enough for 36 entries) + templates_ncsd = (VirtualFile*) (((u8*) vgame_buffer) + 0xE800); // 2kb reserved (enough for 36 entries) + templates_ncch = (VirtualFile*) (((u8*) vgame_buffer) + 0xF000); // 1kb reserved (enough for 18 entries) + templates_nds = (VirtualFile*) (((u8*) vgame_buffer) + 0xF400); // 1kb reserved (enough for 18 entries) + templates_exefs = (VirtualFile*) (((u8*) vgame_buffer) + 0xF800); // 1kb reserved (enough for 18 entries) + templates_tad = (VirtualFile*) (((u8*) vgame_buffer) + 0xFC00); // 1kb reserved (enough for 18 entries) + cia = (CiaStub*) (void*) (((u8*) vgame_buffer) + 0x10000); // 61kB reserved - should be enough by far + twl = (TwlHeader*) (void*) (((u8*) vgame_buffer) + 0x1F400); // 512 byte reserved (not the full thing) + a9l = (FirmA9LHeader*) (void*) (((u8*) vgame_buffer) + 0x1F600); // 512 byte reserved + firm = (FirmHeader*) (void*) (((u8*) vgame_buffer) + 0x1F800); // 512 byte reserved + ncsd = (NcsdHeader*) (void*) (((u8*) vgame_buffer) + 0x1FA00); // 512 byte reserved + ncch = (NcchHeader*) (void*) (((u8*) vgame_buffer) + 0x1FC00); // 512 byte reserved + exefs = (ExeFsHeader*) (void*) (((u8*) vgame_buffer) + 0x1FE00); // 512 byte reserved + romfslv3 = (((u8*) vgame_buffer) + 0x20000); // 1920kB reserved + nitrofs = (((u8*) vgame_buffer) + 0x20000); // 1920kB reserved (FNT+FAT combined) + vgame_type = type; return type; } u64 CheckVGameDrive(void) { - if (vgame_type != GetMountState()) vgame_type = 0; // very basic sanity check + if (!vgame_buffer || (vgame_type != GetMountState())) vgame_type = 0; // very basic sanity check return vgame_type; } diff --git a/arm9/source/virtual/vgame.h b/arm9/source/virtual/vgame.h index c6fb5b8..7c9ed6b 100644 --- a/arm9/source/virtual/vgame.h +++ b/arm9/source/virtual/vgame.h @@ -4,6 +4,7 @@ #include "filetype.h" #include "virtual.h" +void DeinitVGameDrive(void); u64 InitVGameDrive(void); u64 CheckVGameDrive(void); diff --git a/arm9/source/virtual/virtual.c b/arm9/source/virtual/virtual.c index 3061d2b..d0fb7f8 100644 --- a/arm9/source/virtual/virtual.c +++ b/arm9/source/virtual/virtual.c @@ -25,6 +25,9 @@ u32 GetVirtualSource(const char* path) { } bool InitVirtualImageDrive(void) { + DeinitVGameDrive(); + DeinitVTickDbDrive(); + DeinitVKeyDbDrive(); return InitVGameDrive() || InitVTickDbDrive() || InitVKeyDbDrive(); } diff --git a/arm9/source/virtual/vkeydb.c b/arm9/source/virtual/vkeydb.c index 1ed8cbe..46efe3f 100644 --- a/arm9/source/virtual/vkeydb.c +++ b/arm9/source/virtual/vkeydb.c @@ -2,22 +2,36 @@ #include "image.h" #include "keydb.h" +#define VKEYDB_BUFFER_SIZE STD_BUFFER_SIZE // 1MB, enough for 32768 entries + #define NAME_LEGKEY "slot0x%02lXKey%.10s%s.bin" // keyslot / type string / unit extension -static AesKeyInfo* key_info = (AesKeyInfo*) VGAME_BUFFER; // full 1MB reserved (enough for 32768 entries) +static AesKeyInfo* key_info = NULL; static u32 n_keys = 0; -u32 InitVKeyDbDrive(void) { // prerequisite: aeskeydb.bin mounted as image +void DeinitVKeyDbDrive(void) { + if (key_info) free(key_info); + key_info = NULL; +} + +u64 InitVKeyDbDrive(void) { // prerequisite: aeskeydb.bin mounted as image if (!(GetMountState() & BIN_KEYDB)) return 0; + n_keys = 0; // sanity check u64 fsize = GetMountSize(); - if (!fsize || (fsize % sizeof(AesKeyInfo)) || (fsize > VGAME_BUFFER_SIZE)) { + if (!fsize || (fsize % sizeof(AesKeyInfo)) || (fsize > VKEYDB_BUFFER_SIZE)) { n_keys = 0; return 0; - } else n_keys = fsize / sizeof(AesKeyInfo); + } + + // setup vkeydb buffer + DeinitVKeyDbDrive(); // dangerous shit + key_info = (AesKeyInfo*) malloc(VKEYDB_BUFFER_SIZE); + if (!key_info) return 0; // load the full database into memory + n_keys = fsize / sizeof(AesKeyInfo); if (ReadImageBytes((u8*) key_info, 0, fsize) != 0) n_keys = 0; // decrypt keys if required @@ -25,11 +39,12 @@ u32 InitVKeyDbDrive(void) { // prerequisite: aeskeydb.bin mounted as image if (key_info[i].isEncrypted) CryptAesKeyInfo(&(key_info[i])); } + if (!n_keys) DeinitVKeyDbDrive(); return (n_keys) ? BIN_KEYDB : 0; } -u32 CheckVKeyDbDrive(void) { - if ((GetMountState() & BIN_KEYDB) && n_keys) // very basic sanity check +u64 CheckVKeyDbDrive(void) { + if ((GetMountState() & BIN_KEYDB) && key_info) // very basic sanity check return BIN_KEYDB; return 0; } diff --git a/arm9/source/virtual/vkeydb.h b/arm9/source/virtual/vkeydb.h index c0a67bc..2207d22 100644 --- a/arm9/source/virtual/vkeydb.h +++ b/arm9/source/virtual/vkeydb.h @@ -3,8 +3,9 @@ #include "common.h" #include "virtual.h" -u32 InitVKeyDbDrive(void); -u32 CheckVKeyDbDrive(void); +void DeinitVKeyDbDrive(void); +u64 InitVKeyDbDrive(void); +u64 CheckVKeyDbDrive(void); bool ReadVKeyDbDir(VirtualFile* vfile, VirtualDir* vdir); int ReadVKeyDbFile(const VirtualFile* vfile, void* buffer, u64 offset, u64 count); diff --git a/arm9/source/virtual/vtickdb.c b/arm9/source/virtual/vtickdb.c index 9804045..4443975 100644 --- a/arm9/source/virtual/vtickdb.c +++ b/arm9/source/virtual/vtickdb.c @@ -2,6 +2,8 @@ #include "image.h" #include "ticket.h" +#define VTICKDB_BUFFER_SIZE 0x100000 // 1MB, enough for ~20000 entries + #define VFLAG_UNKNOWN (1UL<<29) #define VFLAG_ESHOP (1UL<<30) #define VFLAG_SYSTEM (1UL<<31) @@ -22,7 +24,7 @@ typedef struct { typedef struct { u32 n_entries; u8 reserved[12]; - TickDbEntry entries[256]; // this number is only a placeholder + TickDbEntry entries[256]; // this number is only a placeholder (dangerous?) } __attribute__((packed)) TickDbInfo; // only for the main directory @@ -32,7 +34,7 @@ static const VirtualFile vTickDbFileTemplates[] = { { "unknown" , 0x00000000, 0x00000000, 0xFF, VFLAG_DIR | VFLAG_UNKNOWN } }; -static TickDbInfo* tick_info = (TickDbInfo*) VGAME_BUFFER; // full 1MB reserved (enough for ~20000 entries) +static TickDbInfo* tick_info = NULL; u32 AddTickDbInfo(TickDbInfo* info, Ticket* ticket, u32 offset) { if (ValidateTicket(ticket) != 0) return 1; @@ -62,16 +64,28 @@ u32 AddTickDbInfo(TickDbInfo* info, Ticket* ticket, u32 offset) { return 0; } -u32 InitVTickDbDrive(void) { // prerequisite: ticket.db mounted as image +void DeinitVTickDbDrive(void) { + if (tick_info) free(tick_info); + tick_info = NULL; +} + +u64 InitVTickDbDrive(void) { // prerequisite: ticket.db mounted as image const u32 area_offsets[] = { TICKDB_AREA_OFFSETS }; if (!(GetMountState() & SYS_TICKDB)) return 0; - // reset internal db + // set up drive buffer / internal db + DeinitVTickDbDrive(); + tick_info = (TickDbInfo*) malloc(VTICKDB_BUFFER_SIZE); + if (!tick_info) return 0; memset(tick_info, 0, 16); + // set up buffer u8* buffer = (u8*) malloc(STD_BUFFER_SIZE); - if (!buffer) return 0; + if (!buffer) { + DeinitVTickDbDrive(); + return 0; + } // parse file, sector by sector for (u32 p = 0; p < sizeof(area_offsets) / sizeof(u32); p++) { @@ -80,11 +94,10 @@ u32 InitVTickDbDrive(void) { // prerequisite: ticket.db mounted as image u32 read_bytes = min(STD_BUFFER_SIZE, TICKDB_AREA_SIZE - i); u8* data = buffer; if (ReadImageBytes(data, offset_area + i, read_bytes) != 0) { - tick_info->n_entries = 0; + DeinitVTickDbDrive(); free(buffer); return 0; } - // likely bug here (!!!) (not a new one) for (; data + TICKET_SIZE < buffer + read_bytes; data += 0x200) { Ticket* ticket = TicketFromTickDbChunk(data, NULL, true); if (!ticket) continue; @@ -94,11 +107,12 @@ u32 InitVTickDbDrive(void) { // prerequisite: ticket.db mounted as image } free(buffer); + if (!tick_info->n_entries) DeinitVTickDbDrive(); return (tick_info->n_entries) ? SYS_TICKDB : 0; } -u32 CheckVTickDbDrive(void) { - if ((GetMountState() & SYS_TICKDB) && tick_info->n_entries) // very basic sanity check +u64 CheckVTickDbDrive(void) { + if ((GetMountState() & SYS_TICKDB) && tick_info) // very basic sanity check return SYS_TICKDB; return 0; } diff --git a/arm9/source/virtual/vtickdb.h b/arm9/source/virtual/vtickdb.h index f61a2ee..4c841df 100644 --- a/arm9/source/virtual/vtickdb.h +++ b/arm9/source/virtual/vtickdb.h @@ -3,8 +3,9 @@ #include "common.h" #include "virtual.h" -u32 InitVTickDbDrive(void); -u32 CheckVTickDbDrive(void); +void DeinitVTickDbDrive(void); +u64 InitVTickDbDrive(void); +u64 CheckVTickDbDrive(void); bool ReadVTickDbDir(VirtualFile* vfile, VirtualDir* vdir); int ReadVTickDbFile(const VirtualFile* vfile, void* buffer, u64 offset, u64 count);