diff --git a/Makefile b/Makefile index 7af4adb..0ab7aa7 100644 --- a/Makefile +++ b/Makefile @@ -31,20 +31,31 @@ INCLUDES := source #--------------------------------------------------------------------------------- ARCH := -march=armv5te -mtune=arm946e-s -mthumb -mthumb-interwork -CFLAGS := -g -Wall -O2\ +CFLAGS := -g -Wall -Wextra -Wpedantic -O2 -flto\ -fomit-frame-pointer\ - -ffast-math -std=c99\ + -ffast-math -std=c11\ $(ARCH) -CFLAGS += $(INCLUDE) -DARM9 -Werror-implicit-function-declaration +CFLAGS += $(INCLUDE) -DARM9 -Werror-implicit-function-declaration -Wcast-align \ + -Wcast-qual -Wdisabled-optimization -Wformat=2 -Winit-self \ + -Wlogical-op -Wmissing-declarations -Wmissing-include-dirs \ + -Wredundant-decls -Wshadow -Wsign-conversion -Wstrict-overflow=5 \ + -Wswitch-default -Wundef -Wno-unused CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions ASFLAGS := -g $(ARCH) LDFLAGS = -nostartfiles -g --specs=../stub.specs $(ARCH) -Wl,-Map,$(TARGET).map +OCFLAGS = --set-section-flags .bss=alloc,load,contents LIBS := +ifeq ($(EXEC_METHOD),BRAHMA) + CFLAGS += -DBRAHMA #can't use CPPFLAGS because 3ds_rules doesn't use them +else ifeq ($(EXEC_METHOD), A9LH) + CFLAGS += -DA9LH #can't use CPPFLAGS because 3ds_rules doesn't use them +endif + #--------------------------------------------------------------------------------- # list of directories containing libraries, this must be the top level containing # include and lib @@ -93,20 +104,33 @@ export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) -.PHONY: $(BUILD) clean all +.PHONY: common clean all brahma a9lh release #--------------------------------------------------------------------------------- -all: $(BUILD) +all: release -$(BUILD): - @[ -d $@ ] || mkdir -p $@ - @make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile - cp $(OUTPUT).bin arm9payload.bin +common: + @[ -d $(BUILD) ] || mkdir -p $(BUILD) + +a9lh: common + @make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile EXEC_METHOD=A9LH + @mv $(OUTPUT).bin uncart_arm9loaderhax.bin + +brahma: common + @make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile EXEC_METHOD=BRAHMA + @mv $(OUTPUT).bin uncart_brahma.bin + +release: + @rm -fr $(BUILD) $(OUTPUT).bin $(OUTPUT).elf + @make --no-print-directory a9lh + @rm -fr $(BUILD) $(OUTPUT).bin $(OUTPUT).elf + @make --no-print-directory brahma #--------------------------------------------------------------------------------- clean: @echo clean ... - @rm -fr $(BUILD) $(OUTPUT).elf $(OUTPUT).bin arm9payload.bin + @rm -fr $(BUILD) $(OUTPUT).elf $(OUTPUT).bin uncart_arm9loaderhax.bin \ + uncart_brahma.bin #--------------------------------------------------------------------------------- @@ -123,7 +147,7 @@ $(OUTPUT).elf : $(OFILES) #--------------------------------------------------------------------------------- %.bin: %.elf - @$(OBJCOPY) -O binary $< $@ + @$(OBJCOPY) $(OCFLAGS) -O binary $< $@ @echo built ... $(notdir $@) diff --git a/source/aes.h b/source/aes.h index 5192127..1c951e7 100644 --- a/source/aes.h +++ b/source/aes.h @@ -1,54 +1,54 @@ -// Copyright 2014 Normmatt -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include "common.h" - -#define REG_AESCNT (*(vu32*)0x10009000) -#define REG_AESBLKCNT (*(vu32*)0x10009004) -#define REG_AESBLKCNTH1 (*(vu16*)0x10009004) -#define REG_AESBLKCNTH2 (*(vu16*)0x10009006) -#define REG_AESWRFIFO (*(vu32*)0x10009008) -#define REG_AESRDFIFO (*(vu32*)0x1000900C) -#define REG_AESKEYSEL (*(vu8*)0x10009010) -#define REG_AESKEYCNT (*(vu8*)0x10009011) -#define REG_AESCTR ((vu32*)0x10009020) // 16 -#define REG_AESMAC ((vu32*)0x10009030) // 16 -#define REG_AESKEY0 ((vu32*)0x10009040) // 48 -#define REG_AESKEY1 ((vu32*)0x10009070) // 48 -#define REG_AESKEY2 ((vu32*)0x100090A0) // 48 -#define REG_AESKEY3 ((vu32*)0x100090D0) // 48 -#define REG_AESKEYFIFO (*(vu32*)0x10009100) -#define REG_AESKEYXFIFO (*(vu32*)0x10009104) -#define REG_AESKEYYFIFO (*(vu32*)0x10009108) - -#define AES_WRITE_FIFO_COUNT ((REG_AESCNT>>0) & 0x1F) -#define AES_READ_FIFO_COUNT ((REG_AESCNT>>5) & 0x1F) -#define AES_BUSY (1<<31) - -#define AES_FLUSH_READ_FIFO (1<<10) -#define AES_FLUSH_WRITE_FIFO (1<<11) -#define AES_BIT12 (1<<12) -#define AES_BIT13 (1<<13) -#define AES_MAC_SIZE(n) ((n&7)<<16) -#define AES_MAC_REGISTER_SOURCE (1<<20) -#define AES_UNKNOWN_21 (1<<21) -#define AES_OUTPUT_BIG_ENDIAN (1<<22) -#define AES_INPUT_BIG_ENDIAN (1<<23) -#define AES_OUTPUT_NORMAL_ORDER (1<<24) -#define AES_INPUT_NORMAL_ORDER (1<<25) -#define AES_UNKNOWN_26 (1<<26) -#define AES_MODE(n) ((n&7)<<27) -#define AES_INTERRUPT_ENABLE (1<<30) -#define AES_ENABLE (1<<31) - -#define AES_MODE_CCM_DECRYPT 0 -#define AES_MODE_CCM_ENCRYPT 1 -#define AES_MODE_CTR 2 -#define AES_MODE_UNK3 3 -#define AES_MODE_CBC_DECRYPT 4 -#define AES_MODE_CBC_ENCRYPT 5 -#define AES_MODE_UNK6 6 -#define AES_MODE_UNK7 7 +// Copyright 2014 Normmatt +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "common.h" + +#define REG_AESCNT (*(vu32*)0x10009000) +#define REG_AESBLKCNT (*(vu32*)0x10009004) +#define REG_AESBLKCNTH1 (*(vu16*)0x10009004) +#define REG_AESBLKCNTH2 (*(vu16*)0x10009006) +#define REG_AESWRFIFO (*(vu32*)0x10009008) +#define REG_AESRDFIFO (*(vu32*)0x1000900C) +#define REG_AESKEYSEL (*(vu8*)0x10009010) +#define REG_AESKEYCNT (*(vu8*)0x10009011) +#define REG_AESCTR ((vu32*)0x10009020) // 16 +#define REG_AESMAC ((vu32*)0x10009030) // 16 +#define REG_AESKEY0 ((vu32*)0x10009040) // 48 +#define REG_AESKEY1 ((vu32*)0x10009070) // 48 +#define REG_AESKEY2 ((vu32*)0x100090A0) // 48 +#define REG_AESKEY3 ((vu32*)0x100090D0) // 48 +#define REG_AESKEYFIFO (*(vu32*)0x10009100) +#define REG_AESKEYXFIFO (*(vu32*)0x10009104) +#define REG_AESKEYYFIFO (*(vu32*)0x10009108) + +#define AES_WRITE_FIFO_COUNT ((REG_AESCNT>>0) & 0x1F) +#define AES_READ_FIFO_COUNT ((REG_AESCNT>>5) & 0x1F) +#define AES_BUSY (1u<<31) + +#define AES_FLUSH_READ_FIFO (1u<<10) +#define AES_FLUSH_WRITE_FIFO (1u<<11) +#define AES_BIT12 (1u<<12) +#define AES_BIT13 (1u<<13) +#define AES_MAC_SIZE(n) ((n&7u)<<16) +#define AES_MAC_REGISTER_SOURCE (1u<<20) +#define AES_UNKNOWN_21 (1u<<21) +#define AES_OUTPUT_BIG_ENDIAN (1u<<22) +#define AES_INPUT_BIG_ENDIAN (1u<<23) +#define AES_OUTPUT_NORMAL_ORDER (1u<<24) +#define AES_INPUT_NORMAL_ORDER (1u<<25) +#define AES_UNKNOWN_26 (1u<<26) +#define AES_MODE(n) ((n&7u)<<27) +#define AES_INTERRUPT_ENABLE (1u<<30) +#define AES_ENABLE (1u<<31) + +#define AES_MODE_CCM_DECRYPT 0u +#define AES_MODE_CCM_ENCRYPT 1u +#define AES_MODE_CTR 2u +#define AES_MODE_UNK3 3u +#define AES_MODE_CBC_DECRYPT 4u +#define AES_MODE_CBC_ENCRYPT 5u +#define AES_MODE_UNK6 6u +#define AES_MODE_UNK7 7u diff --git a/source/draw.c b/source/draw.c index 1e82cac..d4f397d 100644 --- a/source/draw.c +++ b/source/draw.c @@ -10,7 +10,29 @@ #include "font.h" #include "draw.h" -int current_y = 0; +u8 *TOP_SCREEN0; +u8 *TOP_SCREEN1; +u8 *BOT_SCREEN0; +u8 *BOT_SCREEN1; + +size_t current_y = 0; + +void DrawInit(void) +{ +#ifdef BRAHMA + TOP_SCREEN0 = (u8*)(0x20000000); + TOP_SCREEN1 = (u8*)(0x20046500); + BOT_SCREEN0 = (u8*)(0x2008CA00); + BOT_SCREEN1 = (u8*)(0x200C4E00); +#elif A9LH + TOP_SCREEN0 = (u8*)(*(u32*)0x23FFFE00); + TOP_SCREEN1 = (u8*)(*(u32*)0x23FFFE00); + BOT_SCREEN0 = (u8*)(*(u32*)0x23FFFE08); + BOT_SCREEN1 = (u8*)(*(u32*)0x23FFFE08); +#else + #error "BRAHMA or A9LH must be defined!" +#endif +} void ClearScreen(unsigned char *screen, int color) { @@ -23,16 +45,15 @@ void ClearScreen(unsigned char *screen, int color) } } -void DrawCharacter(unsigned char *screen, int character, int x, int y, int color, int bgcolor) +void DrawCharacter(unsigned char *screen, int character, size_t x, size_t y, int color, int bgcolor) { - int yy, xx; - for (yy = 0; yy < 8; yy++) { - int xDisplacement = (x * BYTES_PER_PIXEL * SCREEN_WIDTH); - int yDisplacement = ((SCREEN_WIDTH - (y + yy) - 1) * BYTES_PER_PIXEL); - unsigned char *screenPos = screen + xDisplacement + yDisplacement; + for (size_t yy = 0; yy < 8; yy++) { + size_t xDisplacement = (x * BYTES_PER_PIXEL * SCREEN_WIDTH); + size_t yDisplacement = ((SCREEN_WIDTH - (y + yy) - 1) * BYTES_PER_PIXEL); - unsigned char charPos = font[character * 8 + yy]; - for (xx = 7; xx >= 0; xx--) { + unsigned char *screenPos = screen + xDisplacement + yDisplacement; + unsigned char charPos = font[(size_t)character * 8 + yy]; + for (int xx = 7; xx >= 0; xx--) { if ((charPos >> xx) & 1) { *(screenPos + 0) = color >> 16; // B *(screenPos + 1) = color >> 8; // G @@ -47,7 +68,7 @@ void DrawCharacter(unsigned char *screen, int character, int x, int y, int color } } -void DrawString(unsigned char *screen, const char *str, int x, int y, int color, int bgcolor) +void DrawString(unsigned char *screen, const char *str, size_t x, size_t y, int color, int bgcolor) { const size_t string_len = strlen(str); @@ -55,7 +76,7 @@ void DrawString(unsigned char *screen, const char *str, int x, int y, int color, DrawCharacter(screen, str[i], x + i * 8, y, color, bgcolor); } -void DrawStringF(int x, int y, const char *format, ...) +void DrawStringF(size_t x, size_t y, const char *format, ...) { char str[256]; va_list va; @@ -70,8 +91,8 @@ void DrawStringF(int x, int y, const char *format, ...) void Debug(const char *format, ...) { - char str[50]; - const char* spaces = " X"; + char str[51]; + const char* spaces = " X"; va_list va; va_start(va, format); @@ -79,10 +100,10 @@ void Debug(const char *format, ...) va_end(va); snprintf(str, sizeof(str), "%s%s", str, spaces); - DrawString(TOP_SCREEN0, str, 10, current_y, RGB(255, 0, 0), RGB(255, 255, 255)); - DrawString(TOP_SCREEN0, spaces, 10, current_y + 10, RGB(255, 0, 0), RGB(255, 255, 255)); - DrawString(TOP_SCREEN1, str, 10, current_y, RGB(255, 0, 0), RGB(255, 255, 255)); - DrawString(TOP_SCREEN1, spaces, 10, current_y + 10, RGB(255, 0, 0), RGB(255, 255, 255)); + DrawString(TOP_SCREEN0, str, 0u, current_y, RGB(255, 0, 0), RGB(255, 255, 255)); + DrawString(TOP_SCREEN0, spaces, 0u, current_y + 10, RGB(255, 0, 0), RGB(255, 255, 255)); + DrawString(TOP_SCREEN1, str, 0u, current_y, RGB(255, 0, 0), RGB(255, 255, 255)); + DrawString(TOP_SCREEN1, spaces, 0u, current_y + 10, RGB(255, 0, 0), RGB(255, 255, 255)); current_y += 10; if (current_y >= 240) { diff --git a/source/draw.h b/source/draw.h index 5f55ea0..d8a4013 100644 --- a/source/draw.h +++ b/source/draw.h @@ -14,17 +14,19 @@ #define RGB(r,g,b) (r<<24|b<<16|g<<8|r) -#define TOP_SCREEN0 (u8*)(0x20000000) -#define TOP_SCREEN1 (u8*)(0x20046500) -#define BOT_SCREEN0 (u8*)(0x2008CA00) -#define BOT_SCREEN1 (u8*)(0x200C4E00) -extern int current_y; +extern u8 *TOP_SCREEN0; +extern u8 *TOP_SCREEN1; +extern u8 *BOT_SCREEN0; +extern u8 *BOT_SCREEN1; +extern size_t current_y; + +void DrawInit(void); void ClearScreen(unsigned char *screen, int color); -void DrawCharacter(unsigned char *screen, int character, int x, int y, int color, int bgcolor); -void DrawHex(unsigned char *screen, unsigned int hex, int x, int y, int color, int bgcolor); -void DrawString(unsigned char *screen, const char *str, int x, int y, int color, int bgcolor); -void DrawStringF(int x, int y, const char *format, ...); -void DrawHexWithName(unsigned char *screen, const char *str, unsigned int hex, int x, int y, int color, int bgcolor); +void DrawCharacter(unsigned char *screen, int character, size_t x, size_t y, int color, int bgcolor); +void DrawHex(unsigned char *screen, unsigned int hex, size_t x, size_t y, int color, int bgcolor); +void DrawString(unsigned char *screen, const char *str, size_t x, size_t y, int color, int bgcolor); +void DrawStringF(size_t x, size_t y, const char *format, ...); +void DrawHexWithName(unsigned char *screen, const char *str, unsigned int hex, size_t x, size_t y, int color, int bgcolor); void Debug(const char *format, ...); diff --git a/source/fatfs/ff.c b/source/fatfs/ff.c index f5547ae..e2b72f5 100644 --- a/source/fatfs/ff.c +++ b/source/fatfs/ff.c @@ -139,8 +139,8 @@ const unsigned short Tbl[] = { /* CP437(0x80-0xFF) to Unicode conversion table }; DWORD get_fattime (void) { - //NO - return 0; + // fixed valid time of 1980-01-01 00:00:00 + return 0x210000; } WCHAR ff_convert ( /* Converted character, Returns zero on error */ @@ -908,7 +908,7 @@ FRESULT sync_fs ( /* FR_OK: successful, FR_DISK_ERR: failed */ /*-----------------------------------------------------------------------*/ -DWORD clust2sect ( /* !=0: Sector number, 0: Failed - invalid cluster# */ +static DWORD clust2sect ( /* !=0: Sector number, 0: Failed - invalid cluster# */ FATFS* fs, /* File system object */ DWORD clst /* Cluster# to be converted */ ) @@ -926,7 +926,7 @@ DWORD clust2sect ( /* !=0: Sector number, 0: Failed - invalid cluster# */ /*-----------------------------------------------------------------------*/ -DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, Else:Cluster status */ +static DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, Else:Cluster status */ FATFS* fs, /* File system object */ DWORD clst /* Cluster# to get the link information */ ) @@ -946,7 +946,7 @@ DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, Else:Cluster status wc = fs->win[bc % SS(fs)]; bc++; if (move_window(fs, fs->fatbase + (bc / SS(fs)))) break; - wc |= fs->win[bc % SS(fs)] << 8; + wc |= (UINT)fs->win[bc % SS(fs)] << 8; return clst & 1 ? wc >> 4 : (wc & 0xFFF); case FS_FAT16 : @@ -974,7 +974,7 @@ DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, Else:Cluster status /*-----------------------------------------------------------------------*/ #if !_FS_READONLY -FRESULT put_fat ( +static FRESULT put_fat ( FATFS* fs, /* File system object */ DWORD clst, /* Cluster# to be changed in range of 2 to fs->n_fatent - 1 */ DWORD val /* New value to mark the cluster */ @@ -1245,7 +1245,7 @@ FRESULT dir_next ( /* FR_OK:Succeeded, FR_NO_FILE:End of table, FR_DENIED:Could UINT i; - i = dp->index + 1; + i = dp->index + 1u; if (!(i & 0xFFFF) || !dp->sect) /* Report EOT when index has reached 65535 */ return FR_NO_FILE; @@ -1257,7 +1257,7 @@ FRESULT dir_next ( /* FR_OK:Succeeded, FR_NO_FILE:End of table, FR_DENIED:Could return FR_NO_FILE; } else { /* Dynamic table */ - if (((i / (SS(dp->fs) / SZ_DIR)) & (dp->fs->csize - 1)) == 0) { /* Cluster changed? */ + if (((i / (SS(dp->fs) / SZ_DIR)) & (dp->fs->csize - 1u)) == 0) { /* Cluster changed? */ clst = get_fat(dp->fs, dp->clust); /* Get next cluster */ if (clst <= 1) return FR_INT_ERR; if (clst == 0xFFFFFFFF) return FR_DISK_ERR; @@ -1389,7 +1389,7 @@ int cmp_lfn ( /* 1:Matched, 0:Not matched */ WCHAR wc, uc; - i = ((dir[LDIR_Ord] & ~LLE) - 1) * 13; /* Get offset in the LFN buffer */ + i = ((UINT)(dir[LDIR_Ord] & ~LLE) - 1u) * 13u; /* Get offset in the LFN buffer */ s = 0; wc = 1; do { @@ -1421,7 +1421,7 @@ int pick_lfn ( /* 1:Succeeded, 0:Buffer overflow */ WCHAR wc, uc; - i = ((dir[LDIR_Ord] & 0x3F) - 1) * 13; /* Offset in the LFN buffer */ + i = ((dir[LDIR_Ord] & 0x3F) - 1u) * 13u; /* Offset in the LFN buffer */ s = 0; wc = 1; @@ -1462,7 +1462,7 @@ void fit_lfn ( dir[LDIR_Type] = 0; ST_WORD(dir+LDIR_FstClusLO, 0); - i = (ord - 1) * 13; /* Get offset in the LFN buffer */ + i = (ord - 1u) * 13u; /* Get offset in the LFN buffer */ s = wc = 0; do { if (wc != 0xFFFF) wc = lfnbuf[i++]; /* Get an effective character */ @@ -2200,7 +2200,7 @@ int get_ldnumber ( /* Returns logical drive number (-1:invalid drive) */ for (tt = *path; (UINT)*tt >= (_USE_LFN ? ' ' : '!') && *tt != ':'; tt++) ; /* Find ':' in the path */ if (*tt == ':') { /* If a ':' is exist in the path name */ tp = *path; - i = *tp++ - '0'; + i = (UINT)(*tp++ - '0'); if (i < 10 && tp == tt) { /* Is there a numeric drive id? */ if (i < _VOLUMES) { /* If a drive id is found, get the value and strip it */ vol = (int)i; @@ -2696,7 +2696,7 @@ FRESULT f_read ( for ( ; btr; /* Repeat until all data read */ rbuff += rcnt, fp->fptr += rcnt, *br += rcnt, btr -= rcnt) { if ((fp->fptr % SS(fp->fs)) == 0) { /* On the sector boundary? */ - csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1)); /* Sector offset in the cluster */ + csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1u)); /* Sector offset in the cluster */ if (!csect) { /* On the cluster boundary? */ if (fp->fptr == 0) { /* On the top of the file? */ clst = fp->sclust; /* Follow from the origin */ @@ -2718,7 +2718,7 @@ FRESULT f_read ( cc = btr / SS(fp->fs); /* When remaining bytes >= sector size, */ if (cc) { /* Read maximum contiguous sectors directly */ if (csect + cc > fp->fs->csize) /* Clip at cluster boundary */ - cc = fp->fs->csize - csect; + cc = (UINT)fp->fs->csize - csect; if (disk_read(fp->fs->drv, rbuff, sect, cc)) ABORT(fp->fs, FR_DISK_ERR); #if !_FS_READONLY && _FS_MINIMIZE <= 2 /* Replace one of the read sectors with cached data if it contains a dirty sector */ @@ -2797,7 +2797,7 @@ FRESULT f_write ( for ( ; btw; /* Repeat until all data written */ wbuff += wcnt, fp->fptr += wcnt, *bw += wcnt, btw -= wcnt) { if ((fp->fptr % SS(fp->fs)) == 0) { /* On the sector boundary? */ - csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1)); /* Sector offset in the cluster */ + csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1u)); /* Sector offset in the cluster */ if (!csect) { /* On the cluster boundary? */ if (fp->fptr == 0) { /* On the top of the file? */ clst = fp->sclust; /* Follow from the origin */ @@ -2832,7 +2832,7 @@ FRESULT f_write ( cc = btw / SS(fp->fs); /* When remaining bytes >= sector size, */ if (cc) { /* Write maximum contiguous sectors directly */ if (csect + cc > fp->fs->csize) /* Clip at cluster boundary */ - cc = fp->fs->csize - csect; + cc = (UINT)fp->fs->csize - csect; if (disk_write(fp->fs->drv, wbuff, sect, cc)) ABORT(fp->fs, FR_DISK_ERR); #if _FS_MINIMIZE <= 2 diff --git a/source/fatfs/ff.h b/source/fatfs/ff.h index c0d742f..a35b12c 100644 --- a/source/fatfs/ff.h +++ b/source/fatfs/ff.h @@ -330,7 +330,7 @@ int ff_del_syncobj (_SYNC_t sobj); /* Delete a sync object */ #define ST_DWORD(ptr,val) *(DWORD*)(BYTE*)(ptr)=(DWORD)(val) #else /* Use byte-by-byte access to the FAT structure */ #define LD_WORD(ptr) (WORD)(((WORD)*((BYTE*)(ptr)+1)<<8)|(WORD)*(BYTE*)(ptr)) -#define LD_DWORD(ptr) (DWORD)(((DWORD)*((BYTE*)(ptr)+3)<<24)|((DWORD)*((BYTE*)(ptr)+2)<<16)|((WORD)*((BYTE*)(ptr)+1)<<8)|*(BYTE*)(ptr)) +#define LD_DWORD(ptr) (DWORD)(((DWORD)*((BYTE*)(ptr)+3)<<24)|((DWORD)*((BYTE*)(ptr)+2)<<16)|(DWORD)((WORD)*((BYTE*)(ptr)+1)<<8)|*(BYTE*)(ptr)) #define ST_WORD(ptr,val) *(BYTE*)(ptr)=(BYTE)(val); *((BYTE*)(ptr)+1)=(BYTE)((WORD)(val)>>8) #define ST_DWORD(ptr,val) *(BYTE*)(ptr)=(BYTE)(val); *((BYTE*)(ptr)+1)=(BYTE)((WORD)(val)>>8); *((BYTE*)(ptr)+2)=(BYTE)((DWORD)(val)>>16); *((BYTE*)(ptr)+3)=(BYTE)((DWORD)(val)>>24) #endif diff --git a/source/fatfs/sdmmc.c b/source/fatfs/sdmmc.c index ab45589..458fd0d 100644 --- a/source/fatfs/sdmmc.c +++ b/source/fatfs/sdmmc.c @@ -20,15 +20,15 @@ mmcdevice *getMMCDevice(int drive) return &handleSD; } -int __attribute__((noinline)) geterror(struct mmcdevice *ctx) +static int __attribute__((noinline)) geterror(struct mmcdevice *ctx) { //if(ctx->error == 0x4) return -1; //else return 0; - return (ctx->error << 29) >> 31; + return (int)((ctx->error << 29) >> 31); } -void __attribute__((noinline)) inittarget(struct mmcdevice *ctx) +static void __attribute__((noinline)) inittarget(struct mmcdevice *ctx) { sdmmc_mask16(REG_SDPORTSEL,0x3,(u16)ctx->devicenumber); setckl(ctx->clk); @@ -41,7 +41,7 @@ void __attribute__((noinline)) inittarget(struct mmcdevice *ctx) } -void __attribute__((noinline)) sdmmc_send_command(struct mmcdevice *ctx, u32 cmd, u32 args) +static void __attribute__((noinline)) sdmmc_send_command(struct mmcdevice *ctx, u32 cmd, u32 args) { bool getSDRESP = (cmd << 15) >> 31; u16 flags = (cmd << 15) >> 31; @@ -72,8 +72,7 @@ void __attribute__((noinline)) sdmmc_send_command(struct mmcdevice *ctx, u32 cmd sdmmc_write16(REG_SDCMD,cmd &0xFFFF); u32 size = ctx->size; - u16 *dataPtr = (u16*)ctx->data; - u32 *dataPtr32 = (u32*)ctx->data; + u8 *dataPtr = ctx->data; bool useBuf = ( NULL != dataPtr ); bool useBuf32 = (useBuf && (0 == (3 & ((u32)dataPtr)))); @@ -88,12 +87,20 @@ void __attribute__((noinline)) sdmmc_send_command(struct mmcdevice *ctx, u32 cmd if (size > 0x1FF) { #ifdef DATA32_SUPPORT if (useBuf32) { - for(int i = 0; i<0x200; i+=4) - *dataPtr32++ = sdmmc_read32(REG_SDFIFO32); + for(int i = 0; i<0x200; i+=4) { + u32 data = sdmmc_read32(REG_SDFIFO32); + *dataPtr++ = data; + *dataPtr++ = data >> 8; + *dataPtr++ = data >> 16; + *dataPtr++ = data >> 24; + } } else { #endif - for(int i = 0; i<0x200; i+=2) - *dataPtr++ = sdmmc_read16(REG_SDFIFO); + for(int i = 0; i<0x200; i+=2) { + u16 data = sdmmc_read16(REG_SDFIFO); + *dataPtr++ = data; + *dataPtr++ = data >> 8; + } #ifdef DATA32_SUPPORT } #endif @@ -108,11 +115,19 @@ void __attribute__((noinline)) sdmmc_send_command(struct mmcdevice *ctx, u32 cmd //sdmmc_write16(REG_SDSTATUS1,~TMIO_STAT1_TXRQ); if (size > 0x1FF) { #ifdef DATA32_SUPPORT - for (int i = 0; i<0x200; i+=4) - sdmmc_write32(REG_SDFIFO32,*dataPtr32++); + for (int i = 0; i<0x200; i+=4) { + u32 data = *dataPtr++; + data |= *dataPtr++ << 8; + data |= *dataPtr++ << 16; + data |= *dataPtr++ << 24; + sdmmc_write32(REG_SDFIFO32,data); + } #else - for (int i = 0; i<0x200; i+=2) - sdmmc_write16(REG_SDFIFO,*dataPtr++); + for (int i = 0; i<0x200; i+=2) { + u16 data = *dataPtr++; + data |= *dataPtr++ << 8; + sdmmc_write16(REG_SDFIFO,data); + } #endif size -= 0x200; } @@ -140,14 +155,14 @@ void __attribute__((noinline)) sdmmc_send_command(struct mmcdevice *ctx, u32 cmd sdmmc_write16(REG_SDSTATUS1,0); if (getSDRESP != 0) { - ctx->ret[0] = sdmmc_read16(REG_SDRESP0) | (sdmmc_read16(REG_SDRESP1) << 16); - ctx->ret[1] = sdmmc_read16(REG_SDRESP2) | (sdmmc_read16(REG_SDRESP3) << 16); - ctx->ret[2] = sdmmc_read16(REG_SDRESP4) | (sdmmc_read16(REG_SDRESP5) << 16); - ctx->ret[3] = sdmmc_read16(REG_SDRESP6) | (sdmmc_read16(REG_SDRESP7) << 16); + ctx->ret[0] = (u32)sdmmc_read16(REG_SDRESP0) | ((u32)sdmmc_read16(REG_SDRESP1) << 16); + ctx->ret[1] = (u32)sdmmc_read16(REG_SDRESP2) | ((u32)sdmmc_read16(REG_SDRESP3) << 16); + ctx->ret[2] = (u32)sdmmc_read16(REG_SDRESP4) | ((u32)sdmmc_read16(REG_SDRESP5) << 16); + ctx->ret[3] = (u32)sdmmc_read16(REG_SDRESP6) | ((u32)sdmmc_read16(REG_SDRESP7) << 16); } } -int __attribute__((noinline)) sdmmc_sdcard_writesectors(u32 sector_no, u32 numsectors, u8 *in) +int __attribute__((noinline)) sdmmc_sdcard_writesectors(u32 sector_no, u32 numsectors, const u8 *in) { if (handleSD.isSDHC == 0) sector_no <<= 9; @@ -206,7 +221,7 @@ int __attribute__((noinline)) sdmmc_nand_readsectors(u32 sector_no, u32 numsecto return geterror(&handleNAND); } -int __attribute__((noinline)) sdmmc_nand_writesectors(u32 sector_no, u32 numsectors, u8 *in) //experimental +int __attribute__((noinline)) sdmmc_nand_writesectors(u32 sector_no, u32 numsectors, const u8 *in) //experimental { if (handleNAND.isSDHC == 0) sector_no <<= 9; @@ -226,7 +241,7 @@ int __attribute__((noinline)) sdmmc_nand_writesectors(u32 sector_no, u32 numsect return geterror(&handleNAND); } -u32 calcSDSize(u8* csd, int type) +static u32 calcSDSize(u8* csd, int type) { u32 result = 0; u8 temp = csd[0xE]; @@ -238,14 +253,14 @@ u32 calcSDSize(u8* csd, int type) break; case 0: { - u32 temp = (csd[0x7] << 0x2 | csd[0x8] << 0xA | csd[0x6] >> 0x6 | (csd[0x9] & 0xF) << 0x10) & 0xFFF; - u32 temp2 = temp * (1 << (csd[0x9] & 0xF)); - u32 retval = temp2 * (1 << (((csd[0x4] >> 7 | csd[0x5] << 1) & 7) + 2)); + u32 temp2 = (csd[0x7] << 0x2 | csd[0x8] << 0xA | csd[0x6] >> 0x6 | (csd[0x9] & 0xF) << 0x10) & 0xFFF; + u32 temp3 = temp2 * (1u << (csd[0x9] & 0xF)); + u32 retval = temp3 * (1u << (((csd[0x4] >> 7 | csd[0x5] << 1) & 7) + 2)); result = retval >> 9; break; } case 1: - result = (((csd[0x7] & 0x3F) << 0x10 | csd[0x6] << 8 | csd[0x5]) + 1) << 0xA; + result = (u32)(((csd[0x7] & 0x3F) << 0x10 | csd[0x6] << 8 | csd[0x5]) + 1) << 0xA; break; default: result = 0; @@ -255,7 +270,7 @@ u32 calcSDSize(u8* csd, int type) return result; } -void InitSD() +static void InitSD() { //NAND handleNAND.isSDHC = 0; @@ -453,9 +468,10 @@ int SD_Init() return 0; } -void sdmmc_sdcard_init() +int sdmmc_sdcard_init() { InitSD(); - u32 nand_res = Nand_Init(); - u32 sd_res = SD_Init(); + int nand_res = Nand_Init(); + int sd_res = SD_Init(); + return nand_res | sd_res; } diff --git a/source/fatfs/sdmmc.h b/source/fatfs/sdmmc.h index bc067cb..9578503 100644 --- a/source/fatfs/sdmmc.h +++ b/source/fatfs/sdmmc.h @@ -125,14 +125,14 @@ void sdmmc_sdcard_writesector(uint32_t sector_no, void *in); void sdmmc_sdcard_writesectors(uint32_t sector_no, uint32_t numsectors, void *in); void sdmmc_blktransferinit();*/ -void sdmmc_sdcard_init(); +int sdmmc_sdcard_init(); int sdmmc_sdcard_readsector(u32 sector_no, u8 *out); int sdmmc_sdcard_readsectors(u32 sector_no, u32 numsectors, u8 *out); -int sdmmc_sdcard_writesector(u32 sector_no, u8 *in); -int sdmmc_sdcard_writesectors(u32 sector_no, u32 numsectors, u8 *in); +int sdmmc_sdcard_writesector(u32 sector_no, const u8 *in); +int sdmmc_sdcard_writesectors(u32 sector_no, u32 numsectors, const u8 *in); int sdmmc_nand_readsectors(u32 sector_no, u32 numsectors, u8 *out); -int sdmmc_nand_writesectors(u32 sector_no, u32 numsectors, u8 *in); +int sdmmc_nand_writesectors(u32 sector_no, u32 numsectors, const u8 *in); mmcdevice *getMMCDevice(int drive); diff --git a/source/gamecart/command_ctr.c b/source/gamecart/command_ctr.c index 517c679..8e9ae75 100644 --- a/source/gamecart/command_ctr.c +++ b/source/gamecart/command_ctr.c @@ -9,7 +9,7 @@ static int read_count = 0; -void CTR_CmdC5() +static void CTR_CmdC5() { static const u32 c5_cmd[4] = { 0xC5000000, 0x00000000, 0x00000000, 0x00000000 }; CTR_SendCommand(c5_cmd, 0, 1, 0x100002C, NULL); diff --git a/source/gamecart/command_ntr.c b/source/gamecart/command_ntr.c index f0f66f0..e63ae22 100644 --- a/source/gamecart/command_ntr.c +++ b/source/gamecart/command_ntr.c @@ -12,7 +12,7 @@ void NTR_CmdReset(void) NTR_SendCommand(reset_cmd, 0x2000, NTRCARD_CLK_SLOW | NTRCARD_DELAY1(0x1FFF) | NTRCARD_DELAY2(0x18), NULL); } -int NTR_CmdGetCartId(void) +u32 NTR_CmdGetCartId(void) { u32 id; static const u32 getid_cmd[2] = { 0x90000000, 0x00000000 }; diff --git a/source/gamecart/command_ntr.h b/source/gamecart/command_ntr.h index 7c5459f..1e7162a 100644 --- a/source/gamecart/command_ntr.h +++ b/source/gamecart/command_ntr.h @@ -7,5 +7,5 @@ #include "common.h" void NTR_CmdReset(void); -int NTR_CmdGetCartId(void); +u32 NTR_CmdGetCartId(void); void NTR_CmdEnter16ByteMode(void); diff --git a/source/gamecart/protocol.c b/source/gamecart/protocol.c index 86b1147..70f4dac 100644 --- a/source/gamecart/protocol.c +++ b/source/gamecart/protocol.c @@ -1,226 +1,226 @@ -// Copyright 2014 Normmatt -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "protocol.h" - -#include -#include -#include - -#include "draw.h" -#include "common.h" -#include "aes.h" -#include "protocol_ctr.h" -#include "protocol_ntr.h" -#include "command_ctr.h" -#include "command_ntr.h" -#include "delay.h" - -extern u8* bottomScreen; - -u32 CartID = -1; -u32 CartType = 0; - -static int A0_Response = -1; -static u32 rand1 = 0; -static u32 rand2 = 0; - -u32 BSWAP32(u32 val) { - return (((val >> 24) & 0xFF)) | - (((val >> 16) & 0xFF) << 8) | - (((val >> 8) & 0xFF) << 16) | - ((val & 0xFF) << 24); -} - -// TODO: Verify -static void ResetCartSlot(void) -{ - REG_CARDCONF2 = 0x0C; - REG_CARDCONF &= ~3; - - if (REG_CARDCONF2 == 0xC) { - while (REG_CARDCONF2 != 0); - } - - if (REG_CARDCONF2 != 0) - return; - - REG_CARDCONF2 = 0x4; - while(REG_CARDCONF2 != 0x4); - - REG_CARDCONF2 = 0x8; - while(REG_CARDCONF2 != 0x8); -} - -static void SwitchToNTRCARD(void) -{ - REG_NTRCARDROMCNT = 0x20000000; - REG_CARDCONF &= ~3; - REG_CARDCONF &= ~0x100; - REG_NTRCARDMCNT = NTRCARD_CR1_ENABLE; -} - -static void SwitchToCTRCARD(void) -{ - REG_CTRCARDCNT = 0x10000000; - REG_CARDCONF = (REG_CARDCONF & ~3) | 2; -} - -int Cart_IsInserted(void) -{ - return (0x9000E2C2 == CTR_CmdGetSecureId(rand1, rand2) ); -} - -u32 Cart_GetID(void) -{ - return CartID; -} - -void Cart_Init(void) -{ - ResetCartSlot(); //Seems to reset the cart slot? - - REG_CTRCARDSECCNT &= 0xFFFFFFFB; - ioDelay(0x30000); - - SwitchToNTRCARD(); - ioDelay(0x30000); - - REG_NTRCARDROMCNT = 0; - REG_NTRCARDMCNT &= 0xFF; - ioDelay(0x40000); - - REG_NTRCARDMCNT |= (NTRCARD_CR1_ENABLE | NTRCARD_CR1_IRQ); - REG_NTRCARDROMCNT = NTRCARD_nRESET | NTRCARD_SEC_SEED; - while (REG_NTRCARDROMCNT & NTRCARD_BUSY); - - // Reset - NTR_CmdReset(); - CartID = NTR_CmdGetCartId(); - - // 3ds - if (CartID & 0x10000000) { - u32 unknowna0_cmd[2] = { 0xA0000000, 0x00000000 }; - NTR_SendCommand(unknowna0_cmd, 0x4, 0, &A0_Response); - - NTR_CmdEnter16ByteMode(); - SwitchToCTRCARD(); - ioDelay(0xF000); - - REG_CTRCARDBLKCNT = 0; - } -} - -static void AES_SetKeyControl(u32 a) { - REG_AESKEYCNT = (REG_AESKEYCNT & 0xC0) | a | 0x80; -} - -//returns 1 if MAC valid otherwise 0 -static u8 card_aes(u32 *out, u32 *buff, size_t size) { // note size param ignored - u8 tmp = REG_AESKEYCNT; - REG_AESCNT = 0x10C00; //flush r/w fifo macsize = 001 - - (*(vu8*)0x10000008) |= 0x0C; //??? - - REG_AESCNT |= 0x2800000; - - //const u8 is_dev_unit = *(vu8*)0x10010010; - //if(is_dev_unit) //Dev unit - const u8 is_dev_cart = (A0_Response&3)==3; - if(is_dev_cart) //Dev unit - { - AES_SetKeyControl(0x11); - REG_AESKEYFIFO = 0; - REG_AESKEYFIFO = 0; - REG_AESKEYFIFO = 0; - REG_AESKEYFIFO = 0; - REG_AESKEYSEL = 0x11; - } - else - { - AES_SetKeyControl(0x3B); - REG_AESKEYYFIFO = buff[0]; - REG_AESKEYYFIFO = buff[1]; - REG_AESKEYYFIFO = buff[2]; - REG_AESKEYYFIFO = buff[3]; - REG_AESKEYSEL = 0x3B; - } - - REG_AESCNT = 0x4000000; - REG_AESCNT &= 0xFFF7FFFF; - REG_AESCNT |= 0x2970000; - REG_AESMAC[0] = buff[11]; - REG_AESMAC[1] = buff[10]; - REG_AESMAC[2] = buff[9]; - REG_AESMAC[3] = buff[8]; - REG_AESCNT |= 0x2800000; - REG_AESCTR[0] = buff[14]; - REG_AESCTR[1] = buff[13]; - REG_AESCTR[2] = buff[12]; - REG_AESBLKCNT = 0x10000; - - u32 v11 = ((REG_AESCNT | 0x80000000) & 0xC7FFFFFF); //Start and clear mode (ccm decrypt) - u32 v12 = v11 & 0xBFFFFFFF; //Disable Interrupt - REG_AESCNT = ((((v12 | 0x3000) & 0xFD7F3FFF) | (5 << 23)) & 0xFEBFFFFF) | (5 << 22); - - //REG_AESCNT = 0x83D73C00; - REG_AESWRFIFO = buff[4]; - REG_AESWRFIFO = buff[5]; - REG_AESWRFIFO = buff[6]; - REG_AESWRFIFO = buff[7]; - while (((REG_AESCNT >> 5) & 0x1F) <= 3); - out[0] = REG_AESRDFIFO; - out[1] = REG_AESRDFIFO; - out[2] = REG_AESRDFIFO; - out[3] = REG_AESRDFIFO; - return ((REG_AESCNT >> 21) & 1); -} - -void Cart_Secure_Init(u32 *buf, u32 *out) -{ - u8 mac_valid = card_aes(out, buf, 0x200); - -// if (!mac_valid) -// ClearScreen(bottomScreen, RGB(255, 0, 0)); - - ioDelay(0xF0000); - - CTR_SetSecKey(A0_Response); - CTR_SetSecSeed(out, true); - - rand1 = 0x42434445;//*((vu32*)0x10011000); - rand2 = 0x46474849;//*((vu32*)0x10011010); - - CTR_CmdSeed(rand1, rand2); - - out[3] = BSWAP32(rand2); - out[2] = BSWAP32(rand1); - CTR_SetSecSeed(out, false); - - u32 test = 0; - const u32 A2_cmd[4] = { 0xA2000000, 0x00000000, rand1, rand2 }; - CTR_SendCommand(A2_cmd, 4, 1, 0x701002C, &test); - - u32 test2 = 0; - const u32 A3_cmd[4] = { 0xA3000000, 0x00000000, rand1, rand2 }; - CTR_SendCommand(A3_cmd, 4, 1, 0x701002C, &test2); - - if(test==CartID && test2==A0_Response) - { - const u32 C5_cmd[4] = { 0xC5000000, 0x00000000, rand1, rand2 }; - CTR_SendCommand(C5_cmd, 0, 1, 0x100002C, NULL); - } - - for (int i = 0; i < 5; ++i) { - CTR_SendCommand(A2_cmd, 4, 1, 0x701002C, &test); - ioDelay(0xF0000); - } -} - -void Cart_Dummy(void) { - // Sends a dummy command to skip encrypted responses some problematic carts send. - u32 test; - const u32 A2_cmd[4] = { 0xA2000000, 0x00000000, rand1, rand2 }; - CTR_SendCommand(A2_cmd, 4, 1, 0x701002C, &test); -} +// Copyright 2014 Normmatt +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "protocol.h" + +#include +#include +#include + +#include "draw.h" +#include "common.h" +#include "aes.h" +#include "protocol_ctr.h" +#include "protocol_ntr.h" +#include "command_ctr.h" +#include "command_ntr.h" +#include "delay.h" + +extern u8* bottomScreen; + +u32 CartID = 0xFFFFFFFFu; +u32 CartType = 0; + +static u32 A0_Response = 0xFFFFFFFFu; +static u32 rand1 = 0; +static u32 rand2 = 0; + +u32 BSWAP32(u32 val) { + return (((val >> 24) & 0xFF)) | + (((val >> 16) & 0xFF) << 8) | + (((val >> 8) & 0xFF) << 16) | + ((val & 0xFF) << 24); +} + +// TODO: Verify +static void ResetCartSlot(void) +{ + REG_CARDCONF2 = 0x0C; + REG_CARDCONF &= ~3; + + if (REG_CARDCONF2 == 0xC) { + while (REG_CARDCONF2 != 0); + } + + if (REG_CARDCONF2 != 0) + return; + + REG_CARDCONF2 = 0x4; + while(REG_CARDCONF2 != 0x4); + + REG_CARDCONF2 = 0x8; + while(REG_CARDCONF2 != 0x8); +} + +static void SwitchToNTRCARD(void) +{ + REG_NTRCARDROMCNT = 0x20000000; + REG_CARDCONF &= ~3; + REG_CARDCONF &= ~0x100; + REG_NTRCARDMCNT = NTRCARD_CR1_ENABLE; +} + +static void SwitchToCTRCARD(void) +{ + REG_CTRCARDCNT = 0x10000000; + REG_CARDCONF = (REG_CARDCONF & ~3) | 2; +} + +int Cart_IsInserted(void) +{ + return (0x9000E2C2 == CTR_CmdGetSecureId(rand1, rand2) ); +} + +u32 Cart_GetID(void) +{ + return CartID; +} + +void Cart_Init(void) +{ + ResetCartSlot(); //Seems to reset the cart slot? + + REG_CTRCARDSECCNT &= 0xFFFFFFFB; + ioDelay(0x30000); + + SwitchToNTRCARD(); + ioDelay(0x30000); + + REG_NTRCARDROMCNT = 0; + REG_NTRCARDMCNT &= 0xFF; + ioDelay(0x40000); + + REG_NTRCARDMCNT |= (NTRCARD_CR1_ENABLE | NTRCARD_CR1_IRQ); + REG_NTRCARDROMCNT = NTRCARD_nRESET | NTRCARD_SEC_SEED; + while (REG_NTRCARDROMCNT & NTRCARD_BUSY); + + // Reset + NTR_CmdReset(); + CartID = NTR_CmdGetCartId(); + + // 3ds + if (CartID & 0x10000000) { + u32 unknowna0_cmd[2] = { 0xA0000000, 0x00000000 }; + NTR_SendCommand(unknowna0_cmd, 0x4, 0, &A0_Response); + + NTR_CmdEnter16ByteMode(); + SwitchToCTRCARD(); + ioDelay(0xF000); + + REG_CTRCARDBLKCNT = 0; + } +} + +static void AES_SetKeyControl(u32 a) { + REG_AESKEYCNT = (REG_AESKEYCNT & 0xC0) | a | 0x80; +} + +//returns 1 if MAC valid otherwise 0 +static u8 card_aes(u32 *out, u32 *buff, size_t size) { // note size param ignored + u8 tmp = REG_AESKEYCNT; + REG_AESCNT = 0x10C00; //flush r/w fifo macsize = 001 + + (*(vu8*)0x10000008) |= 0x0C; //??? + + REG_AESCNT |= 0x2800000; + + //const u8 is_dev_unit = *(vu8*)0x10010010; + //if(is_dev_unit) //Dev unit + const u8 is_dev_cart = (A0_Response&3)==3; + if(is_dev_cart) //Dev unit + { + AES_SetKeyControl(0x11); + REG_AESKEYFIFO = 0; + REG_AESKEYFIFO = 0; + REG_AESKEYFIFO = 0; + REG_AESKEYFIFO = 0; + REG_AESKEYSEL = 0x11; + } + else + { + AES_SetKeyControl(0x3B); + REG_AESKEYYFIFO = buff[0]; + REG_AESKEYYFIFO = buff[1]; + REG_AESKEYYFIFO = buff[2]; + REG_AESKEYYFIFO = buff[3]; + REG_AESKEYSEL = 0x3B; + } + + REG_AESCNT = 0x4000000; + REG_AESCNT &= 0xFFF7FFFF; + REG_AESCNT |= 0x2970000; + REG_AESMAC[0] = buff[11]; + REG_AESMAC[1] = buff[10]; + REG_AESMAC[2] = buff[9]; + REG_AESMAC[3] = buff[8]; + REG_AESCNT |= 0x2800000; + REG_AESCTR[0] = buff[14]; + REG_AESCTR[1] = buff[13]; + REG_AESCTR[2] = buff[12]; + REG_AESBLKCNT = 0x10000; + + u32 v11 = ((REG_AESCNT | 0x80000000) & 0xC7FFFFFF); //Start and clear mode (ccm decrypt) + u32 v12 = v11 & 0xBFFFFFFF; //Disable Interrupt + REG_AESCNT = ((((v12 | 0x3000) & 0xFD7F3FFF) | (5 << 23)) & 0xFEBFFFFF) | (5 << 22); + + //REG_AESCNT = 0x83D73C00; + REG_AESWRFIFO = buff[4]; + REG_AESWRFIFO = buff[5]; + REG_AESWRFIFO = buff[6]; + REG_AESWRFIFO = buff[7]; + while (((REG_AESCNT >> 5) & 0x1F) <= 3); + out[0] = REG_AESRDFIFO; + out[1] = REG_AESRDFIFO; + out[2] = REG_AESRDFIFO; + out[3] = REG_AESRDFIFO; + return ((REG_AESCNT >> 21) & 1); +} + +void Cart_Secure_Init(u32 *buf, u32 *out) +{ + u8 mac_valid = card_aes(out, buf, 0x200); + +// if (!mac_valid) +// ClearScreen(bottomScreen, RGB(255, 0, 0)); + + ioDelay(0xF0000); + + CTR_SetSecKey(A0_Response); + CTR_SetSecSeed(out, true); + + rand1 = 0x42434445;//*((vu32*)0x10011000); + rand2 = 0x46474849;//*((vu32*)0x10011010); + + CTR_CmdSeed(rand1, rand2); + + out[3] = BSWAP32(rand2); + out[2] = BSWAP32(rand1); + CTR_SetSecSeed(out, false); + + u32 test = 0; + const u32 A2_cmd[4] = { 0xA2000000, 0x00000000, rand1, rand2 }; + CTR_SendCommand(A2_cmd, 4, 1, 0x701002C, &test); + + u32 test2 = 0; + const u32 A3_cmd[4] = { 0xA3000000, 0x00000000, rand1, rand2 }; + CTR_SendCommand(A3_cmd, 4, 1, 0x701002C, &test2); + + if(test==CartID && test2==A0_Response) + { + const u32 C5_cmd[4] = { 0xC5000000, 0x00000000, rand1, rand2 }; + CTR_SendCommand(C5_cmd, 0, 1, 0x100002C, NULL); + } + + for (int i = 0; i < 5; ++i) { + CTR_SendCommand(A2_cmd, 4, 1, 0x701002C, &test); + ioDelay(0xF0000); + } +} + +void Cart_Dummy(void) { + // Sends a dummy command to skip encrypted responses some problematic carts send. + u32 test; + const u32 A2_cmd[4] = { 0xA2000000, 0x00000000, rand1, rand2 }; + CTR_SendCommand(A2_cmd, 4, 1, 0x701002C, &test); +} diff --git a/source/gamecart/protocol.h b/source/gamecart/protocol.h index 1f43ba1..7a12407 100644 --- a/source/gamecart/protocol.h +++ b/source/gamecart/protocol.h @@ -1,25 +1,25 @@ -// Copyright 2014 Normmatt -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once -#include "common.h" - -#define REG_CARDCONF (*(vu16*)0x1000000C) -#define REG_CARDCONF2 (*(vu8*)0x10000010) - -//REG_AUXSPICNT -#define CARD_ENABLE (1<<15) -#define CARD_SPI_ENABLE (1<<13) -#define CARD_SPI_BUSY (1<<7) -#define CARD_SPI_HOLD (1<<6) - -#define LATENCY 0x822C - -u32 BSWAP32(u32 val); - -void Cart_Init(void); -int Cart_IsInserted(void); -u32 Cart_GetID(void); -void Cart_Secure_Init(u32* buf, u32* out); -void Cart_Dummy(void); +// Copyright 2014 Normmatt +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once +#include "common.h" + +#define REG_CARDCONF (*(vu16*)0x1000000C) +#define REG_CARDCONF2 (*(vu8*)0x10000010) + +//REG_AUXSPICNT +#define CARD_ENABLE (1u<<15) +#define CARD_SPI_ENABLE (1u<<13) +#define CARD_SPI_BUSY (1u<<7) +#define CARD_SPI_HOLD (1u<<6) + +#define LATENCY 0x822Cu + +u32 BSWAP32(u32 val); + +void Cart_Init(void); +int Cart_IsInserted(void); +u32 Cart_GetID(void); +void Cart_Secure_Init(u32* buf, u32* out); +void Cart_Dummy(void); diff --git a/source/gamecart/protocol_ctr.c b/source/gamecart/protocol_ctr.c index 3fdea64..9799bde 100644 --- a/source/gamecart/protocol_ctr.c +++ b/source/gamecart/protocol_ctr.c @@ -74,6 +74,8 @@ void CTR_SendCommand(const u32 command[4], u32 pageSize, u32 blocks, u32 latency transferLength = 4096; pageParam = CTRCARD_PAGESIZE_4K; break; + default: + break; //Defaults already set } REG_CTRCARDBLKCNT = blocks - 1; diff --git a/source/gamecart/protocol_ctr.h b/source/gamecart/protocol_ctr.h index 67c902c..cba469e 100644 --- a/source/gamecart/protocol_ctr.h +++ b/source/gamecart/protocol_ctr.h @@ -14,27 +14,27 @@ #define REG_CTRCARDFIFO (*(vu32*)0x10004030) #define CTRCARD_PAGESIZE_0 (0<<16) -#define CTRCARD_PAGESIZE_4 (1<<16) -#define CTRCARD_PAGESIZE_16 (2<<16) -#define CTRCARD_PAGESIZE_64 (3<<16) -#define CTRCARD_PAGESIZE_512 (4<<16) -#define CTRCARD_PAGESIZE_1K (5<<16) -#define CTRCARD_PAGESIZE_2K (6<<16) -#define CTRCARD_PAGESIZE_4K (7<<16) -#define CTRCARD_PAGESIZE_16K (8<<16) -#define CTRCARD_PAGESIZE_64K (9<<16) +#define CTRCARD_PAGESIZE_4 (1u<<16) +#define CTRCARD_PAGESIZE_16 (2u<<16) +#define CTRCARD_PAGESIZE_64 (3u<<16) +#define CTRCARD_PAGESIZE_512 (4u<<16) +#define CTRCARD_PAGESIZE_1K (5u<<16) +#define CTRCARD_PAGESIZE_2K (6u<<16) +#define CTRCARD_PAGESIZE_4K (7u<<16) +#define CTRCARD_PAGESIZE_16K (8u<<16) +#define CTRCARD_PAGESIZE_64K (9u<<16) -#define CTRCARD_CRC_ERROR (1<<4) -#define CTRCARD_ACTIVATE (1<<31) // when writing, get the ball rolling -#define CTRCARD_IE (1<<30) // Interrupt enable -#define CTRCARD_WR (1<<29) // Card write enable -#define CTRCARD_nRESET (1<<28) // value on the /reset pin (1 = high out, not a reset state, 0 = low out = in reset) -#define CTRCARD_BLK_SIZE(n) (((n)&0xF)<<16) // Transfer block size +#define CTRCARD_CRC_ERROR (1u<<4) +#define CTRCARD_ACTIVATE (1u<<31) // when writing, get the ball rolling +#define CTRCARD_IE (1u<<30) // Interrupt enable +#define CTRCARD_WR (1u<<29) // Card write enable +#define CTRCARD_nRESET (1u<<28) // value on the /reset pin (1 = high out, not a reset state, 0 = low out = in reset) +#define CTRCARD_BLK_SIZE(n) (((n)&0xFu)<<16) // Transfer block size -#define CTRCARD_BUSY (1<<31) // when reading, still expecting incomming data? -#define CTRCARD_DATA_READY (1<<27) // when reading, REG_CTRCARDFIFO has another word of data and is good to go +#define CTRCARD_BUSY (1u<<31) // when reading, still expecting incomming data? +#define CTRCARD_DATA_READY (1u<<27) // when reading, REG_CTRCARDFIFO has another word of data and is good to go -#define CTRKEY_PARAM 0x1000000 +#define CTRKEY_PARAM 0x1000000u void CTR_SetSecKey(u32 value); void CTR_SetSecSeed(const u32* seed, bool flag); diff --git a/source/gamecart/protocol_ntr.c b/source/gamecart/protocol_ntr.c index 0781fdf..9888307 100644 --- a/source/gamecart/protocol_ntr.c +++ b/source/gamecart/protocol_ntr.c @@ -44,6 +44,8 @@ void NTR_SendCommand(const u32 command[2], u32 pageSize, u32 latency, void* buff transferLength = 8192; pageParam = NTRCARD_PAGESIZE_8K; break; + default: + break; //Using 4K pagesize and transfer length by default } // go diff --git a/source/gamecart/protocol_ntr.h b/source/gamecart/protocol_ntr.h index 2bb3113..069ed61 100644 --- a/source/gamecart/protocol_ntr.h +++ b/source/gamecart/protocol_ntr.h @@ -17,48 +17,48 @@ #define REG_NTRCARDFIFO (*(vu32*)0x1016401C) #define NTRCARD_PAGESIZE_0 (0<<24) -#define NTRCARD_PAGESIZE_4 (7<<24) -#define NTRCARD_PAGESIZE_512 (1<<24) -#define NTRCARD_PAGESIZE_1K (2<<24) -#define NTRCARD_PAGESIZE_2K (3<<24) -#define NTRCARD_PAGESIZE_4K (4<<24) -#define NTRCARD_PAGESIZE_8K (5<<24) -#define NTRCARD_PAGESIZE_16K (6<<24) +#define NTRCARD_PAGESIZE_4 (7u<<24) +#define NTRCARD_PAGESIZE_512 (1u<<24) +#define NTRCARD_PAGESIZE_1K (2u<<24) +#define NTRCARD_PAGESIZE_2K (3u<<24) +#define NTRCARD_PAGESIZE_4K (4u<<24) +#define NTRCARD_PAGESIZE_8K (5u<<24) +#define NTRCARD_PAGESIZE_16K (6u<<24) -#define NTRCARD_ACTIVATE (1<<31) // when writing, get the ball rolling -#define NTRCARD_WR (1<<30) // Card write enable -#define NTRCARD_nRESET (1<<29) // value on the /reset pin (1 = high out, not a reset state, 0 = low out = in reset) -#define NTRCARD_SEC_LARGE (1<<28) // Use "other" secure area mode, which tranfers blocks of 0x1000 bytes at a time -#define NTRCARD_CLK_SLOW (1<<27) // Transfer clock rate (0 = 6.7MHz, 1 = 4.2MHz) -#define NTRCARD_BLK_SIZE(n) (((n)&0x7)<<24) // Transfer block size, (0 = None, 1..6 = (0x100 << n) bytes, 7 = 4 bytes) -#define NTRCARD_SEC_CMD (1<<22) // The command transfer will be hardware encrypted (KEY2) -#define NTRCARD_DELAY2(n) (((n)&0x3F)<<16) // Transfer delay length part 2 -#define NTRCARD_SEC_SEED (1<<15) // Apply encryption (KEY2) seed to hardware registers -#define NTRCARD_SEC_EN (1<<14) // Security enable -#define NTRCARD_SEC_DAT (1<<13) // The data transfer will be hardware encrypted (KEY2) -#define NTRCARD_DELAY1(n) ((n)&0x1FFF) // Transfer delay length part 1 +#define NTRCARD_ACTIVATE (1u<<31) // when writing, get the ball rolling +#define NTRCARD_WR (1u<<30) // Card write enable +#define NTRCARD_nRESET (1u<<29) // value on the /reset pin (1 = high out, not a reset state, 0 = low out = in reset) +#define NTRCARD_SEC_LARGE (1u<<28) // Use "other" secure area mode, which tranfers blocks of 0x1000 bytes at a time +#define NTRCARD_CLK_SLOW (1u<<27) // Transfer clock rate (0 = 6.7MHz, 1 = 4.2MHz) +#define NTRCARD_BLK_SIZE(n) (((n)&0x7u)<<24) // Transfer block size, (0 = None, 1..6 = (0x100 << n) bytes, 7 = 4 bytes) +#define NTRCARD_SEC_CMD (1u<<22) // The command transfer will be hardware encrypted (KEY2) +#define NTRCARD_DELAY2(n) (((n)&0x3Fu)<<16) // Transfer delay length part 2 +#define NTRCARD_SEC_SEED (1u<<15) // Apply encryption (KEY2) seed to hardware registers +#define NTRCARD_SEC_EN (1u<<14) // Security enable +#define NTRCARD_SEC_DAT (1u<<13) // The data transfer will be hardware encrypted (KEY2) +#define NTRCARD_DELAY1(n) ((n)&0x1FFFu) // Transfer delay length part 1 // 3 bits in b10..b8 indicate something // read bits -#define NTRCARD_BUSY (1<<31) // when reading, still expecting incomming data? -#define NTRCARD_DATA_READY (1<<23) // when reading, REG_NTRCARDFIFO has another word of data and is good to go +#define NTRCARD_BUSY (1u<<31) // when reading, still expecting incomming data? +#define NTRCARD_DATA_READY (1u<<23) // when reading, REG_NTRCARDFIFO has another word of data and is good to go // Card commands -#define NTRCARD_CMD_DUMMY 0x9F -#define NTRCARD_CMD_HEADER_READ 0x00 -#define NTRCARD_CMD_HEADER_CHIPID 0x90 -#define NTRCARD_CMD_ACTIVATE_BF 0x3C // Go into blowfish (KEY1) encryption mode -#define NTRCARD_CMD_ACTIVATE_SEC 0x40 // Go into hardware (KEY2) encryption mode -#define NTRCARD_CMD_SECURE_CHIPID 0x10 -#define NTRCARD_CMD_SECURE_READ 0x20 -#define NTRCARD_CMD_DISABLE_SEC 0x60 // Leave hardware (KEY2) encryption mode -#define NTRCARD_CMD_DATA_MODE 0xA0 -#define NTRCARD_CMD_DATA_READ 0xB7 -#define NTRCARD_CMD_DATA_CHIPID 0xB8 +#define NTRCARD_CMD_DUMMY 0x9Fu +#define NTRCARD_CMD_HEADER_READ 0x00u +#define NTRCARD_CMD_HEADER_CHIPID 0x90u +#define NTRCARD_CMD_ACTIVATE_BF 0x3Cu // Go into blowfish (KEY1) encryption mode +#define NTRCARD_CMD_ACTIVATE_SEC 0x40u // Go into hardware (KEY2) encryption mode +#define NTRCARD_CMD_SECURE_CHIPID 0x10u +#define NTRCARD_CMD_SECURE_READ 0x20u +#define NTRCARD_CMD_DISABLE_SEC 0x60u // Leave hardware (KEY2) encryption mode +#define NTRCARD_CMD_DATA_MODE 0xA0u +#define NTRCARD_CMD_DATA_READ 0xB7u +#define NTRCARD_CMD_DATA_CHIPID 0xB8u -#define NTRCARD_CR1_ENABLE 0x8000 -#define NTRCARD_CR1_IRQ 0x4000 +#define NTRCARD_CR1_ENABLE 0x8000u +#define NTRCARD_CR1_IRQ 0x4000u -#define NTRKEY_PARAM 0x3F1FFF +#define NTRKEY_PARAM 0x3F1FFFu void NTR_SendCommand(const u32 command[2], u32 pageSize, u32 latency, void* buffer); diff --git a/source/headers.h b/source/headers.h new file mode 100644 index 0000000..a350083 --- /dev/null +++ b/source/headers.h @@ -0,0 +1,75 @@ +#ifndef UNCART_HEADERS_H_ +#define UNCART_HEADERS_H_ + +#include "common.h" + +typedef enum +{ + MEDIA_6X_SAVE_CRYPTO = 1, + MEDIA_CARD_DEVICE = 3, + MEDIA_PLATFORM_INDEX = 4, + MEDIA_TYPE_INDEX = 5, + MEDIA_UNIT_SIZE = 6, + MEDIA_CARD_DEVICE_OLD = 7 +} NcsdFlagIndex; + +typedef struct +{ + u32 offset; + u32 size; +} partition_offsetsize; + +typedef struct +{ + u8 sha256[0x100]; + u8 magic[4]; + u32 media_size; + u8 title_id[8]; + u8 partitions_fs_type[8]; + u8 partitions_crypto_type[8]; + partition_offsetsize offsetsize_table[8]; + u8 exheader_hash[0x20]; + u8 additional_header_size[0x4]; + u8 sector_zero_offset[0x4]; + u8 partition_flags[8]; + u8 partition_id_table[8][8]; + u8 reserved[0x30]; +} NCSD_HEADER; + +typedef struct +{ + u8 sha256[0x100]; + u8 magic[4]; + u32 content_size; + u8 title_id[8]; + u8 maker_code[2]; + u8 version[2]; + u8 reserved_0[4]; + u8 program_id[8]; + u8 temp_flag; + u8 reserved_1[0xF]; + u8 logo_sha_256_hash[0x20]; + u8 product_code[0x10]; + u8 extended_header_sha_256_hash[0x20]; + u8 extended_header_size[4]; + u8 reserved_2[4]; + u8 flags[8]; + u8 plain_region_offset[4]; + u8 plain_region_size[4]; + u8 logo_region_offset[4]; + u8 logo_region_size[4]; + u8 exefs_offset[4]; + u8 exefs_size[4]; + u8 exefs_hash_size[4]; + u8 reserved_4[4]; + u8 romfs_offset[4]; + u8 romfs_size[4]; + u8 romfs_hash_size[4]; + u8 reserved_5[4]; + u8 exefs_sha_256_hash[0x20]; + u8 romfs_sha_256_hash[0x20]; +} __attribute__((__packed__)) +NCCH_HEADER; + +#endif//UNCART_HEADERS_H_ + diff --git a/source/i2c.c b/source/i2c.c index cd4d597..0e34042 100644 --- a/source/i2c.c +++ b/source/i2c.c @@ -3,7 +3,7 @@ //----------------------------------------------------------------------------- -static const struct { u8 bus_id, reg_addr } dev_data[] = { +static const struct { u8 bus_id, reg_addr; } dev_data[] = { {0, 0x4A}, {0, 0x7A}, {0, 0x78}, {1, 0x4A}, {1, 0x78}, {1, 0x2C}, {1, 0x2E}, {1, 0x40}, {1, 0x44}, @@ -11,35 +11,35 @@ static const struct { u8 bus_id, reg_addr } dev_data[] = { {2, 0xA4}, {2, 0x9A}, {2, 0xA0}, }; -const inline u8 i2cGetDeviceBusId(u8 device_id) { +inline u8 i2cGetDeviceBusId(u8 device_id) { return dev_data[device_id].bus_id; } -const inline u8 i2cGetDeviceRegAddr(u8 device_id) { +inline u8 i2cGetDeviceRegAddr(u8 device_id) { return dev_data[device_id].reg_addr; } //----------------------------------------------------------------------------- -static vu8* const reg_data_addrs[] = { +static vu8* reg_data_addrs[] = { (vu8*)(I2C1_REG_OFF + I2C_REG_DATA), (vu8*)(I2C2_REG_OFF + I2C_REG_DATA), (vu8*)(I2C3_REG_OFF + I2C_REG_DATA), }; -inline vu8* const i2cGetDataReg(u8 bus_id) { +inline vu8* i2cGetDataReg(u8 bus_id) { return reg_data_addrs[bus_id]; } //----------------------------------------------------------------------------- -static vu8* const reg_cnt_addrs[] = { +static vu8* reg_cnt_addrs[] = { (vu8*)(I2C1_REG_OFF + I2C_REG_CNT), (vu8*)(I2C2_REG_OFF + I2C_REG_CNT), (vu8*)(I2C3_REG_OFF + I2C_REG_CNT), }; -inline vu8* const i2cGetCntReg(u8 bus_id) { +inline vu8* i2cGetCntReg(u8 bus_id) { return reg_cnt_addrs[bus_id]; } @@ -114,7 +114,7 @@ bool i2cReadRegisterBuffer(unsigned int dev_id, int reg, u8* buffer, size_t buf_ } if (buf_size != 1) { - for (int i = 0; i < buf_size - 1; i++) { + for (size_t i = 0; i < buf_size - 1; i++) { i2cWaitBusy(bus_id); *i2cGetCntReg(bus_id) = 0xF0; i2cWaitBusy(bus_id); diff --git a/source/i2c.h b/source/i2c.h index f8511f6..4adeb1b 100644 --- a/source/i2c.h +++ b/source/i2c.h @@ -15,11 +15,11 @@ #define I2C_DEV_GYRO 10 #define I2C_DEV_IR 13 -const u8 i2cGetDeviceBusId(u8 device_id); -const u8 i2cGetDeviceRegAddr(u8 device_id); +u8 i2cGetDeviceBusId(u8 device_id); +u8 i2cGetDeviceRegAddr(u8 device_id); -vu8* const i2cGetDataReg(u8 bus_id); -vu8* const i2cGetCntReg(u8 bus_id); +vu8* i2cGetDataReg(u8 bus_id); +vu8* i2cGetCntReg(u8 bus_id); void i2cWaitBusy(u8 bus_id); bool i2cGetResult(u8 bus_id); @@ -33,3 +33,4 @@ u8 i2cReadRegister(u8 dev_id, u8 reg); bool i2cWriteRegister(u8 dev_id, u8 reg, u8 data); bool i2cReadRegisterBuffer(unsigned int dev_id, int reg, u8* buffer, size_t buf_size); + diff --git a/source/main.c b/source/main.c index d7f3db7..494250f 100644 --- a/source/main.c +++ b/source/main.c @@ -1,13 +1,15 @@ -#include -#include -#include - #include "draw.h" #include "hid.h" #include "i2c.h" #include "fatfs/ff.h" #include "gamecart/protocol.h" #include "gamecart/command_ctr.h" +#include "headers.h" + +#include +#include +#include +#include //For memalign extern s32 CartID; extern s32 CartID2; @@ -27,7 +29,7 @@ static void wait_key(void) { InputWait(); } -void Reboot() +static void Reboot() { i2cWriteRegister(I2C_DEV_MCU, 0x20, 1 << 2); while(true); @@ -41,8 +43,8 @@ struct Context { u32 media_unit; }; -int dump_cart_region(u32 start_sector, u32 end_sector, FIL* output_file, struct Context* ctx) { - const u32 read_size = 1 * 1024 * 1024 / ctx->media_unit; // 1MB +static int dump_cart_region(u32 start_sector, u32 end_sector, FIL* output_file, struct Context* ctx) { + u32 read_size = 1u * 1024 * 1024 / ctx->media_unit; // 1MiB default // Dump remaining data u32 current_sector = start_sector; @@ -54,6 +56,12 @@ int dump_cart_region(u32 start_sector, u32 end_sector, FIL* output_file, struct while (read_ptr < ctx->buffer + ctx->buffer_size && current_sector < end_sector) { Cart_Dummy(); Cart_Dummy(); + + // If there is less data to read than the current read_size, fix it + if (end_sector - current_sector < read_size) + { + read_size = end_sector - current_sector; + } CTR_CmdReadData(current_sector, ctx->media_unit, read_size, read_ptr); read_ptr += ctx->media_unit * read_size; current_sector += read_size; @@ -62,8 +70,8 @@ int dump_cart_region(u32 start_sector, u32 end_sector, FIL* output_file, struct u8* write_ptr = ctx->buffer; while (write_ptr < read_ptr) { unsigned int bytes_written = 0; - f_write(output_file, write_ptr, read_ptr - write_ptr, &bytes_written); - Debug("Wrote 0x%x bytes, e.g. %08x", bytes_written, *(u32*)write_ptr); + f_write(output_file, write_ptr, (size_t)(read_ptr - write_ptr), &bytes_written); + Debug("Wrote 0x%x bytes...", bytes_written); if (bytes_written == 0) { Debug("Writing failed! :( SD full?"); @@ -78,67 +86,118 @@ int dump_cart_region(u32 start_sector, u32 end_sector, FIL* output_file, struct } int main() { + // Saves the framebuffer information somewhere safe. + DrawInit(); + + // Arbitrary target buffer + // aligning to 32 bits in case other parts of the software assume alignment + const u32 target_buf_size = 16u * 1024u * 1024u; // 16MB + u32* const target = memalign(4, target_buf_size); + + u32* const ncchHeaderData = memalign(4, sizeof(NCCH_HEADER)); + NCCH_HEADER* const ncchHeader = (NCCH_HEADER*)ncchHeaderData; + + NCSD_HEADER* const ncsdHeader = (NCSD_HEADER*)target; restart_program: // Setup boring stuff - clear the screen, initialize SD output, etc... ClearTop(); - Debug("ROM dump tool v0.2"); + + Debug("Uncart: ROM dump tool v0.2"); Debug("Insert your game cart now."); wait_key(); - // Arbitrary target buffer - // TODO: This should be done in a nicer way ;) - u8* target = (u8*)0x22000000; - u32 target_buf_size = 16u * 1024u * 1024u; // 16MB - u8* header = (u8*)0x23000000; memset(target, 0, target_buf_size); // Clear our buffer - *(vu32*)0x10000020 = 0; // InitFS stuff - *(vu32*)0x10000020 = 0x340; // InitFS stuff - // ROM DUMPING CODE STARTS HERE Cart_Init(); Debug("Cart id is %08x", Cart_GetID()); - CTR_CmdReadHeader(header); - Debug("Done reading header: %08X :)...", *(u32*)&header[0x100]); + Debug("Reading NCCH header..."); + CTR_CmdReadHeader(ncchHeader); + Debug("Done reading NCCH header."); + + // Check that the NCCH header magic is there + if (strncmp((const char*)(ncchHeader->magic), "NCCH", 4)) { + Debug("NCCH magic not found in header!!!"); + Debug("Press A to continue anyway."); + if (!(InputWait() & BUTTON_A)) + goto restart_prompt; + } - // TODO: Check first header bytes for "NCCH" or other magic words u32 sec_keys[4]; - Cart_Secure_Init((u32*)header,sec_keys); - - const u32 mediaUnit = 0x200; // TODO: Read from cart + Cart_Secure_Init(ncchHeaderData, sec_keys); + // Guess 0x200 first for the media size. this will be set correctly once the cart header is read // Read out the header 0x0000-0x1000 Cart_Dummy(); - CTR_CmdReadData(0, mediaUnit, 0x1000 / mediaUnit, target); + Debug("Reading NCSD header..."); + CTR_CmdReadData(0, 0x200, 0x1000 / 0x200, target); + Debug("Done reading NCSD header."); - u32 NCSD_magic = *(u32*)(&target[0x100]); - u32 cartSize = *(u32*)(&target[0x104]); - Debug("Cart size: %llu MB", (u64)cartSize * (u64)mediaUnit / 1024ull / 1024ull); - if (NCSD_magic != 0x4453434E) { + // Check for NCSD magic + if (strncmp((const char*)(ncsdHeader->magic), "NCSD", 4)) { Debug("NCSD magic not found in header!!!"); Debug("Press A to continue anyway."); if (!(InputWait() & BUTTON_A)) goto restart_prompt; } + Debug("Uncart can either dump the entire ROM (including"); + Debug("empty space), or a trimmed version based on the"); + Debug("size of the cart partitions."); + Debug(""); + + u32 input; + do { + Debug("Press A to dump all of ROM, B for only the"); + Debug("trimmed version."); + input = InputWait(); + } + while (!(input & BUTTON_A) && !(input & BUTTON_B)); + + + const u32 mediaUnit = 0x200 * (1u << ncsdHeader->partition_flags[MEDIA_UNIT_SIZE]); //Correctly set the media unit size + + u32 cartSize; + // Maximum number of blocks in a single file + u32 file_max_blocks; + + if (input & BUTTON_B) { + // Calculate the actual size by counting the adding the size of each + // partition, plus the initial offset size is in media units + + // The 3DS carts have up to 8 partitions in their carts + cartSize = ncsdHeader->offsetsize_table[0].offset; + for(size_t i = 0; i < 8; i++) { + cartSize += ncsdHeader->offsetsize_table[i].size; + } + + Debug("Cart data size: %llu MB", (u64)cartSize * (u64)mediaUnit / 1024ull / 1024ull); + // Maximum number of blocks in a single file + file_max_blocks = 0xFFFFFFFFu / mediaUnit + mediaUnit; // 4GiB - 512 + } + else + { + cartSize = ncsdHeader->media_size; + // Maximum number of blocks in a single file + file_max_blocks = 0x80000000u / mediaUnit; // 2GiB + } + struct Context context = { - .buffer = target, + .buffer = (u8*)target, .buffer_size = target_buf_size, .cart_size = cartSize, .media_unit = mediaUnit, }; - // Maximum number of blocks in a single file - u32 file_max_blocks = 2u * 1024u * 1024u * 1024u / mediaUnit; // 2GB u32 current_part = 0; while (current_part * file_max_blocks < cartSize) { // Create output file char filename_buf[32]; char extension_digit = cartSize <= file_max_blocks ? 's' : '0' + current_part; - snprintf(filename_buf, sizeof(filename_buf), "/%.16s.3d%c", &header[0x150], extension_digit); + snprintf(filename_buf, sizeof(filename_buf), "/%.16s.3d%c", ncchHeader->product_code, extension_digit); Debug("Writing to file: \"%s\"", filename_buf); Debug("Change the SD card now and/or press a key."); Debug("(Or SELECT to cancel)"); @@ -172,8 +231,8 @@ restart_program: f_lseek(&file, 0x1000); unsigned int written = 0; // Fill the 0x1200-0x4000 unused area with 0xFF instead of random garbage. - memset(header + 0x200, 0xFF, 0x3000 - 0x200); - f_write(&file, header, 0x3000, &written); + memset((u8*)ncchHeaderData + 0x200, 0xFF, 0x3000 - 0x200); + f_write(&file, ncchHeader, 0x3000, &written); } Debug("Done!"); @@ -194,6 +253,9 @@ restart_prompt: if (!(InputWait() & BUTTON_B)) goto restart_program; + free(ncchHeaderData); + free(target); + Reboot(); return 0; } diff --git a/source/start.s b/source/start.s index cfbfba4..c143ddf 100644 --- a/source/start.s +++ b/source/start.s @@ -3,6 +3,7 @@ .extern main .align 4 .arm +.extern fake_heap_end @ used for heap setup by newlib used by devKitARM #define SIZE_32KB 0b01110 #define SIZE_128KB 0b10000 @@ -86,10 +87,30 @@ _enable_caches: pop {r4-r5, pc} +_fix_sdmc_mount: + @ Fix mounting of SDMC + ldr r0, =0x10000020 + mov r1, #0x340 + str r1, [r0] + mov pc, lr + +_setup_heap: + mov r0, #0x2000000 @ Setup a 32MiB heap + ldr r1, =__end__ @ grab the location of the end of the binary + add r0, r0, r1 + ldr r1, =fake_heap_end @ heap goes from end of program to this variable + str r0, [r1] + mov pc, lr + _init: push {r0-r12, lr} bl _enable_caches + + bl _fix_sdmc_mount + + bl _setup_heap + bl main mrc p15, 0, r4, c1, c0, 0