Merge pull request #21 from gemarcano/trim-cleanup
A9lh support, optional trim support, and cleanups
This commit is contained in:
commit
1577f365f6
46
Makefile
46
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 $@)
|
||||
|
||||
|
||||
|
108
source/aes.h
108
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
|
||||
|
@ -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) {
|
||||
|
@ -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, ...);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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 };
|
||||
|
@ -7,5 +7,5 @@
|
||||
#include "common.h"
|
||||
|
||||
void NTR_CmdReset(void);
|
||||
int NTR_CmdGetCartId(void);
|
||||
u32 NTR_CmdGetCartId(void);
|
||||
void NTR_CmdEnter16ByteMode(void);
|
||||
|
@ -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 <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#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 <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
75
source/headers.h
Normal file
75
source/headers.h
Normal file
@ -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_
|
||||
|
16
source/i2c.c
16
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);
|
||||
|
@ -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);
|
||||
|
||||
|
132
source/main.c
132
source/main.c
@ -1,13 +1,15 @@
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#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 <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <malloc.h> //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;
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user