Compare commits
70 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a11124a3d6 | ||
|
|
d2d6e786c7 | ||
|
|
a76c943c01 | ||
|
|
3c64a3a234 | ||
|
|
06060c67b5 | ||
|
|
0f64fd73ec | ||
|
|
2323528975 | ||
|
|
22b38a0f88 | ||
|
|
034c0f8d7c | ||
|
|
b4cd67cb8c | ||
|
|
be83d77187 | ||
|
|
615cf81a9f | ||
|
|
c60ef7fe82 | ||
|
|
fea5a111a9 | ||
|
|
7eebfd4f6a | ||
|
|
939965b5a0 | ||
|
|
a0334120a6 | ||
|
|
308417a48e | ||
|
|
85533411c9 | ||
|
|
6d4a84a325 | ||
|
|
89350b1edd | ||
|
|
9e58e4ed7a | ||
|
|
f8f4ecea27 | ||
|
|
e9449f86bf | ||
|
|
4fabe1f704 | ||
|
|
ef3ba896d5 | ||
|
|
649b160292 | ||
|
|
697bc74535 | ||
|
|
0e9ff44746 | ||
|
|
49d49e637a | ||
|
|
b3f0d13aa4 | ||
|
|
bd1547710e | ||
|
|
7479bf8092 | ||
|
|
d4d281bb9c | ||
|
|
68bf134017 | ||
|
|
c7b90f739f | ||
|
|
160bc36ae8 | ||
|
|
464bf1680c | ||
|
|
c51eaba18c | ||
|
|
7dbded99a2 | ||
|
|
6351e5b8c3 | ||
|
|
5a0f2e4dfc | ||
|
|
6d06ea6975 | ||
|
|
4180261f1f | ||
|
|
e882dd7aaf | ||
|
|
9e851d2dfd | ||
|
|
21a3edb150 | ||
|
|
3aacbd17ce | ||
|
|
6f8a9421ef | ||
|
|
bb437f6f7b | ||
|
|
0001f301f8 | ||
|
|
f7bbc4bfec | ||
|
|
a127a38438 | ||
|
|
16225b97d7 | ||
|
|
0587c14162 | ||
|
|
a181bba9f2 | ||
|
|
993e564fbb | ||
|
|
956829864c | ||
|
|
24186a7148 | ||
|
|
3475cfe1e6 | ||
|
|
6b64a10362 | ||
|
|
5e99fb3aa0 | ||
|
|
060d8e9945 | ||
|
|
1026471842 | ||
|
|
645208ec82 | ||
|
|
f4c48a64ca | ||
|
|
c80ac985fe | ||
|
|
ac9bdc7665 | ||
|
|
217d75024d | ||
|
|
12e5b4adb9 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,6 +1,7 @@
|
|||||||
out
|
out
|
||||||
build
|
build
|
||||||
loader/build
|
loader/build
|
||||||
|
screeninit/build
|
||||||
injector/build
|
injector/build
|
||||||
*.bin
|
*.bin
|
||||||
*.3dsx
|
*.3dsx
|
||||||
|
|||||||
81
Makefile
81
Makefile
@@ -1,5 +1,11 @@
|
|||||||
rwildcard = $(foreach d, $(wildcard $1*), $(filter $(subst *, %, $2), $d) $(call rwildcard, $d/, $2))
|
rwildcard = $(foreach d, $(wildcard $1*), $(filter $(subst *, %, $2), $d) $(call rwildcard, $d/, $2))
|
||||||
|
|
||||||
|
ifeq ($(strip $(DEVKITARM)),)
|
||||||
|
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
|
||||||
|
endif
|
||||||
|
|
||||||
|
include $(DEVKITARM)/3ds_rules
|
||||||
|
|
||||||
CC := arm-none-eabi-gcc
|
CC := arm-none-eabi-gcc
|
||||||
AS := arm-none-eabi-as
|
AS := arm-none-eabi-as
|
||||||
LD := arm-none-eabi-ld
|
LD := arm-none-eabi-ld
|
||||||
@@ -11,6 +17,7 @@ version := $(shell git describe --abbrev=0 --tags)
|
|||||||
dir_source := source
|
dir_source := source
|
||||||
dir_patches := patches
|
dir_patches := patches
|
||||||
dir_loader := loader
|
dir_loader := loader
|
||||||
|
dir_screeninit := screeninit
|
||||||
dir_injector := injector
|
dir_injector := injector
|
||||||
dir_mset := CakeHax
|
dir_mset := CakeHax
|
||||||
dir_ninjhax := CakeBrah
|
dir_ninjhax := CakeBrah
|
||||||
@@ -18,14 +25,15 @@ dir_build := build
|
|||||||
dir_out := out
|
dir_out := out
|
||||||
|
|
||||||
ASFLAGS := -mlittle-endian -mcpu=arm946e-s -march=armv5te
|
ASFLAGS := -mlittle-endian -mcpu=arm946e-s -march=armv5te
|
||||||
CFLAGS := -Wall -Wextra -MMD -MP -marm $(ASFLAGS) -fno-builtin -fshort-wchar -std=c11 -Wno-main -O2 -ffast-math
|
CFLAGS := -Wall -Wextra -MMD -MP -marm $(ASFLAGS) -fno-builtin -fshort-wchar -std=c11 -Wno-main -O2 -flto -ffast-math
|
||||||
CFLAGS += -DCONFIG_TITLE="\"$(name) $(version) configuration\""
|
LDFLAGS := -nostartfiles
|
||||||
FLAGS := name=$(name).dat dir_out=$(abspath $(dir_out)) ICON=$(abspath icon.png) APP_DESCRIPTION="Noob-friendly 3DS CFW." APP_AUTHOR="Reisyukaku/Aurora Wright" --no-print-directory
|
FLAGS := name=$(name).dat dir_out=$(abspath $(dir_out)) ICON=$(abspath icon.png) APP_DESCRIPTION="Noob-friendly 3DS CFW." APP_AUTHOR="Reisyukaku/Aurora Wright" --no-print-directory
|
||||||
|
|
||||||
objects_cfw = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \
|
objects = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \
|
||||||
$(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \
|
$(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \
|
||||||
$(call rwildcard, $(dir_source), *.s *.c)))
|
$(call rwildcard, $(dir_source), *.s *.c)))
|
||||||
|
|
||||||
|
bundled = $(dir_build)/patches.h $(dir_build)/loader.h $(dir_build)/screeninit.h
|
||||||
|
|
||||||
.PHONY: all
|
.PHONY: all
|
||||||
all: launcher a9lh ninjhax
|
all: launcher a9lh ninjhax
|
||||||
@@ -42,54 +50,67 @@ ninjhax: $(dir_out)/3ds/$(name)
|
|||||||
.PHONY: release
|
.PHONY: release
|
||||||
release: $(dir_out)/$(name).zip
|
release: $(dir_out)/$(name).zip
|
||||||
|
|
||||||
|
.PHONY: pathchanger
|
||||||
|
pathchanger: $(dir_out)/pathchanger
|
||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
clean:
|
clean:
|
||||||
@$(MAKE) $(FLAGS) -C $(dir_mset) clean
|
@$(MAKE) $(FLAGS) -C $(dir_mset) clean
|
||||||
@$(MAKE) $(FLAGS) -C $(dir_ninjhax) clean
|
@$(MAKE) $(FLAGS) -C $(dir_ninjhax) clean
|
||||||
@rm -rf $(dir_out) $(dir_build)
|
|
||||||
@$(MAKE) -C $(dir_loader) clean
|
@$(MAKE) -C $(dir_loader) clean
|
||||||
|
@$(MAKE) -C $(dir_screeninit) clean
|
||||||
@$(MAKE) -C $(dir_injector) clean
|
@$(MAKE) -C $(dir_injector) clean
|
||||||
|
@rm -rf $(dir_out) $(dir_build)
|
||||||
|
|
||||||
$(dir_out):
|
$(dir_out):
|
||||||
@mkdir -p "$(dir_out)/aurei/payloads"
|
@mkdir -p "$(dir_out)/aurei/payloads"
|
||||||
|
|
||||||
|
$(dir_out)/pathchanger: $(dir_out)
|
||||||
|
@cc pathchanger/pathchanger.c -o out/pathchanger
|
||||||
|
|
||||||
$(dir_out)/$(name).dat: $(dir_build)/main.bin $(dir_out)
|
$(dir_out)/$(name).dat: $(dir_build)/main.bin $(dir_out)
|
||||||
@$(MAKE) $(FLAGS) -C $(dir_mset) launcher
|
@$(MAKE) $(FLAGS) -C $(dir_mset) launcher
|
||||||
@dd if=$(dir_build)/main.bin of=$@ bs=512 seek=144
|
@dd if=$(dir_build)/main.bin of=$@ bs=512 seek=144
|
||||||
|
|
||||||
$(dir_out)/arm9loaderhax.bin: $(dir_build)/main.bin $(dir_out)
|
$(dir_out)/arm9loaderhax.bin: $(dir_build)/main.bin $(dir_out)
|
||||||
@cp -av $(dir_build)/main.bin $@
|
@cp -a $(dir_build)/main.bin $@
|
||||||
|
|
||||||
$(dir_out)/3ds/$(name): $(dir_out)
|
$(dir_out)/3ds/$(name): $(dir_out)
|
||||||
@mkdir -p "$(dir_out)/3ds/$(name)"
|
@mkdir -p "$@"
|
||||||
@$(MAKE) $(FLAGS) -C $(dir_ninjhax)
|
@$(MAKE) $(FLAGS) -C $(dir_ninjhax)
|
||||||
@mv $(dir_out)/$(name).3dsx $@
|
@mv $(dir_out)/$(name).3dsx $(dir_out)/$(name).smdh $@
|
||||||
@mv $(dir_out)/$(name).smdh $@
|
|
||||||
|
|
||||||
$(dir_out)/$(name).zip: launcher a9lh ninjhax
|
$(dir_out)/$(name).zip: launcher a9lh ninjhax
|
||||||
@cd $(dir_out) && zip -9 -r $(name) *
|
@cd "$(@D)" && zip -9 -r $(name) *
|
||||||
|
|
||||||
$(dir_build)/patches.h: $(dir_patches)/emunand.s $(dir_patches)/reboot.s $(dir_injector)/Makefile
|
|
||||||
@mkdir -p "$(dir_build)"
|
|
||||||
@armips $<
|
|
||||||
@armips $(word 2,$^)
|
|
||||||
@$(MAKE) -C $(dir_injector)
|
|
||||||
@mv emunand.bin reboot.bin $(dir_injector)/injector.cxi $(dir_build)
|
|
||||||
@bin2c -o $@ -n emunand $(dir_build)/emunand.bin -n reboot $(dir_build)/reboot.bin -n injector $(dir_build)/injector.cxi
|
|
||||||
|
|
||||||
$(dir_build)/loader.h: $(dir_loader)/Makefile
|
|
||||||
@$(MAKE) -C $(dir_loader)
|
|
||||||
@mv $(dir_loader)/loader.bin $(dir_build)
|
|
||||||
@bin2c -o $@ -n loader $(dir_build)/loader.bin
|
|
||||||
|
|
||||||
$(dir_build)/main.bin: $(dir_build)/main.elf
|
$(dir_build)/main.bin: $(dir_build)/main.elf
|
||||||
$(OC) -S -O binary $< $@
|
$(OC) -S -O binary $< $@
|
||||||
|
|
||||||
$(dir_build)/main.elf: $(objects_cfw)
|
$(dir_build)/main.elf: $(objects)
|
||||||
# FatFs requires libgcc for __aeabi_uidiv
|
$(CC) $(LDFLAGS) -T linker.ld $(OUTPUT_OPTION) $^
|
||||||
$(CC) -nostartfiles $(LDFLAGS) -T linker.ld $(OUTPUT_OPTION) $^
|
|
||||||
|
|
||||||
$(dir_build)/%.o: $(dir_source)/%.c $(dir_build)/patches.h $(dir_build)/loader.h
|
$(dir_build)/patches.h: $(dir_patches)/emunand.s $(dir_patches)/reboot.s $(dir_injector)/Makefile
|
||||||
|
@mkdir -p "$(@D)"
|
||||||
|
@armips $<
|
||||||
|
@armips $(word 2,$^)
|
||||||
|
@$(MAKE) -C $(dir_injector)
|
||||||
|
@mv emunand.bin reboot.bin $(dir_injector)/injector.cxi $(@D)
|
||||||
|
@bin2c -o $@ -n emunand $(@D)/emunand.bin -n reboot $(@D)/reboot.bin -n injector $(@D)/injector.cxi
|
||||||
|
|
||||||
|
$(dir_build)/loader.h: $(dir_loader)/Makefile
|
||||||
|
@$(MAKE) -C $(dir_loader)
|
||||||
|
@mv $(dir_loader)/loader.bin $(@D)
|
||||||
|
@bin2c -o $@ -n loader $(@D)/loader.bin
|
||||||
|
|
||||||
|
$(dir_build)/screeninit.h: $(dir_screeninit)/Makefile
|
||||||
|
@$(MAKE) -C $(dir_screeninit)
|
||||||
|
@mv $(dir_screeninit)/screeninit.bin $(@D)
|
||||||
|
@bin2c -o $@ -n screeninit $(@D)/screeninit.bin
|
||||||
|
|
||||||
|
$(dir_build)/memory.o : CFLAGS += -O3
|
||||||
|
$(dir_build)/config.o : CFLAGS += -DCONFIG_TITLE="\"$(name) $(version) configuration\""
|
||||||
|
|
||||||
|
$(dir_build)/%.o: $(dir_source)/%.c $(bundled)
|
||||||
@mkdir -p "$(@D)"
|
@mkdir -p "$(@D)"
|
||||||
$(COMPILE.c) $(OUTPUT_OPTION) $<
|
$(COMPILE.c) $(OUTPUT_OPTION) $<
|
||||||
|
|
||||||
@@ -99,9 +120,9 @@ $(dir_build)/%.o: $(dir_source)/%.s
|
|||||||
|
|
||||||
$(dir_build)/fatfs/%.o: $(dir_source)/fatfs/%.c
|
$(dir_build)/fatfs/%.o: $(dir_source)/fatfs/%.c
|
||||||
@mkdir -p "$(@D)"
|
@mkdir -p "$(@D)"
|
||||||
$(COMPILE.c) -mthumb -mthumb-interwork -Wno-unused-function $(OUTPUT_OPTION) $<
|
$(COMPILE.c) $(OUTPUT_OPTION) $<
|
||||||
|
|
||||||
$(dir_build)/fatfs/%.o: $(dir_source)/fatfs/%.s
|
$(dir_build)/fatfs/%.o: $(dir_source)/fatfs/%.s
|
||||||
@mkdir -p "$(@D)"
|
@mkdir -p "$(@D)"
|
||||||
$(COMPILE.s) -mthumb -mthumb-interwork $(OUTPUT_OPTION) $<
|
$(COMPILE.s) $(OUTPUT_OPTION) $<
|
||||||
include $(call rwildcard, $(dir_build), *.d)
|
include $(call rwildcard, $(dir_build), *.d)
|
||||||
|
|||||||
28
README.md
28
README.md
@@ -3,30 +3,14 @@
|
|||||||
|
|
||||||
**Compiling:**
|
**Compiling:**
|
||||||
|
|
||||||
You'll need armips and [bin2c](https://sourceforge.net/projects/bin2c/) added to your Path. [HERE](http://www91.zippyshare.com/v/ePGpjk9r/file.html) is a pre-compiled version of armips.
|
You'll need armips, [bin2c](https://sourceforge.net/projects/bin2c/), and a recent build of [makerom](https://github.com/profi200/Project_CTR) added to your PATH. [HERE](http://www91.zippyshare.com/v/ePGpjk9r/file.html) is a pre-compiled version of armips for Windows.
|
||||||
|
Then, just run "make" and everything should work!
|
||||||
|
You can find the compiled files in the 'out' folder.
|
||||||
|
|
||||||
Lastly, just run Make and everything should work!
|
**Setup / Usage / Features:**
|
||||||
|
|
||||||
Copy everything in 'out' folder to SD root and run!
|
See https://github.com/AuroraWright/AuReiNand/wiki
|
||||||
|
|
||||||
**Usage / Features:**
|
|
||||||
|
|
||||||
See https://github.com/Reisyukaku/ReiNand and http://gbatemp.net/threads/reinand-mod-o3ds-n3ds-sysnand.411110
|
|
||||||
|
|
||||||
The FIRMs you need are [HERE](http://www99.zippyshare.com/v/kEIiQl0x/file.html).
|
|
||||||
|
|
||||||
**Credits:**
|
**Credits:**
|
||||||
|
|
||||||
Rei as this is mostly his code.
|
See https://github.com/AuroraWright/AuReiNand/wiki/Credits
|
||||||
|
|
||||||
The offset to detect the console, and to calculate the O3DS NAND CTR are from Decrypt9.
|
|
||||||
|
|
||||||
tiniVi suggested me a way to detect a A9LH environment, and figured out screen deinit.
|
|
||||||
|
|
||||||
Delebile provided me with the FIRM writes blocking patch.
|
|
||||||
|
|
||||||
A skilled reverser gave me the new reboot patch.
|
|
||||||
|
|
||||||
The screen init code is from dark_samus, bil1s, Normmatt, delebile and everyone who contributed.
|
|
||||||
|
|
||||||
The code for printing to the screen is from CakesFW.
|
|
||||||
@@ -158,7 +158,7 @@ static Result load_code(u64 progid, prog_addrs_t *shared, u64 prog_handle, int i
|
|||||||
}
|
}
|
||||||
|
|
||||||
// patch
|
// patch
|
||||||
patch_code(progid, (u8 *)shared->text_addr, shared->total_size << 12);
|
patchCode(progid, (u8 *)shared->text_addr, shared->total_size << 12);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,17 +5,21 @@
|
|||||||
|
|
||||||
#ifndef PATH_MAX
|
#ifndef PATH_MAX
|
||||||
#define PATH_MAX 255
|
#define PATH_MAX 255
|
||||||
|
#define CONFIG(a) ((config >> (a + 16)) & 1)
|
||||||
|
#define MULTICONFIG(a) ((config >> (a * 2 + 6)) & 3)
|
||||||
|
#define BOOTCONFIG(a, b) ((config >> a) & b)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static u32 config = 0;
|
static u32 config = 0;
|
||||||
static u8 secureinfo[0x111] = {0};
|
static u8 secureInfo[0x111] = {0};
|
||||||
|
|
||||||
//Quick Search algorithm, adapted from http://igm.univ-mlv.fr/~lecroq/string/node19.html#SECTION00190
|
//Quick Search algorithm, adapted from http://igm.univ-mlv.fr/~lecroq/string/node19.html#SECTION00190
|
||||||
static u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSize){
|
static u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSize)
|
||||||
|
{
|
||||||
const u8 *patternc = (const u8 *)pattern;
|
const u8 *patternc = (const u8 *)pattern;
|
||||||
|
|
||||||
//Preprocessing
|
//Preprocessing
|
||||||
int table[256];
|
u32 table[256];
|
||||||
|
|
||||||
for(u32 i = 0; i < 256; ++i)
|
for(u32 i = 0; i < 256; ++i)
|
||||||
table[i] = patternSize + 1;
|
table[i] = patternSize + 1;
|
||||||
@@ -25,7 +29,8 @@ static u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSiz
|
|||||||
//Searching
|
//Searching
|
||||||
u32 j = 0;
|
u32 j = 0;
|
||||||
|
|
||||||
while(j <= size - patternSize){
|
while(j <= size - patternSize)
|
||||||
|
{
|
||||||
if(memcmp(patternc, startPos + j, patternSize) == 0)
|
if(memcmp(patternc, startPos + j, patternSize) == 0)
|
||||||
return startPos + j;
|
return startPos + j;
|
||||||
j += table[startPos[j + patternSize]];
|
j += table[startPos[j + patternSize]];
|
||||||
@@ -34,28 +39,31 @@ static u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSiz
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 patch_memory(u8 *start, u32 size, const void *pattern, u32 patsize, int offset, const void *replace, u32 repsize, u32 count){
|
static u32 patchMemory(u8 *start, u32 size, const void *pattern, u32 patSize, int offset, const void *replace, u32 repSize, u32 count)
|
||||||
|
{
|
||||||
u32 i;
|
u32 i;
|
||||||
|
|
||||||
for(i = 0; i < count; i++){
|
for(i = 0; i < count; i++)
|
||||||
u8 *found = memsearch(start, pattern, size, patsize);
|
{
|
||||||
if(found == NULL)
|
u8 *found = memsearch(start, pattern, size, patSize);
|
||||||
break;
|
|
||||||
|
|
||||||
memcpy(found + offset, replace, repsize);
|
if(found == NULL) break;
|
||||||
|
|
||||||
|
memcpy(found + offset, replace, repSize);
|
||||||
|
|
||||||
u32 at = (u32)(found - start);
|
u32 at = (u32)(found - start);
|
||||||
|
|
||||||
if(at + patsize > size) size = 0;
|
if(at + patSize > size) break;
|
||||||
else size = size - (at + patsize);
|
|
||||||
|
|
||||||
start = found + patsize;
|
size -= at + patSize;
|
||||||
|
start = found + patSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int file_open(IFile *file, FS_ArchiveID id, const char *path, int flags){
|
static int fileOpen(IFile *file, FS_ArchiveID id, const char *path, int flags)
|
||||||
|
{
|
||||||
FS_Archive archive;
|
FS_Archive archive;
|
||||||
FS_Path ppath;
|
FS_Path ppath;
|
||||||
|
|
||||||
@@ -66,209 +74,422 @@ static int file_open(IFile *file, FS_ArchiveID id, const char *path, int flags){
|
|||||||
archive.lowPath.data = (u8 *)"";
|
archive.lowPath.data = (u8 *)"";
|
||||||
ppath.type = PATH_ASCII;
|
ppath.type = PATH_ASCII;
|
||||||
ppath.data = path;
|
ppath.data = path;
|
||||||
ppath.size = len+1;
|
ppath.size = len + 1;
|
||||||
|
|
||||||
return IFile_Open(file, archive, ppath, flags);
|
return IFile_Open(file, archive, ppath, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int patch_secureinfo(){
|
static int loadSecureInfo(void)
|
||||||
IFile file;
|
{
|
||||||
Result ret;
|
if(secureInfo[0] == 0xFF)
|
||||||
u64 total;
|
|
||||||
|
|
||||||
if(secureinfo[0] == 0xFF)
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
ret = file_open(&file, ARCHIVE_SDMC, "/SecureInfo_A", FS_OPEN_READ);
|
IFile file;
|
||||||
if(R_SUCCEEDED(ret)){
|
Result ret = fileOpen(&file, ARCHIVE_NAND_RW, "/sys/SecureInfo_C", FS_OPEN_READ);
|
||||||
ret = IFile_Read(&file, &total, secureinfo, sizeof(secureinfo));
|
if(R_SUCCEEDED(ret))
|
||||||
|
{
|
||||||
|
u64 total;
|
||||||
|
|
||||||
|
ret = IFile_Read(&file, &total, secureInfo, 0x111);
|
||||||
IFile_Close(&file);
|
IFile_Close(&file);
|
||||||
if(R_SUCCEEDED(ret) && total == sizeof(secureinfo)){
|
if(R_SUCCEEDED(ret) && total == 0x111)
|
||||||
ret = file_open(&file, ARCHIVE_NAND_RW, "/sys/SecureInfo_C", FS_OPEN_WRITE | FS_OPEN_CREATE);
|
secureInfo[0] = 0xFF;
|
||||||
if(R_SUCCEEDED(ret)){
|
|
||||||
ret = IFile_Write(&file, &total, secureinfo, sizeof(secureinfo), FS_WRITE_FLUSH);
|
|
||||||
IFile_Close(&file);
|
|
||||||
}
|
|
||||||
secureinfo[0] = 0xFF; // we repurpose this byte as status
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else { // get file from NAND
|
|
||||||
ret = file_open(&file, ARCHIVE_NAND_RW, "/sys/SecureInfo_C", FS_OPEN_READ);
|
|
||||||
if(R_SUCCEEDED(ret)){
|
|
||||||
ret = IFile_Read(&file, &total, secureinfo, sizeof(secureinfo));
|
|
||||||
IFile_Close(&file);
|
|
||||||
if(R_SUCCEEDED(ret) && total == sizeof(secureinfo))
|
|
||||||
secureinfo[0] = 0xFF;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int open_config(){
|
static int loadConfig(void)
|
||||||
IFile file;
|
{
|
||||||
Result ret;
|
|
||||||
u64 total;
|
|
||||||
|
|
||||||
if(config)
|
if(config)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
ret = file_open(&file, ARCHIVE_SDMC, "/aurei/config.bin", FS_OPEN_READ);
|
IFile file;
|
||||||
if(R_SUCCEEDED(ret)){
|
Result ret = fileOpen(&file, ARCHIVE_SDMC, "/aurei/config.bin", FS_OPEN_READ);
|
||||||
ret = IFile_Read(&file, &total, (void *)&config, 3);
|
if(R_SUCCEEDED(ret))
|
||||||
|
{
|
||||||
|
u64 total;
|
||||||
|
|
||||||
|
ret = IFile_Read(&file, &total, &config, 4);
|
||||||
IFile_Close(&file);
|
IFile_Close(&file);
|
||||||
|
if(R_SUCCEEDED(ret)) config |= 1 << 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 patch_code(u64 progid, u8 *code, u32 size){
|
static int loadTitleLocaleConfig(u64 progId, u8 *regionId, u8 *languageId)
|
||||||
if( progid == 0x0004003000008F02LL || // USA Menu
|
{
|
||||||
progid == 0x0004003000008202LL || // JPN Menu
|
/* Here we look for "/aurei/locales/[u64 titleID in hex, uppercase].txt"
|
||||||
progid == 0x0004003000009802LL || // EUR Menu
|
If it exists it should contain, for example, "EUR IT" */
|
||||||
progid == 0x000400300000A102LL || // CHN Menu
|
|
||||||
progid == 0x000400300000A902LL || // KOR Menu
|
|
||||||
progid == 0x000400300000B102LL // TWN Menu
|
|
||||||
){
|
|
||||||
static const u8 regionFreePattern[] = {
|
|
||||||
0x00, 0x00, 0x55, 0xE3, 0x01, 0x10, 0xA0, 0xE3
|
|
||||||
};
|
|
||||||
static const u8 regionFreePatch[] = {
|
|
||||||
0x01, 0x00, 0xA0, 0xE3, 0x1E, 0xFF, 0x2F, 0xE1
|
|
||||||
};
|
|
||||||
|
|
||||||
patch_memory(code, size,
|
char path[] = "/aurei/locales/0000000000000000.txt";
|
||||||
regionFreePattern,
|
|
||||||
sizeof(regionFreePattern), -16,
|
u32 i = 30;
|
||||||
regionFreePatch,
|
|
||||||
sizeof(regionFreePatch), 1
|
while(progId > 0)
|
||||||
);
|
{
|
||||||
|
static const char hexDigits[] = "0123456789ABCDEF";
|
||||||
|
path[i--] = hexDigits[(u32)(progId & 0xF)];
|
||||||
|
progId >>= 4;
|
||||||
}
|
}
|
||||||
else if(progid == 0x0004013000002C02LL){ // NIM
|
|
||||||
static const u8 blockAutoUpdatesPattern[] = {
|
|
||||||
0x25, 0x79, 0x0B, 0x99
|
|
||||||
};
|
|
||||||
static const u8 blockAutoUpdatesPatch[] = {
|
|
||||||
0xE3, 0xA0
|
|
||||||
};
|
|
||||||
static const u8 blockEShopUpdateCheckPattern[] = {
|
|
||||||
0x30, 0xB5, 0xF1, 0xB0
|
|
||||||
};
|
|
||||||
static const u8 blockEShopUpdateCheckPatch[] = {
|
|
||||||
0x00, 0x20, 0x08, 0x60, 0x70, 0x47
|
|
||||||
};
|
|
||||||
static const u8 countryRespPattern[] = {
|
|
||||||
0x01, 0x20, 0x01, 0x90, 0x22, 0x46, 0x06, 0x9B
|
|
||||||
};
|
|
||||||
static const char countryRespPatchModel[] = {
|
|
||||||
0x06, 0x9A, 0x03, 0x20, 0x90, 0x47, 0x55, 0x21, 0x01, 0x70, 0x53, 0x21, 0x41, 0x70, 0x00, 0x21,
|
|
||||||
0x81, 0x70, 0x60, 0x61, 0x00, 0x20
|
|
||||||
};
|
|
||||||
const char *country;
|
|
||||||
char countryRespPatch[sizeof(countryRespPatchModel)];
|
|
||||||
|
|
||||||
patch_memory(code, size,
|
IFile file;
|
||||||
blockAutoUpdatesPattern,
|
Result ret = fileOpen(&file, ARCHIVE_SDMC, path, FS_OPEN_READ);
|
||||||
sizeof(blockAutoUpdatesPattern), 0,
|
if(R_SUCCEEDED(ret))
|
||||||
blockAutoUpdatesPatch,
|
{
|
||||||
sizeof(blockAutoUpdatesPatch), 1
|
char buf[6];
|
||||||
);
|
u64 total;
|
||||||
patch_memory(code, size,
|
|
||||||
blockEShopUpdateCheckPattern,
|
ret = IFile_Read(&file, &total, buf, 6);
|
||||||
sizeof(blockEShopUpdateCheckPattern), 0,
|
IFile_Close(&file);
|
||||||
blockEShopUpdateCheckPatch,
|
|
||||||
sizeof(blockEShopUpdateCheckPatch), 1
|
if(!R_SUCCEEDED(ret) || total < 6) return -1;
|
||||||
);
|
|
||||||
if(R_SUCCEEDED(patch_secureinfo())){
|
for(u32 i = 0; i < 7; ++i)
|
||||||
switch(secureinfo[0x100]){
|
{
|
||||||
case 1: country = "US"; break;
|
static const char *regions[] = {"JPN", "USA", "EUR", "AUS", "CHN", "KOR", "TWN"};
|
||||||
case 2: country = "GB"; break; // sorry rest-of-Europe, you have to change this
|
|
||||||
case 3: country = "AU"; break;
|
if(memcmp(buf, regions[i], 3) == 0)
|
||||||
case 4: country = "CN"; break;
|
{
|
||||||
case 5: country = "KR"; break;
|
*regionId = (u8)i;
|
||||||
case 6: country = "TW"; break;
|
break;
|
||||||
default: case 0: country = "JP"; break;
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(u32 i = 0; i < 12; ++i)
|
||||||
|
{
|
||||||
|
static const char *languages[] = {"JP", "EN", "FR", "DE", "IT", "ES", "ZH", "KO", "NL", "PT", "RU", "TW"};
|
||||||
|
|
||||||
|
if(memcmp(buf + 4, languages[i], 2) == 0)
|
||||||
|
{
|
||||||
|
*languageId = (u8)i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static u8 *getCfgOffsets(u8 *code, u32 size, u32 *CFGUHandleOffset)
|
||||||
|
{
|
||||||
|
/* HANS:
|
||||||
|
Look for error code which is known to be stored near cfg:u handle
|
||||||
|
this way we can find the right candidate
|
||||||
|
(handle should also be stored right after end of candidate function) */
|
||||||
|
|
||||||
|
u32 n = 0,
|
||||||
|
possible[24];
|
||||||
|
|
||||||
|
for(u8 *pos = code + 4; n < 24 && pos < code + size - 4; pos += 4)
|
||||||
|
{
|
||||||
|
if(*(u32 *)pos == 0xD8A103F9)
|
||||||
|
{
|
||||||
|
for(u32 *l = (u32 *)pos - 4; n < 24 && l < (u32 *)pos + 4; l++)
|
||||||
|
if(*l <= 0x10000000) possible[n++] = *l;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(u8 *CFGU_GetConfigInfoBlk2_endPos = code; CFGU_GetConfigInfoBlk2_endPos < code + size - 8; CFGU_GetConfigInfoBlk2_endPos += 4)
|
||||||
|
{
|
||||||
|
static const u32 CFGU_GetConfigInfoBlk2_endPattern[] = {0xE8BD8010, 0x00010082};
|
||||||
|
|
||||||
|
//There might be multiple implementations of GetConfigInfoBlk2 but let's search for the one we want
|
||||||
|
u32 *cmp = (u32 *)CFGU_GetConfigInfoBlk2_endPos;
|
||||||
|
|
||||||
|
if(cmp[0] == CFGU_GetConfigInfoBlk2_endPattern[0] && cmp[1] == CFGU_GetConfigInfoBlk2_endPattern[1])
|
||||||
|
{
|
||||||
|
*CFGUHandleOffset = *((u32 *)CFGU_GetConfigInfoBlk2_endPos + 2);
|
||||||
|
|
||||||
|
for(u32 i = 0; i < n; i++)
|
||||||
|
if(possible[i] == *CFGUHandleOffset) return CFGU_GetConfigInfoBlk2_endPos;
|
||||||
|
|
||||||
|
CFGU_GetConfigInfoBlk2_endPos += 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void patchCfgGetLanguage(u8 *code, u32 size, u8 languageId, u8 *CFGU_GetConfigInfoBlk2_endPos)
|
||||||
|
{
|
||||||
|
u8 *CFGU_GetConfigInfoBlk2_startPos; //Let's find STMFD SP (there might be a NOP before, but nevermind)
|
||||||
|
|
||||||
|
for(CFGU_GetConfigInfoBlk2_startPos = CFGU_GetConfigInfoBlk2_endPos - 4;
|
||||||
|
CFGU_GetConfigInfoBlk2_startPos >= code && *((u16 *)CFGU_GetConfigInfoBlk2_startPos + 1) != 0xE92D;
|
||||||
|
CFGU_GetConfigInfoBlk2_startPos -= 2);
|
||||||
|
|
||||||
|
for(u8 *languageBlkIdPos = code; languageBlkIdPos < code + size; languageBlkIdPos += 4)
|
||||||
|
{
|
||||||
|
if(*(u32 *)languageBlkIdPos == 0xA0002)
|
||||||
|
{
|
||||||
|
for(u8 *instr = languageBlkIdPos - 8; instr >= languageBlkIdPos - 0x1008 && instr >= code + 4; instr -= 4) //Should be enough
|
||||||
|
{
|
||||||
|
if(instr[3] == 0xEB) //We're looking for BL
|
||||||
|
{
|
||||||
|
u8 *calledFunction = instr;
|
||||||
|
u32 i = 0,
|
||||||
|
found;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
u32 low24 = (*(u32 *)calledFunction & 0x00FFFFFF) << 2;
|
||||||
|
u32 signMask = (u32)(-(low24 >> 25)) & 0xFC000000; //Sign extension
|
||||||
|
s32 offset = (s32)(low24 | signMask) + 8; //Branch offset + 8 for prefetch
|
||||||
|
|
||||||
|
calledFunction += offset;
|
||||||
|
|
||||||
|
found = calledFunction >= CFGU_GetConfigInfoBlk2_startPos - 4 && calledFunction <= CFGU_GetConfigInfoBlk2_endPos;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
while(i < 2 && !found && calledFunction[3] == 0xEA);
|
||||||
|
|
||||||
|
if(found)
|
||||||
|
{
|
||||||
|
*((u32 *)instr - 1) = 0xE3A00000 | languageId; // mov r0, sp => mov r0, =languageId
|
||||||
|
*(u32 *)instr = 0xE5CD0000; // bl CFGU_GetConfigInfoBlk2 => strb r0, [sp]
|
||||||
|
*((u32 *)instr + 1) = 0xE3B00000; // (1 or 2 instructions) => movs r0, 0 (result code)
|
||||||
|
|
||||||
|
//We're done
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void patchCfgGetRegion(u8 *code, u32 size, u8 regionId, u32 CFGUHandleOffset)
|
||||||
|
{
|
||||||
|
for(u8 *cmdPos = code; cmdPos < code + size - 28; cmdPos += 4)
|
||||||
|
{
|
||||||
|
static const u32 cfgSecureInfoGetRegionCmdPattern[] = {0xEE1D4F70, 0xE3A00802, 0xE5A40080};
|
||||||
|
|
||||||
|
u32 *cmp = (u32 *)cmdPos;
|
||||||
|
|
||||||
|
if(cmp[0] == cfgSecureInfoGetRegionCmdPattern[0] && cmp[1] == cfgSecureInfoGetRegionCmdPattern[1] &&
|
||||||
|
cmp[2] == cfgSecureInfoGetRegionCmdPattern[2] && *((u16 *)cmdPos + 7) == 0xE59F &&
|
||||||
|
*(u32 *)(cmdPos + 20 + *((u16 *)cmdPos + 6)) == CFGUHandleOffset)
|
||||||
|
{
|
||||||
|
*((u32 *)cmdPos + 4) = 0xE3A00000 | regionId; // mov r0, =regionId
|
||||||
|
*((u32 *)cmdPos + 5) = 0xE5C40008; // strb r0, [r4, 8]
|
||||||
|
*((u32 *)cmdPos + 6) = 0xE3B00000; // movs r0, 0 (result code) ('s' not needed but nvm)
|
||||||
|
*((u32 *)cmdPos + 7) = 0xE5840004; // str r0, [r4, 4]
|
||||||
|
|
||||||
|
//The remaining, not patched, function code will do the rest for us
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void patchCode(u64 progId, u8 *code, u32 size)
|
||||||
|
{
|
||||||
|
switch(progId)
|
||||||
|
{
|
||||||
|
case 0x0004003000008F02LL: // USA Menu
|
||||||
|
case 0x0004003000008202LL: // EUR Menu
|
||||||
|
case 0x0004003000009802LL: // JPN Menu
|
||||||
|
case 0x000400300000A102LL: // CHN Menu
|
||||||
|
case 0x000400300000A902LL: // KOR Menu
|
||||||
|
case 0x000400300000B102LL: // TWN Menu
|
||||||
|
{
|
||||||
|
static const u8 regionFreePattern[] = {
|
||||||
|
0x00, 0x00, 0x55, 0xE3, 0x01, 0x10, 0xA0, 0xE3
|
||||||
|
};
|
||||||
|
static const u8 regionFreePatch[] = {
|
||||||
|
0x01, 0x00, 0xA0, 0xE3, 0x1E, 0xFF, 0x2F, 0xE1
|
||||||
|
};
|
||||||
|
|
||||||
|
//Patch SMDH region checks
|
||||||
|
patchMemory(code, size,
|
||||||
|
regionFreePattern,
|
||||||
|
sizeof(regionFreePattern), -16,
|
||||||
|
regionFreePatch,
|
||||||
|
sizeof(regionFreePatch), 1
|
||||||
|
);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 0x0004013000002C02LL: // NIM
|
||||||
|
{
|
||||||
|
static const u8 blockAutoUpdatesPattern[] = {
|
||||||
|
0x25, 0x79, 0x0B, 0x99
|
||||||
|
};
|
||||||
|
static const u8 blockAutoUpdatesPatch[] = {
|
||||||
|
0xE3, 0xA0
|
||||||
|
};
|
||||||
|
static const u8 skipEshopUpdateCheckPattern[] = {
|
||||||
|
0x30, 0xB5, 0xF1, 0xB0
|
||||||
|
};
|
||||||
|
static const u8 skipEshopUpdateCheckPatch[] = {
|
||||||
|
0x00, 0x20, 0x08, 0x60, 0x70, 0x47
|
||||||
|
};
|
||||||
|
|
||||||
|
//Block silent auto-updates
|
||||||
|
patchMemory(code, size,
|
||||||
|
blockAutoUpdatesPattern,
|
||||||
|
sizeof(blockAutoUpdatesPattern), 0,
|
||||||
|
blockAutoUpdatesPatch,
|
||||||
|
sizeof(blockAutoUpdatesPatch), 1
|
||||||
|
);
|
||||||
|
|
||||||
|
//Skip update checks to access the EShop
|
||||||
|
patchMemory(code, size,
|
||||||
|
skipEshopUpdateCheckPattern,
|
||||||
|
sizeof(skipEshopUpdateCheckPattern), 0,
|
||||||
|
skipEshopUpdateCheckPatch,
|
||||||
|
sizeof(skipEshopUpdateCheckPatch), 1
|
||||||
|
);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 0x0004013000003202LL: // FRIENDS
|
||||||
|
{
|
||||||
|
static const u8 fpdVerPattern[] = {
|
||||||
|
0xE0, 0x1E, 0xFF, 0x2F, 0xE1, 0x01, 0x01, 0x01
|
||||||
|
};
|
||||||
|
|
||||||
|
u8 *fdpVer = memsearch(code, fpdVerPattern, size, sizeof(fpdVerPattern));
|
||||||
|
|
||||||
|
if(fdpVer != NULL)
|
||||||
|
{
|
||||||
|
fdpVer += sizeof(fpdVerPattern) + 1;
|
||||||
|
|
||||||
|
//Allow online access to work with old friends modules
|
||||||
|
if(*fdpVer < 5) *fdpVer = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
// patch XML response Country
|
break;
|
||||||
memcpy(countryRespPatch,
|
}
|
||||||
countryRespPatchModel,
|
|
||||||
sizeof(countryRespPatchModel)
|
case 0x0004001000021000LL: // USA MSET
|
||||||
|
case 0x0004001000020000LL: // JPN MSET
|
||||||
|
case 0x0004001000022000LL: // EUR MSET
|
||||||
|
case 0x0004001000026000LL: // CHN MSET
|
||||||
|
case 0x0004001000027000LL: // KOR MSET
|
||||||
|
case 0x0004001000028000LL: // TWN MSET
|
||||||
|
{
|
||||||
|
if(R_SUCCEEDED(loadConfig()) && CONFIG(6))
|
||||||
|
{
|
||||||
|
static const u16 verPattern[] = u"Ver.";
|
||||||
|
const u32 currentNand = BOOTCONFIG(0, 3);
|
||||||
|
const u32 matchingFirm = BOOTCONFIG(2, 1) == (currentNand != 0);
|
||||||
|
|
||||||
|
//Patch Ver. string
|
||||||
|
patchMemory(code, size,
|
||||||
|
verPattern,
|
||||||
|
sizeof(verPattern) - sizeof(u16), 0,
|
||||||
|
!currentNand ? ((matchingFirm) ? u" Sys" : u"SysE") :
|
||||||
|
((currentNand == 1) ? (matchingFirm ? u" Emu" : u"EmuS") : ((matchingFirm) ? u"Emu2" : u"Em2S")),
|
||||||
|
sizeof(verPattern) - sizeof(u16), 1
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 0x0004013000008002LL: // NS
|
||||||
|
{
|
||||||
|
static const u8 stopCartUpdatesPattern[] = {
|
||||||
|
0x0C, 0x18, 0xE1, 0xD8
|
||||||
|
};
|
||||||
|
static const u8 stopCartUpdatesPatch[] = {
|
||||||
|
0x0B, 0x18, 0x21, 0xC8
|
||||||
|
};
|
||||||
|
|
||||||
|
//Disable updates from foreign carts (makes carts region-free)
|
||||||
|
patchMemory(code, size,
|
||||||
|
stopCartUpdatesPattern,
|
||||||
|
sizeof(stopCartUpdatesPattern), 0,
|
||||||
|
stopCartUpdatesPatch,
|
||||||
|
sizeof(stopCartUpdatesPatch), 2
|
||||||
);
|
);
|
||||||
countryRespPatch[6] = country[0];
|
|
||||||
countryRespPatch[10] = country[1];
|
if(R_SUCCEEDED(loadConfig()) && MULTICONFIG(1))
|
||||||
patch_memory(code, size,
|
{
|
||||||
countryRespPattern,
|
static const u8 cfgN3dsCpuPattern[] = {
|
||||||
sizeof(countryRespPattern), 0,
|
0x40, 0xA0, 0xE1, 0x07, 0x00
|
||||||
countryRespPatch,
|
};
|
||||||
sizeof(countryRespPatch), 1
|
|
||||||
|
u8 *cfgN3dsCpuLoc = memsearch(code, cfgN3dsCpuPattern, size, sizeof(cfgN3dsCpuPattern));
|
||||||
|
|
||||||
|
//Patch N3DS CPU Clock and L2 cache setting
|
||||||
|
if(cfgN3dsCpuLoc != NULL)
|
||||||
|
{
|
||||||
|
*(u32 *)(cfgN3dsCpuLoc + 3) = 0xE1A00000;
|
||||||
|
*(u32 *)(cfgN3dsCpuLoc + 0x1F) = 0xE3A00000 | MULTICONFIG(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 0x0004013000001702LL: // CFG
|
||||||
|
{
|
||||||
|
static const u8 secureinfoSigCheckPattern[] = {
|
||||||
|
0x06, 0x46, 0x10, 0x48, 0xFC
|
||||||
|
};
|
||||||
|
static const u8 secureinfoSigCheckPatch[] = {
|
||||||
|
0x00, 0x26
|
||||||
|
};
|
||||||
|
|
||||||
|
//Disable SecureInfo signature check
|
||||||
|
patchMemory(code, size,
|
||||||
|
secureinfoSigCheckPattern,
|
||||||
|
sizeof(secureinfoSigCheckPattern), 0,
|
||||||
|
secureinfoSigCheckPatch,
|
||||||
|
sizeof(secureinfoSigCheckPatch), 1
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if(R_SUCCEEDED(loadSecureInfo()))
|
||||||
|
{
|
||||||
|
static const u16 secureinfoFilenamePattern[] = u"SecureInfo_";
|
||||||
|
static const u16 secureinfoFilenamePatch[] = u"C";
|
||||||
|
|
||||||
|
//Use SecureInfo_C
|
||||||
|
patchMemory(code, size,
|
||||||
|
secureinfoFilenamePattern,
|
||||||
|
sizeof(secureinfoFilenamePattern) - sizeof(u16),
|
||||||
|
sizeof(secureinfoFilenamePattern) - sizeof(u16),
|
||||||
|
secureinfoFilenamePatch,
|
||||||
|
sizeof(secureinfoFilenamePatch) - sizeof(u16), 2
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
if(R_SUCCEEDED(loadConfig()) && CONFIG(4))
|
||||||
|
{
|
||||||
|
u32 tidHigh = (progId & 0xFFFFFFF000000000LL) >> 0x24;
|
||||||
|
|
||||||
|
if(tidHigh == 0x0004000)
|
||||||
|
{
|
||||||
|
//Language emulation
|
||||||
|
u8 regionId = 0xFF,
|
||||||
|
languageId = 0xFF;
|
||||||
|
|
||||||
|
int ret = loadTitleLocaleConfig(progId, ®ionId, &languageId);
|
||||||
|
|
||||||
|
if(R_SUCCEEDED(ret))
|
||||||
|
{
|
||||||
|
u32 CFGUHandleOffset;
|
||||||
|
|
||||||
|
u8 *CFGU_GetConfigInfoBlk2_endPos = getCfgOffsets(code, size, &CFGUHandleOffset);
|
||||||
|
|
||||||
|
if(CFGU_GetConfigInfoBlk2_endPos != NULL)
|
||||||
|
{
|
||||||
|
if(languageId != 0xFF) patchCfgGetLanguage(code, size, languageId, CFGU_GetConfigInfoBlk2_endPos);
|
||||||
|
if(regionId != 0xFF) patchCfgGetRegion(code, size, regionId, CFGUHandleOffset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(
|
|
||||||
progid == 0x0004001000021000LL || // USA MSET
|
|
||||||
progid == 0x0004001000020000LL || // JPN MSET
|
|
||||||
progid == 0x0004001000022000LL || // EUR MSET
|
|
||||||
progid == 0x0004001000026000LL || // CHN MSET
|
|
||||||
progid == 0x0004001000027000LL || // KOR MSET
|
|
||||||
progid == 0x0004001000028000LL // TWN MSET
|
|
||||||
){
|
|
||||||
if(R_SUCCEEDED(open_config()) && ((config >> 5) & 0x1)){
|
|
||||||
static const u16 VerPattern[] = u"Ver.";
|
|
||||||
const u32 currentFirm = ((config >> 12) & 0x1);
|
|
||||||
const u32 currentNand = ((config >> 13) & 0x3);
|
|
||||||
|
|
||||||
patch_memory(code, size,
|
|
||||||
VerPattern,
|
|
||||||
sizeof(VerPattern) - sizeof(u16), 0,
|
|
||||||
currentNand ? ((currentNand == 1) ? ((currentFirm == 1) ? u" Emu" : u"Emu9") : u"Emu2") :
|
|
||||||
((currentFirm == 1) ? u" Sys" : u"Sys9"),
|
|
||||||
sizeof(VerPattern) - sizeof(u16), 1
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (progid == 0x0004013000008002LL){ // NS
|
|
||||||
static const u8 stopCartUpdatesPattern[] = {
|
|
||||||
0x0C, 0x18, 0xE1, 0xD8
|
|
||||||
};
|
|
||||||
static const u8 stopCartUpdatesPatch[] = {
|
|
||||||
0x0B, 0x18, 0x21, 0xC8
|
|
||||||
};
|
|
||||||
|
|
||||||
patch_memory(code, size,
|
|
||||||
stopCartUpdatesPattern,
|
|
||||||
sizeof(stopCartUpdatesPattern), 0,
|
|
||||||
stopCartUpdatesPatch,
|
|
||||||
sizeof(stopCartUpdatesPatch), 2
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else if(progid == 0x0004013000001702LL){ // CFG
|
|
||||||
static const u8 secureinfoSigCheckPattern[] = {
|
|
||||||
0x06, 0x46, 0x10, 0x48, 0xFC
|
|
||||||
};
|
|
||||||
static const u8 secureinfoSigCheckPatch[] = {
|
|
||||||
0x00, 0x26
|
|
||||||
};
|
|
||||||
static const u16 secureinfoFilenamePattern[] = u"SecureInfo_";
|
|
||||||
static const u16 secureinfoFilenamePatch[] = u"C";
|
|
||||||
|
|
||||||
// disable SecureInfo signature check
|
|
||||||
patch_memory(code, size,
|
|
||||||
secureinfoSigCheckPattern,
|
|
||||||
sizeof(secureinfoSigCheckPattern), 0,
|
|
||||||
secureinfoSigCheckPatch,
|
|
||||||
sizeof(secureinfoSigCheckPatch), 1
|
|
||||||
);
|
|
||||||
if(R_SUCCEEDED(patch_secureinfo())){
|
|
||||||
// use SecureInfo_C
|
|
||||||
patch_memory(code, size,
|
|
||||||
secureinfoFilenamePattern,
|
|
||||||
sizeof(secureinfoFilenamePattern) - sizeof(u16),
|
|
||||||
sizeof(secureinfoFilenamePattern) - sizeof(u16),
|
|
||||||
secureinfoFilenamePatch,
|
|
||||||
sizeof(secureinfoFilenamePatch) - sizeof(u16), 2
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
@@ -2,4 +2,4 @@
|
|||||||
|
|
||||||
#include <3ds/types.h>
|
#include <3ds/types.h>
|
||||||
|
|
||||||
u32 patch_code(u64 progid, u8 *code, u32 size);
|
void patchCode(u64 progId, u8 *code, u32 size);
|
||||||
149
loader/Makefile
149
loader/Makefile
@@ -1,6 +1,4 @@
|
|||||||
#---------------------------------------------------------------------------------
|
rwildcard = $(foreach d, $(wildcard $1*), $(filter $(subst *, %, $2), $d) $(call rwildcard, $d/, $2))
|
||||||
.SUFFIXES:
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
ifeq ($(strip $(DEVKITARM)),)
|
ifeq ($(strip $(DEVKITARM)),)
|
||||||
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
|
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
|
||||||
@@ -8,127 +6,50 @@ endif
|
|||||||
|
|
||||||
include $(DEVKITARM)/3ds_rules
|
include $(DEVKITARM)/3ds_rules
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
CC := arm-none-eabi-gcc
|
||||||
# TARGET is the name of the output
|
AS := arm-none-eabi-as
|
||||||
# BUILD is the directory where object files & intermediate files will be placed
|
LD := arm-none-eabi-ld
|
||||||
# SOURCES is a list of directories containing source code
|
OC := arm-none-eabi-objcopy
|
||||||
# DATA is a list of directories containing data files
|
|
||||||
# INCLUDES is a list of directories containing header files
|
|
||||||
# SPECS is the directory containing the important build and link files
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
export TARGET := $(shell basename $(CURDIR))
|
|
||||||
BUILD := build
|
|
||||||
SOURCES := source source/fatfs source/fatfs/sdmmc
|
|
||||||
DATA := data
|
|
||||||
INCLUDES := include source/fatfs source/fatfs/sdmmc
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
name := $(shell basename $(CURDIR))
|
||||||
# Setup some defines
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
dir_source := source
|
||||||
# options for code generation
|
dir_build := build
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
ARCH := -mthumb -mthumb-interwork
|
|
||||||
|
|
||||||
CFLAGS := -g -Wall -O2\
|
ASFLAGS := -mlittle-endian -mcpu=arm946e-s -march=armv5te
|
||||||
-march=armv5te -mtune=arm946e-s\
|
CFLAGS := -Wall -Wextra -MMD -MP -marm $(ASFLAGS) -fno-builtin -std=c11 -Wno-main -O2 -flto -ffast-math -mthumb -mthumb-interwork
|
||||||
-ffast-math -Wno-main -std=c99\
|
LDFLAGS := -nostartfiles
|
||||||
$(ARCH)
|
|
||||||
|
|
||||||
CFLAGS += $(INCLUDE) -DARM9
|
objects = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \
|
||||||
|
$(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \
|
||||||
|
$(call rwildcard, $(dir_source), *.s *.c)))
|
||||||
|
|
||||||
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions
|
.PHONY: all
|
||||||
|
all: $(name).bin
|
||||||
|
|
||||||
ASFLAGS := -g $(ARCH)
|
.PHONY: clean
|
||||||
LDFLAGS = -nostartfiles -g --specs=../stub.specs $(ARCH) -Wl,-Map,$(TARGET).map
|
|
||||||
|
|
||||||
LIBS :=
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
# list of directories containing libraries, this must be the top level containing
|
|
||||||
# include and lib
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
LIBDIRS :=
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
# no real need to edit anything past this point unless you need to add additional
|
|
||||||
# rules for different file extensions
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
ifneq ($(BUILD),$(notdir $(CURDIR)))
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
export OUTPUT := $(CURDIR)/$(TARGET)
|
|
||||||
|
|
||||||
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
|
|
||||||
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
|
|
||||||
|
|
||||||
export DEPSDIR := $(CURDIR)/$(BUILD)
|
|
||||||
|
|
||||||
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
|
|
||||||
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
|
|
||||||
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
|
|
||||||
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
# use CXX for linking C++ projects, CC for standard C
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
ifeq ($(strip $(CPPFILES)),)
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
export LD := $(CC)
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
else
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
export LD := $(CXX)
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
endif
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
export OFILES := $(addsuffix .o,$(BINFILES)) \
|
|
||||||
$(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
|
|
||||||
|
|
||||||
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
|
|
||||||
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
|
|
||||||
-I$(CURDIR)/$(BUILD)
|
|
||||||
|
|
||||||
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
|
|
||||||
|
|
||||||
.PHONY: $(BUILD) clean all
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
all: $(BUILD)
|
|
||||||
|
|
||||||
$(BUILD):
|
|
||||||
@[ -d $@ ] || mkdir -p $@
|
|
||||||
@make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
clean:
|
clean:
|
||||||
@echo clean ...
|
@rm -rf $(dir_build)
|
||||||
@rm -fr $(BUILD) $(OUTPUT).elf
|
|
||||||
|
|
||||||
|
$(name).bin: $(dir_build)/$(name).elf
|
||||||
|
$(OC) -S -O binary $< $@
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
$(dir_build)/$(name).elf: $(objects)
|
||||||
else
|
$(CC) $(LDFLAGS) -T linker.ld $(OUTPUT_OPTION) $^
|
||||||
|
|
||||||
DEPENDS := $(OFILES:.o=.d)
|
$(dir_build)/%.o: $(dir_source)/%.c
|
||||||
|
@mkdir -p "$(@D)"
|
||||||
|
$(COMPILE.c) $(OUTPUT_OPTION) $<
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
$(dir_build)/%.o: $(dir_source)/%.s
|
||||||
# main targets
|
@mkdir -p "$(@D)"
|
||||||
#---------------------------------------------------------------------------------
|
$(COMPILE.s) $(OUTPUT_OPTION) $<
|
||||||
$(OUTPUT).bin : $(OUTPUT).elf
|
|
||||||
$(OUTPUT).elf : $(OFILES)
|
|
||||||
|
|
||||||
|
$(dir_build)/fatfs/%.o: $(dir_source)/fatfs/%.c
|
||||||
|
@mkdir -p "$(@D)"
|
||||||
|
$(COMPILE.c) $(OUTPUT_OPTION) $<
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
$(dir_build)/fatfs/%.o: $(dir_source)/fatfs/%.s
|
||||||
%.bin: %.elf
|
@mkdir -p "$(@D)"
|
||||||
@$(OBJCOPY) -O binary $< $@
|
$(COMPILE.s) $(OUTPUT_OPTION) $<
|
||||||
@echo built ... $(notdir $@)
|
include $(call rwildcard, $(dir_build), *.d)
|
||||||
|
|
||||||
|
|
||||||
-include $(DEPENDS)
|
|
||||||
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------------
|
|
||||||
endif
|
|
||||||
#---------------------------------------------------------------------------------------
|
|
||||||
|
|||||||
@@ -9,4 +9,3 @@ SECTIONS
|
|||||||
.rodata : { *(.rodata) }
|
.rodata : { *(.rodata) }
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2,13 +2,12 @@
|
|||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
#define HID_PAD (*(vu16 *)0x10146000 ^ 0xFFF)
|
#define HID_PAD (*(vu32 *)0x10146000 ^ 0xFFF)
|
||||||
#define BUTTON_B (1 << 1)
|
|
||||||
#define BUTTON_X (1 << 10)
|
|
||||||
#define BUTTON_Y (1 << 11)
|
|
||||||
#define BUTTON_SELECT (1 << 2)
|
|
||||||
#define BUTTON_START (1 << 3)
|
|
||||||
#define BUTTON_RIGHT (1 << 4)
|
#define BUTTON_RIGHT (1 << 4)
|
||||||
#define BUTTON_LEFT (1 << 5)
|
#define BUTTON_LEFT (1 << 5)
|
||||||
#define BUTTON_UP (1 << 6)
|
#define BUTTON_UP (1 << 6)
|
||||||
#define BUTTON_DOWN (1 << 7)
|
#define BUTTON_DOWN (1 << 7)
|
||||||
|
#define BUTTON_X (1 << 10)
|
||||||
|
#define BUTTON_Y (1 << 11)
|
||||||
|
#define BUTTON_R1 (1 << 8)
|
||||||
|
#define BUTTON_SELECT (1 << 2)
|
||||||
65
loader/source/fatfs/history.txt → loader/source/fatfs/00history.txt
Normal file → Executable file
65
loader/source/fatfs/history.txt → loader/source/fatfs/00history.txt
Normal file → Executable file
@@ -3,73 +3,98 @@
|
|||||||
----------------------------------------------------------------------------
|
----------------------------------------------------------------------------
|
||||||
|
|
||||||
R0.00 (February 26, 2006)
|
R0.00 (February 26, 2006)
|
||||||
|
|
||||||
Prototype.
|
Prototype.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
R0.01 (April 29, 2006)
|
R0.01 (April 29, 2006)
|
||||||
|
|
||||||
First stable version.
|
First stable version.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
R0.02 (June 01, 2006)
|
R0.02 (June 01, 2006)
|
||||||
|
|
||||||
Added FAT12 support.
|
Added FAT12 support.
|
||||||
Removed unbuffered mode.
|
Removed unbuffered mode.
|
||||||
Fixed a problem on small (<32M) partition.
|
Fixed a problem on small (<32M) partition.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
R0.02a (June 10, 2006)
|
R0.02a (June 10, 2006)
|
||||||
|
|
||||||
Added a configuration option (_FS_MINIMUM).
|
Added a configuration option (_FS_MINIMUM).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
R0.03 (September 22, 2006)
|
R0.03 (September 22, 2006)
|
||||||
|
|
||||||
Added f_rename().
|
Added f_rename().
|
||||||
Changed option _FS_MINIMUM to _FS_MINIMIZE.
|
Changed option _FS_MINIMUM to _FS_MINIMIZE.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
R0.03a (December 11, 2006)
|
R0.03a (December 11, 2006)
|
||||||
|
|
||||||
Improved cluster scan algorithm to write files fast.
|
Improved cluster scan algorithm to write files fast.
|
||||||
Fixed f_mkdir() creates incorrect directory on FAT32.
|
Fixed f_mkdir() creates incorrect directory on FAT32.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
R0.04 (February 04, 2007)
|
R0.04 (February 04, 2007)
|
||||||
|
|
||||||
Added f_mkfs().
|
Added f_mkfs().
|
||||||
Supported multiple drive system.
|
Supported multiple drive system.
|
||||||
Changed some interfaces for multiple drive system.
|
Changed some interfaces for multiple drive system.
|
||||||
Changed f_mountdrv() to f_mount().
|
Changed f_mountdrv() to f_mount().
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
R0.04a (April 01, 2007)
|
R0.04a (April 01, 2007)
|
||||||
|
|
||||||
Supported multiple partitions on a physical drive.
|
Supported multiple partitions on a physical drive.
|
||||||
Added a capability of extending file size to f_lseek().
|
Added a capability of extending file size to f_lseek().
|
||||||
Added minimization level 3.
|
Added minimization level 3.
|
||||||
Fixed an endian sensitive code in f_mkfs().
|
Fixed an endian sensitive code in f_mkfs().
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
R0.04b (May 05, 2007)
|
R0.04b (May 05, 2007)
|
||||||
|
|
||||||
Added a configuration option _USE_NTFLAG.
|
Added a configuration option _USE_NTFLAG.
|
||||||
Added FSINFO support.
|
Added FSINFO support.
|
||||||
Fixed DBCS name can result FR_INVALID_NAME.
|
Fixed DBCS name can result FR_INVALID_NAME.
|
||||||
Fixed short seek (<= csize) collapses the file object.
|
Fixed short seek (<= csize) collapses the file object.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
R0.05 (August 25, 2007)
|
R0.05 (August 25, 2007)
|
||||||
|
|
||||||
Changed arguments of f_read(), f_write() and f_mkfs().
|
Changed arguments of f_read(), f_write() and f_mkfs().
|
||||||
Fixed f_mkfs() on FAT32 creates incorrect FSINFO.
|
Fixed f_mkfs() on FAT32 creates incorrect FSINFO.
|
||||||
Fixed f_mkdir() on FAT32 creates incorrect directory.
|
Fixed f_mkdir() on FAT32 creates incorrect directory.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
R0.05a (February 03, 2008)
|
R0.05a (February 03, 2008)
|
||||||
|
|
||||||
Added f_truncate() and f_utime().
|
Added f_truncate() and f_utime().
|
||||||
Fixed off by one error at FAT sub-type determination.
|
Fixed off by one error at FAT sub-type determination.
|
||||||
Fixed btr in f_read() can be mistruncated.
|
Fixed btr in f_read() can be mistruncated.
|
||||||
Fixed cached sector is not flushed when create and close without write.
|
Fixed cached sector is not flushed when create and close without write.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
R0.06 (April 01, 2008)
|
R0.06 (April 01, 2008)
|
||||||
|
|
||||||
Added fputc(), fputs(), fprintf() and fgets().
|
Added fputc(), fputs(), fprintf() and fgets().
|
||||||
Improved performance of f_lseek() on moving to the same or following cluster.
|
Improved performance of f_lseek() on moving to the same or following cluster.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
R0.07 (April 01, 2009)
|
R0.07 (April 01, 2009)
|
||||||
|
|
||||||
Merged Tiny-FatFs as a configuration option. (_FS_TINY)
|
Merged Tiny-FatFs as a configuration option. (_FS_TINY)
|
||||||
Added long file name feature. (_USE_LFN)
|
Added long file name feature. (_USE_LFN)
|
||||||
Added multiple code page feature. (_CODE_PAGE)
|
Added multiple code page feature. (_CODE_PAGE)
|
||||||
@@ -80,12 +105,16 @@ R0.07 (April 01, 2009)
|
|||||||
Renamed string functions to avoid name collision.
|
Renamed string functions to avoid name collision.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
R0.07a (April 14, 2009)
|
R0.07a (April 14, 2009)
|
||||||
|
|
||||||
Septemberarated out OS dependent code on reentrant cfg.
|
Septemberarated out OS dependent code on reentrant cfg.
|
||||||
Added multiple sector size feature.
|
Added multiple sector size feature.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
R0.07c (June 21, 2009)
|
R0.07c (June 21, 2009)
|
||||||
|
|
||||||
Fixed f_unlink() can return FR_OK on error.
|
Fixed f_unlink() can return FR_OK on error.
|
||||||
Fixed wrong cache control in f_lseek().
|
Fixed wrong cache control in f_lseek().
|
||||||
Added relative path feature.
|
Added relative path feature.
|
||||||
@@ -93,7 +122,9 @@ R0.07c (June 21, 2009)
|
|||||||
Added proper case conversion to extended character.
|
Added proper case conversion to extended character.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
R0.07e (November 03, 2009)
|
R0.07e (November 03, 2009)
|
||||||
|
|
||||||
Septemberarated out configuration options from ff.h to ffconf.h.
|
Septemberarated out configuration options from ff.h to ffconf.h.
|
||||||
Fixed f_unlink() fails to remove a sub-directory on _FS_RPATH.
|
Fixed f_unlink() fails to remove a sub-directory on _FS_RPATH.
|
||||||
Fixed name matching error on the 13 character boundary.
|
Fixed name matching error on the 13 character boundary.
|
||||||
@@ -101,7 +132,9 @@ R0.07e (November 03, 2009)
|
|||||||
Changed f_readdir() to return the SFN with always upper case on non-LFN cfg.
|
Changed f_readdir() to return the SFN with always upper case on non-LFN cfg.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
R0.08 (May 15, 2010)
|
R0.08 (May 15, 2010)
|
||||||
|
|
||||||
Added a memory configuration option. (_USE_LFN = 3)
|
Added a memory configuration option. (_USE_LFN = 3)
|
||||||
Added file lock feature. (_FS_SHARE)
|
Added file lock feature. (_FS_SHARE)
|
||||||
Added fast seek feature. (_USE_FASTSEEK)
|
Added fast seek feature. (_USE_FASTSEEK)
|
||||||
@@ -110,36 +143,48 @@ R0.08 (May 15, 2010)
|
|||||||
String functions support UTF-8 encoding files on Unicode cfg.
|
String functions support UTF-8 encoding files on Unicode cfg.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
R0.08a (August 16, 2010)
|
R0.08a (August 16, 2010)
|
||||||
|
|
||||||
Added f_getcwd(). (_FS_RPATH = 2)
|
Added f_getcwd(). (_FS_RPATH = 2)
|
||||||
Added sector erase feature. (_USE_ERASE)
|
Added sector erase feature. (_USE_ERASE)
|
||||||
Moved file lock semaphore table from fs object to the bss.
|
Moved file lock semaphore table from fs object to the bss.
|
||||||
Fixed f_mkfs() creates wrong FAT32 volume.
|
Fixed f_mkfs() creates wrong FAT32 volume.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
R0.08b (January 15, 2011)
|
R0.08b (January 15, 2011)
|
||||||
|
|
||||||
Fast seek feature is also applied to f_read() and f_write().
|
Fast seek feature is also applied to f_read() and f_write().
|
||||||
f_lseek() reports required table size on creating CLMP.
|
f_lseek() reports required table size on creating CLMP.
|
||||||
Extended format syntax of f_printf().
|
Extended format syntax of f_printf().
|
||||||
Ignores duplicated directory separators in given path name.
|
Ignores duplicated directory separators in given path name.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
R0.09 (September 06, 2011)
|
R0.09 (September 06, 2011)
|
||||||
|
|
||||||
f_mkfs() supports multiple partition to complete the multiple partition feature.
|
f_mkfs() supports multiple partition to complete the multiple partition feature.
|
||||||
Added f_fdisk().
|
Added f_fdisk().
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
R0.09a (August 27, 2012)
|
R0.09a (August 27, 2012)
|
||||||
|
|
||||||
Changed f_open() and f_opendir() reject null object pointer to avoid crash.
|
Changed f_open() and f_opendir() reject null object pointer to avoid crash.
|
||||||
Changed option name _FS_SHARE to _FS_LOCK.
|
Changed option name _FS_SHARE to _FS_LOCK.
|
||||||
Fixed assertion failure due to OS/2 EA on FAT12/16 volume.
|
Fixed assertion failure due to OS/2 EA on FAT12/16 volume.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
R0.09b (January 24, 2013)
|
R0.09b (January 24, 2013)
|
||||||
|
|
||||||
Added f_setlabel() and f_getlabel().
|
Added f_setlabel() and f_getlabel().
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
R0.10 (October 02, 2013)
|
R0.10 (October 02, 2013)
|
||||||
|
|
||||||
Added selection of character encoding on the file. (_STRF_ENCODE)
|
Added selection of character encoding on the file. (_STRF_ENCODE)
|
||||||
Added f_closedir().
|
Added f_closedir().
|
||||||
Added forced full FAT scan for f_getfree(). (_FS_NOFSINFO)
|
Added forced full FAT scan for f_getfree(). (_FS_NOFSINFO)
|
||||||
@@ -151,7 +196,9 @@ R0.10 (October 02, 2013)
|
|||||||
Fixed f_open(), f_mkdir() and f_setlabel() can return incorrect error code.
|
Fixed f_open(), f_mkdir() and f_setlabel() can return incorrect error code.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
R0.10a (January 15, 2014)
|
R0.10a (January 15, 2014)
|
||||||
|
|
||||||
Added arbitrary strings as drive number in the path name. (_STR_VOLUME_ID)
|
Added arbitrary strings as drive number in the path name. (_STR_VOLUME_ID)
|
||||||
Added a configuration option of minimum sector size. (_MIN_SS)
|
Added a configuration option of minimum sector size. (_MIN_SS)
|
||||||
2nd argument of f_rename() can have a drive number and it will be ignored.
|
2nd argument of f_rename() can have a drive number and it will be ignored.
|
||||||
@@ -161,12 +208,16 @@ R0.10a (January 15, 2014)
|
|||||||
Fixed creation of an entry with LFN fails on too many SFN collisions. (appeared at R0.07)
|
Fixed creation of an entry with LFN fails on too many SFN collisions. (appeared at R0.07)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
R0.10b (May 19, 2014)
|
R0.10b (May 19, 2014)
|
||||||
|
|
||||||
Fixed a hard error in the disk I/O layer can collapse the directory entry.
|
Fixed a hard error in the disk I/O layer can collapse the directory entry.
|
||||||
Fixed LFN entry is not deleted on delete/rename an object with lossy converted SFN. (appeared at R0.07)
|
Fixed LFN entry is not deleted on delete/rename an object with lossy converted SFN. (appeared at R0.07)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
R0.10c (November 09, 2014)
|
R0.10c (November 09, 2014)
|
||||||
|
|
||||||
Added a configuration option for the platforms without RTC. (_FS_NORTC)
|
Added a configuration option for the platforms without RTC. (_FS_NORTC)
|
||||||
Changed option name _USE_ERASE to _USE_TRIM.
|
Changed option name _USE_ERASE to _USE_TRIM.
|
||||||
Fixed volume label created by Mac OS X cannot be retrieved with f_getlabel(). (appeared at R0.09b)
|
Fixed volume label created by Mac OS X cannot be retrieved with f_getlabel(). (appeared at R0.09b)
|
||||||
@@ -174,7 +225,21 @@ R0.10c (November 09, 2014)
|
|||||||
Fixed null pointer dereference on attempting to delete the root direcotry. (appeared at R0.08)
|
Fixed null pointer dereference on attempting to delete the root direcotry. (appeared at R0.08)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
R0.11 (February 09, 2015)
|
R0.11 (February 09, 2015)
|
||||||
|
|
||||||
Added f_findfirst(), f_findnext() and f_findclose(). (_USE_FIND)
|
Added f_findfirst(), f_findnext() and f_findclose(). (_USE_FIND)
|
||||||
Fixed f_unlink() does not remove cluster chain of the file. (appeared at R0.10c)
|
Fixed f_unlink() does not remove cluster chain of the file. (appeared at R0.10c)
|
||||||
Fixed _FS_NORTC option does not work properly. (appeared at R0.10c)
|
Fixed _FS_NORTC option does not work properly. (appeared at R0.10c)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
R0.11a (September 05, 2015)
|
||||||
|
|
||||||
|
Fixed wrong media change can lead a deadlock at thread-safe configuration.
|
||||||
|
Added code page 771, 860, 861, 863, 864, 865 and 869. (_CODE_PAGE)
|
||||||
|
Removed some code pages actually not exist on the standard systems. (_CODE_PAGE)
|
||||||
|
Fixed errors in the case conversion teble of code page 437 and 850 (ff.c).
|
||||||
|
Fixed errors in the case conversion teble of Unicode (cc*.c).
|
||||||
|
|
||||||
|
|
||||||
@@ -35,6 +35,7 @@ DSTATUS disk_initialize (
|
|||||||
)
|
)
|
||||||
{
|
{
|
||||||
sdmmc_sdcard_init();
|
sdmmc_sdcard_init();
|
||||||
|
|
||||||
return RES_OK;
|
return RES_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,9 +53,8 @@ DRESULT disk_read (
|
|||||||
UINT count /* Number of sectors to read */
|
UINT count /* Number of sectors to read */
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if (sdmmc_sdcard_readsectors(sector, count, buff)) {
|
if(sdmmc_sdcard_readsectors(sector, count, buff))
|
||||||
return RES_PARERR;
|
return RES_PARERR;
|
||||||
}
|
|
||||||
|
|
||||||
return RES_OK;
|
return RES_OK;
|
||||||
}
|
}
|
||||||
@@ -74,9 +74,8 @@ DRESULT disk_write (
|
|||||||
UINT count /* Number of sectors to write */
|
UINT count /* Number of sectors to write */
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if (sdmmc_sdcard_writesectors(sector, count, (BYTE *)buff)) {
|
if(sdmmc_sdcard_writesectors(sector, count, (BYTE *)buff))
|
||||||
return RES_PARERR;
|
return RES_PARERR;
|
||||||
}
|
|
||||||
|
|
||||||
return RES_OK;
|
return RES_OK;
|
||||||
}
|
}
|
||||||
|
|||||||
565
loader/source/fatfs/ff.c
Normal file → Executable file
565
loader/source/fatfs/ff.c
Normal file → Executable file
File diff suppressed because it is too large
Load Diff
6
loader/source/fatfs/ff.h
Normal file → Executable file
6
loader/source/fatfs/ff.h
Normal file → Executable file
@@ -1,5 +1,5 @@
|
|||||||
/*---------------------------------------------------------------------------/
|
/*---------------------------------------------------------------------------/
|
||||||
/ FatFs - FAT file system module include R0.11 (C)ChaN, 2015
|
/ FatFs - FAT file system module include R0.11a (C)ChaN, 2015
|
||||||
/----------------------------------------------------------------------------/
|
/----------------------------------------------------------------------------/
|
||||||
/ FatFs module is a free software that opened under license policy of
|
/ FatFs module is a free software that opened under license policy of
|
||||||
/ following conditions.
|
/ following conditions.
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
|
|
||||||
#ifndef _FATFS
|
#ifndef _FATFS
|
||||||
#define _FATFS 32020 /* Revision ID */
|
#define _FATFS 64180 /* Revision ID */
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@@ -200,7 +200,7 @@ typedef enum {
|
|||||||
FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */
|
FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */
|
||||||
FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */
|
FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */
|
||||||
FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */
|
FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */
|
||||||
FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > _FS_SHARE */
|
FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > _FS_LOCK */
|
||||||
FR_INVALID_PARAMETER /* (19) Given parameter is invalid */
|
FR_INVALID_PARAMETER /* (19) Given parameter is invalid */
|
||||||
} FRESULT;
|
} FRESULT;
|
||||||
|
|
||||||
|
|||||||
77
loader/source/fatfs/ffconf.h
Normal file → Executable file
77
loader/source/fatfs/ffconf.h
Normal file → Executable file
@@ -1,21 +1,13 @@
|
|||||||
/*---------------------------------------------------------------------------/
|
/*---------------------------------------------------------------------------/
|
||||||
/ FatFs - FAT file system module configuration file R0.11 (C)ChaN, 2015
|
/ FatFs - FAT file system module configuration file R0.11a (C)ChaN, 2015
|
||||||
/---------------------------------------------------------------------------*/
|
/---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
#define _FFCONF 32020 /* Revision ID */
|
#define _FFCONF 64180 /* Revision ID */
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------/
|
/*---------------------------------------------------------------------------/
|
||||||
/ Functions and Buffer Configurations
|
/ Function Configurations
|
||||||
/---------------------------------------------------------------------------*/
|
/---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
#define _FS_TINY 0
|
|
||||||
/* This option switches tiny buffer configuration. (0:Normal or 1:Tiny)
|
|
||||||
/ At the tiny configuration, size of the file object (FIL) is reduced _MAX_SS
|
|
||||||
/ bytes. Instead of private sector buffer eliminated from the file object,
|
|
||||||
/ common sector buffer in the file system object (FATFS) is used for the file
|
|
||||||
/ data transfer. */
|
|
||||||
|
|
||||||
|
|
||||||
#define _FS_READONLY 1
|
#define _FS_READONLY 1
|
||||||
/* This option switches read-only configuration. (0:Read/Write or 1:Read-only)
|
/* This option switches read-only configuration. (0:Read/Write or 1:Read-only)
|
||||||
/ Read-only configuration removes writing API functions, f_write(), f_sync(),
|
/ Read-only configuration removes writing API functions, f_write(), f_sync(),
|
||||||
@@ -23,7 +15,7 @@
|
|||||||
/ and optional writing functions as well. */
|
/ and optional writing functions as well. */
|
||||||
|
|
||||||
|
|
||||||
#define _FS_MINIMIZE 3
|
#define _FS_MINIMIZE 1
|
||||||
/* This option defines minimization level to remove some basic API functions.
|
/* This option defines minimization level to remove some basic API functions.
|
||||||
/
|
/
|
||||||
/ 0: All basic functions are enabled.
|
/ 0: All basic functions are enabled.
|
||||||
@@ -42,7 +34,7 @@
|
|||||||
/ 2: Enable with LF-CRLF conversion. */
|
/ 2: Enable with LF-CRLF conversion. */
|
||||||
|
|
||||||
|
|
||||||
#define _USE_FIND 0
|
#define _USE_FIND 1
|
||||||
/* This option switches filtered directory read feature and related functions,
|
/* This option switches filtered directory read feature and related functions,
|
||||||
/ f_findfirst() and f_findnext(). (0:Disable or 1:Enable) */
|
/ f_findfirst() and f_findnext(). (0:Disable or 1:Enable) */
|
||||||
|
|
||||||
@@ -69,31 +61,36 @@
|
|||||||
/ Locale and Namespace Configurations
|
/ Locale and Namespace Configurations
|
||||||
/---------------------------------------------------------------------------*/
|
/---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
#define _CODE_PAGE 437
|
#define _CODE_PAGE 1
|
||||||
/* This option specifies the OEM code page to be used on the target system.
|
/* This option specifies the OEM code page to be used on the target system.
|
||||||
/ Incorrect setting of the code page can cause a file open failure.
|
/ Incorrect setting of the code page can cause a file open failure.
|
||||||
/
|
/
|
||||||
/ 1 - ASCII (No extended character. Non-LFN cfg. only)
|
/ 1 - ASCII (No extended character. Non-LFN cfg. only)
|
||||||
/ 437 - U.S.
|
/ 437 - U.S.
|
||||||
/ 720 - Arabic
|
/ 720 - Arabic
|
||||||
/ 737 - Greek
|
/ 737 - Greek
|
||||||
/ 775 - Baltic
|
/ 771 - KBL
|
||||||
/ 850 - Multilingual Latin 1
|
/ 775 - Baltic
|
||||||
/ 852 - Latin 2
|
/ 850 - Latin 1
|
||||||
/ 855 - Cyrillic
|
/ 852 - Latin 2
|
||||||
/ 857 - Turkish
|
/ 855 - Cyrillic
|
||||||
/ 858 - Multilingual Latin 1 + Euro
|
/ 857 - Turkish
|
||||||
/ 862 - Hebrew
|
/ 860 - Portuguese
|
||||||
/ 866 - Russian
|
/ 861 - Icelandic
|
||||||
/ 874 - Thai
|
/ 862 - Hebrew
|
||||||
/ 932 - Japanese Shift_JIS (DBCS)
|
/ 863 - Canadian French
|
||||||
/ 936 - Simplified Chinese GBK (DBCS)
|
/ 864 - Arabic
|
||||||
/ 949 - Korean (DBCS)
|
/ 865 - Nordic
|
||||||
/ 950 - Traditional Chinese Big5 (DBCS)
|
/ 866 - Russian
|
||||||
|
/ 869 - Greek 2
|
||||||
|
/ 932 - Japanese (DBCS)
|
||||||
|
/ 936 - Simplified Chinese (DBCS)
|
||||||
|
/ 949 - Korean (DBCS)
|
||||||
|
/ 950 - Traditional Chinese (DBCS)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#define _USE_LFN 2
|
#define _USE_LFN 0
|
||||||
#define _MAX_LFN 255
|
#define _MAX_LFN 255
|
||||||
/* The _USE_LFN option switches the LFN feature.
|
/* The _USE_LFN option switches the LFN feature.
|
||||||
/
|
/
|
||||||
@@ -115,7 +112,7 @@
|
|||||||
/ to 1. This option also affects behavior of string I/O functions. */
|
/ to 1. This option also affects behavior of string I/O functions. */
|
||||||
|
|
||||||
|
|
||||||
#define _STRF_ENCODE 0
|
#define _STRF_ENCODE 3
|
||||||
/* When _LFN_UNICODE is 1, this option selects the character encoding on the file to
|
/* When _LFN_UNICODE is 1, this option selects the character encoding on the file to
|
||||||
/ be read/written via string I/O functions, f_gets(), f_putc(), f_puts and f_printf().
|
/ be read/written via string I/O functions, f_gets(), f_putc(), f_puts and f_printf().
|
||||||
/
|
/
|
||||||
@@ -195,15 +192,23 @@
|
|||||||
/ System Configurations
|
/ System Configurations
|
||||||
/---------------------------------------------------------------------------*/
|
/---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#define _FS_TINY 0
|
||||||
|
/* This option switches tiny buffer configuration. (0:Normal or 1:Tiny)
|
||||||
|
/ At the tiny configuration, size of the file object (FIL) is reduced _MAX_SS
|
||||||
|
/ bytes. Instead of private sector buffer eliminated from the file object,
|
||||||
|
/ common sector buffer in the file system object (FATFS) is used for the file
|
||||||
|
/ data transfer. */
|
||||||
|
|
||||||
|
|
||||||
#define _FS_NORTC 1
|
#define _FS_NORTC 1
|
||||||
#define _NORTC_MON 2
|
#define _NORTC_MON 1
|
||||||
#define _NORTC_MDAY 1
|
#define _NORTC_MDAY 1
|
||||||
#define _NORTC_YEAR 2015
|
#define _NORTC_YEAR 2015
|
||||||
/* The _FS_NORTC option switches timestamp feature. If the system does not have
|
/* The _FS_NORTC option switches timestamp feature. If the system does not have
|
||||||
/ an RTC function or valid timestamp is not needed, set _FS_NORTC to 1 to disable
|
/ an RTC function or valid timestamp is not needed, set _FS_NORTC to 1 to disable
|
||||||
/ the timestamp feature. All objects modified by FatFs will have a fixed timestamp
|
/ the timestamp feature. All objects modified by FatFs will have a fixed timestamp
|
||||||
/ defined by _NORTC_MON, _NORTC_MDAY and _NORTC_YEAR.
|
/ defined by _NORTC_MON, _NORTC_MDAY and _NORTC_YEAR.
|
||||||
/ When timestamp feature is enabled (_FS_NORTC == 0), get_fattime() function need
|
/ When timestamp feature is enabled (_FS_NORTC == 0), get_fattime() function need
|
||||||
/ to be added to the project to read current time form RTC. _NORTC_MON,
|
/ to be added to the project to read current time form RTC. _NORTC_MON,
|
||||||
/ _NORTC_MDAY and _NORTC_YEAR have no effect.
|
/ _NORTC_MDAY and _NORTC_YEAR have no effect.
|
||||||
/ These options have no effect at read-only configuration (_FS_READONLY == 1). */
|
/ These options have no effect at read-only configuration (_FS_READONLY == 1). */
|
||||||
@@ -253,7 +258,7 @@
|
|||||||
/ * Byte order on the memory is little-endian.
|
/ * Byte order on the memory is little-endian.
|
||||||
/
|
/
|
||||||
/ If it is the case, _WORD_ACCESS can also be set to 1 to reduce code size.
|
/ If it is the case, _WORD_ACCESS can also be set to 1 to reduce code size.
|
||||||
/ Following table shows allowable settings of some processor types.
|
/ Following table shows allowable settings of some type of processors.
|
||||||
/
|
/
|
||||||
/ ARM7TDMI 0 *2 ColdFire 0 *1 V850E 0 *2
|
/ ARM7TDMI 0 *2 ColdFire 0 *1 V850E 0 *2
|
||||||
/ Cortex-M3 0 *3 Z80 0/1 V850ES 0/1
|
/ Cortex-M3 0 *3 Z80 0/1 V850ES 0/1
|
||||||
|
|||||||
10
loader/source/fatfs/integer.h
Normal file → Executable file
10
loader/source/fatfs/integer.h
Normal file → Executable file
@@ -5,26 +5,26 @@
|
|||||||
#ifndef _FF_INTEGER
|
#ifndef _FF_INTEGER
|
||||||
#define _FF_INTEGER
|
#define _FF_INTEGER
|
||||||
|
|
||||||
#ifdef _WIN32 /* FatFs development platform */
|
#ifdef _WIN32 /* Development platform */
|
||||||
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <tchar.h>
|
#include <tchar.h>
|
||||||
|
|
||||||
#else /* Embedded platform */
|
#else /* Embedded platform */
|
||||||
|
|
||||||
/* This type MUST be 8 bit */
|
/* This type MUST be 8-bit */
|
||||||
typedef unsigned char BYTE;
|
typedef unsigned char BYTE;
|
||||||
|
|
||||||
/* These types MUST be 16 bit */
|
/* These types MUST be 16-bit */
|
||||||
typedef short SHORT;
|
typedef short SHORT;
|
||||||
typedef unsigned short WORD;
|
typedef unsigned short WORD;
|
||||||
typedef unsigned short WCHAR;
|
typedef unsigned short WCHAR;
|
||||||
|
|
||||||
/* These types MUST be 16 bit or 32 bit */
|
/* These types MUST be 16-bit or 32-bit */
|
||||||
typedef int INT;
|
typedef int INT;
|
||||||
typedef unsigned int UINT;
|
typedef unsigned int UINT;
|
||||||
|
|
||||||
/* These types MUST be 32 bit */
|
/* These types MUST be 32-bit */
|
||||||
typedef long LONG;
|
typedef long LONG;
|
||||||
typedef unsigned long DWORD;
|
typedef unsigned long DWORD;
|
||||||
|
|
||||||
|
|||||||
@@ -3,37 +3,55 @@
|
|||||||
#include "fatfs/ff.h"
|
#include "fatfs/ff.h"
|
||||||
|
|
||||||
#define PAYLOAD_ADDRESS 0x23F00000
|
#define PAYLOAD_ADDRESS 0x23F00000
|
||||||
|
#define LOAD_PAYLOAD(a) loadPayload(a "_*.bin")
|
||||||
|
|
||||||
|
static u32 loadPayload(const char *pattern)
|
||||||
|
{
|
||||||
|
char path[30] = "/aurei/payloads";
|
||||||
|
|
||||||
|
DIR dir;
|
||||||
|
FILINFO info;
|
||||||
|
|
||||||
|
FRESULT result = f_findfirst(&dir, &info, path, pattern);
|
||||||
|
|
||||||
|
f_closedir(&dir);
|
||||||
|
|
||||||
|
if(result != FR_OK || !info.fname[0])
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
path[15] = '/';
|
||||||
|
u32 i;
|
||||||
|
for(i = 0; info.fname[i]; i++)
|
||||||
|
path[16 + i] = info.fname[i];
|
||||||
|
path[16 + i] = '\0';
|
||||||
|
|
||||||
static u32 loadPayload(const char *path){
|
|
||||||
FIL payload;
|
FIL payload;
|
||||||
unsigned int br;
|
unsigned int br;
|
||||||
if(f_open(&payload, path, FA_READ) == FR_OK)
|
|
||||||
{
|
|
||||||
f_read(&payload, (void *)PAYLOAD_ADDRESS, f_size(&payload), &br);
|
|
||||||
f_close(&payload);
|
|
||||||
|
|
||||||
return 1;
|
f_open(&payload, path, FA_READ);
|
||||||
}
|
f_read(&payload, (void *)PAYLOAD_ADDRESS, f_size(&payload), &br);
|
||||||
|
f_close(&payload);
|
||||||
|
|
||||||
return 0;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void main(void){
|
void main(void)
|
||||||
|
{
|
||||||
FATFS fs;
|
FATFS fs;
|
||||||
|
|
||||||
f_mount(&fs, "0:", 1);
|
f_mount(&fs, "0:", 1);
|
||||||
|
|
||||||
//Get pressed buttons
|
//Get pressed buttons
|
||||||
u16 pressed = HID_PAD;
|
u32 pressed = HID_PAD;
|
||||||
|
|
||||||
if(((pressed & BUTTON_B) && loadPayload("/aurei/payloads/b.bin")) ||
|
if(((pressed & BUTTON_RIGHT) && LOAD_PAYLOAD("right")) ||
|
||||||
((pressed & BUTTON_X) && loadPayload("/aurei/payloads/x.bin")) ||
|
((pressed & BUTTON_LEFT) && LOAD_PAYLOAD("left")) ||
|
||||||
((pressed & BUTTON_Y) && loadPayload("/aurei/payloads/y.bin")) ||
|
((pressed & BUTTON_UP) && LOAD_PAYLOAD("up")) ||
|
||||||
((pressed & BUTTON_SELECT) && loadPayload("/aurei/payloads/select.bin")) ||
|
((pressed & BUTTON_DOWN) && LOAD_PAYLOAD("down")) ||
|
||||||
((pressed & BUTTON_START) && loadPayload("/aurei/payloads/start.bin")) ||
|
((pressed & BUTTON_X) && LOAD_PAYLOAD("x")) ||
|
||||||
((pressed & BUTTON_RIGHT) && loadPayload("/aurei/payloads/right.bin")) ||
|
((pressed & BUTTON_Y) && LOAD_PAYLOAD("y")) ||
|
||||||
((pressed & BUTTON_LEFT) && loadPayload("/aurei/payloads/left.bin")) ||
|
((pressed & BUTTON_R1) && LOAD_PAYLOAD("r")) ||
|
||||||
((pressed & BUTTON_UP) && loadPayload("/aurei/payloads/up.bin")) ||
|
((pressed & BUTTON_SELECT) && LOAD_PAYLOAD("sel")) ||
|
||||||
((pressed & BUTTON_DOWN) && loadPayload("/aurei/payloads/down.bin")) ||
|
LOAD_PAYLOAD("def"))
|
||||||
loadPayload("/aurei/payloads/default.bin"))
|
|
||||||
((void (*)())PAYLOAD_ADDRESS)();
|
((void (*)())PAYLOAD_ADDRESS)();
|
||||||
}
|
}
|
||||||
@@ -12,7 +12,4 @@ _start:
|
|||||||
mcr p15, 0, r0, c7, c6, 0 @ flush D-cache
|
mcr p15, 0, r0, c7, c6, 0 @ flush D-cache
|
||||||
mcr p15, 0, r0, c7, c10, 4 @ drain write buffer
|
mcr p15, 0, r0, c7, c10, 4 @ drain write buffer
|
||||||
|
|
||||||
bl main
|
b main
|
||||||
|
|
||||||
.die:
|
|
||||||
b .die
|
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
%rename link old_link
|
|
||||||
|
|
||||||
*link:
|
|
||||||
%(old_link) -T ../stub.ld%s
|
|
||||||
|
|
||||||
319
patches/reboot.s
319
patches/reboot.s
@@ -1,221 +1,148 @@
|
|||||||
.arm.little
|
.arm.little
|
||||||
|
|
||||||
byteswritten equ 0x2000E000
|
payload_addr equ 0x23F00000 ; Brahma payload address.
|
||||||
kernelCode equ 0x080F0000
|
payload_maxsize equ 0x20000 ; Maximum size for the payload (200 KB will do).
|
||||||
buffer equ 0x24000000
|
|
||||||
fileOpen equ 0x4E45504F ;dummy
|
|
||||||
|
|
||||||
.create "reboot.bin", 0
|
.create "reboot.bin", 0
|
||||||
.arm
|
.arm
|
||||||
//Code jumps here right after the sprintf call
|
; Interesting registers and locations to keep in mind, set before this code is ran:
|
||||||
process9Reboot:
|
; - sp + 0x3A8 - 0x70: FIRM path in exefs.
|
||||||
doPxi:
|
; - r7 (which is sp + 0x3A8 - 0x198): Reserved space for file handle
|
||||||
ldr r4, =0x44846
|
; - *(sp + 0x3A8 - 0x198) + 0x28: fread function.
|
||||||
ldr r0, =0x10008000
|
|
||||||
readPxiLoop1:
|
|
||||||
ldrh r1, [r0,#4]
|
|
||||||
.word 0xE1B01B81 //lsls r1, r1, #0x17
|
|
||||||
bmi readPxiLoop1
|
|
||||||
ldr r0, [r0,#0xC]
|
|
||||||
cmp r0, r4
|
|
||||||
bne doPxi
|
|
||||||
|
|
||||||
GetFirmPath:
|
pxi_wait_recv:
|
||||||
add r0, sp, #0x3A8-0x70+0x24
|
ldr r2, =0x44846
|
||||||
ldr r1, [r0], #4
|
ldr r0, =0x10008000
|
||||||
ldr r2, =0x00300030
|
readPxiLoop1:
|
||||||
cmp r1, r2
|
ldrh r1, [r0, #4]
|
||||||
ldreq r1, [r0], #4
|
lsls r1, #0x17
|
||||||
ldreq r2, =0x002F0032
|
bmi readPxiLoop1
|
||||||
cmpeq r1, r2
|
ldr r0, [r0, #0xC]
|
||||||
|
cmp r0, r2
|
||||||
|
bne pxi_wait_recv
|
||||||
|
|
||||||
OpenFirm:
|
mov r4, #0
|
||||||
ldreq r1, =(FileName - OpenFirm - 12)
|
adr r1, bin_fname
|
||||||
addeq r1, pc
|
b open_payload
|
||||||
addne r1, sp, #0x3A8-0x70
|
|
||||||
moveq r2, #1
|
|
||||||
movne r2, #0
|
|
||||||
str r2, [externalFirm]
|
|
||||||
mov r2, #1
|
|
||||||
add r0, r7, #8
|
|
||||||
ldr r6, =fileOpen
|
|
||||||
blx r6
|
|
||||||
|
|
||||||
SeekFirm:
|
fallback:
|
||||||
ldr r0, [externalFirm]
|
mov r4, #1
|
||||||
cmp r0, #1
|
adr r1, dat_fname
|
||||||
moveq r0, r7
|
|
||||||
ldreq r1, =byteswritten
|
|
||||||
ldreq r2, =buffer
|
|
||||||
ldreq r3, =0x0
|
|
||||||
ldreq r6, [sp,#0x3A8-0x198]
|
|
||||||
ldreq r6, [r6,#0x28] //fread function stored here
|
|
||||||
blxeq r6
|
|
||||||
|
|
||||||
ReadFirm:
|
open_payload:
|
||||||
mov r0, r7
|
; Open file
|
||||||
ldr r1, =byteswritten
|
add r0, r7, #8
|
||||||
ldr r2, =buffer
|
mov r2, #1
|
||||||
ldr r3, =0x200000
|
ldr r6, [fopen]
|
||||||
ldr r6, [sp,#0x3A8-0x198]
|
orr r6, 1
|
||||||
ldr r6, [r6,#0x28] //fread function stored here
|
blx r6
|
||||||
blx r6
|
cmp r0, #0
|
||||||
|
bne fallback ; If the .bin is not found, try the .dat.
|
||||||
|
|
||||||
KernelSetState:
|
read_payload:
|
||||||
mov r2, #0
|
; Read file
|
||||||
mov r3, r2
|
mov r0, r7
|
||||||
mov r1, r2
|
adr r1, bytes_read
|
||||||
mov r0, r2
|
ldr r2, =payload_addr
|
||||||
.word 0xEF00007C //SVC 0x7C
|
cmp r4, #0
|
||||||
|
movne r3, #0x12000 ; Skip the first 0x12000 bytes.
|
||||||
|
moveq r3, payload_maxsize
|
||||||
|
ldr r6, [sp, #0x3A8-0x198]
|
||||||
|
ldr r6, [r6, #0x28]
|
||||||
|
blx r6
|
||||||
|
cmp r4, #0
|
||||||
|
movne r4, #0
|
||||||
|
bne read_payload ; Go read the real payload.
|
||||||
|
|
||||||
GoToReboot:
|
add r0, sp, #0x3A8 - 0x70
|
||||||
ldr r0, =(KernelCodeStart - GoToReboot - 12)
|
ldr r0, [r0, #0x27]
|
||||||
add r0, pc
|
ldr r1, =payload_addr + 4
|
||||||
ldr r1, =kernelCode
|
str r0, [r1] ; Copy the last digits of the wanted firm to the 5th byte of the payload.
|
||||||
ldr r2, =0x300
|
|
||||||
bl Memcpy
|
|
||||||
|
|
||||||
ldr r0, =kernelCode
|
; Set kernel state
|
||||||
.word 0xEF00007B //SVC 0x7B
|
mov r0, #0
|
||||||
|
mov r1, #0
|
||||||
|
mov r2, #0
|
||||||
|
mov r3, #0
|
||||||
|
swi 0x7C
|
||||||
|
|
||||||
InfiniteLoop:
|
goto_reboot:
|
||||||
b InfiniteLoop
|
; Jump to reboot code
|
||||||
|
ldr r0, =(kernelcode_start - goto_reboot - 12)
|
||||||
|
add r0, pc
|
||||||
|
swi 0x7B
|
||||||
|
|
||||||
Memcpy:
|
die:
|
||||||
MOV R12, LR
|
b die
|
||||||
STMFD SP!, {R0-R4}
|
|
||||||
ADD R2, R2, R0
|
|
||||||
|
|
||||||
memcpyLoop:
|
|
||||||
LDR R3, [R0],#4
|
|
||||||
STR R3, [R1],#4
|
|
||||||
CMP R0, R2
|
|
||||||
BLT memcpyLoop
|
|
||||||
LDMFD SP!, {R0-R4}
|
|
||||||
MOV LR, R12
|
|
||||||
BX LR
|
|
||||||
|
|
||||||
FileName:
|
|
||||||
.dcw "sdmc:/aurei/patched_firmware_sys.bin"
|
|
||||||
.word 0x0
|
|
||||||
|
|
||||||
externalFirm:
|
|
||||||
.word 0x2000A000
|
|
||||||
|
|
||||||
|
bytes_read: .word 0
|
||||||
|
fopen: .ascii "OPEN"
|
||||||
.pool
|
.pool
|
||||||
|
bin_fname: .dcw "sdmc:/arm9loaderhax.bin"
|
||||||
|
.word 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||||
|
dat_fname: .dcw "sdmc:/AuReiNand.dat"
|
||||||
|
.word 0
|
||||||
|
|
||||||
// Kernel Code
|
|
||||||
.align 4
|
.align 4
|
||||||
KernelCodeStart:
|
kernelcode_start:
|
||||||
memorySetting:
|
; Set MPU settings
|
||||||
MRC p15, 0, R0,c2,c0, 0
|
mrc p15, 0, r0, c2, c0, 0 ; dcacheable
|
||||||
MRC p15, 0, R12,c2,c0, 1
|
mrc p15, 0, r12, c2, c0, 1 ; icacheable
|
||||||
MRC p15, 0, R1,c3,c0, 0
|
mrc p15, 0, r1, c3, c0, 0 ; write bufferable
|
||||||
MRC p15, 0, R2,c5,c0, 2
|
mrc p15, 0, r2, c5, c0, 2 ; daccess
|
||||||
MRC p15, 0, R3,c5,c0, 3
|
mrc p15, 0, r3, c5, c0, 3 ; iaccess
|
||||||
LDR R4, =0x18000035
|
ldr r4, =0x18000035 ; 0x18000000 128M
|
||||||
BIC R2, R2, #0xF0000
|
bic r2, r2, #0xF0000 ; unprotect region 4
|
||||||
BIC R3, R3, #0xF0000
|
bic r3, r3, #0xF0000 ; unprotect region 4
|
||||||
ORR R0, R0, #0x10
|
orr r0, r0, #0x10 ; dcacheable region 4
|
||||||
ORR R2, R2, #0x30000
|
orr r2, r2, #0x30000 ; region 4 r/w
|
||||||
ORR R3, R3, #0x30000
|
orr r3, r3, #0x30000 ; region 4 r/w
|
||||||
ORR R12, R12, #0x10
|
orr r12, r12, #0x10 ; icacheable region 4
|
||||||
ORR R1, R1, #0x10
|
orr r1, r1, #0x10 ; write bufferable region 4
|
||||||
MCR p15, 0, R0,c2,c0, 0
|
mcr p15, 0, r0, c2, c0, 0
|
||||||
MCR p15, 0, R12,c2,c0, 1
|
mcr p15, 0, r12, c2, c0, 1
|
||||||
MCR p15, 0, R1,c3,c0, 0
|
mcr p15, 0, r1, c3, c0, 0 ; write bufferable
|
||||||
MCR p15, 0, R2,c5,c0, 2
|
mcr p15, 0, r2, c5, c0, 2 ; daccess
|
||||||
MCR p15, 0, R3,c5,c0, 3
|
mcr p15, 0, r3, c5, c0, 3 ; iaccess
|
||||||
MCR p15, 0, R4,c6,c4, 0
|
mcr p15, 0, r4, c6, c4, 0 ; region 4 (hmmm)
|
||||||
MRC p15, 0, R0,c2,c0, 0
|
|
||||||
MRC p15, 0, R1,c2,c0, 1
|
|
||||||
MRC p15, 0, R2,c3,c0, 0
|
|
||||||
ORR R0, R0, #0x20
|
|
||||||
ORR R1, R1, #0x20
|
|
||||||
ORR R2, R2, #0x20
|
|
||||||
MCR p15, 0, R0,c2,c0, 0
|
|
||||||
MCR p15, 0, R1,c2,c0, 1
|
|
||||||
MCR p15, 0, R2,c3,c0, 0
|
|
||||||
|
|
||||||
copyFirmPartitions:
|
mrc p15, 0, r0, c2, c0, 0 ; dcacheable
|
||||||
LDR R4, =buffer
|
mrc p15, 0, r1, c2, c0, 1 ; icacheable
|
||||||
ADD R3, R4, #0x40
|
mrc p15, 0, r2, c3, c0, 0 ; write bufferable
|
||||||
LDR R0, [R3]
|
orr r0, r0, #0x20 ; dcacheable region 5
|
||||||
ADD R0, R0, R4
|
orr r1, r1, #0x20 ; icacheable region 5
|
||||||
LDR R1, [R3,#4]
|
orr r2, r2, #0x20 ; write bufferable region 5
|
||||||
LDR R2, [R3,#8]
|
mcr p15, 0, r0, c2, c0, 0 ; dcacheable
|
||||||
bl KernelMemcpy
|
mcr p15, 0, r1, c2, c0, 1 ; icacheable
|
||||||
|
mcr p15, 0, r2, c3, c0, 0 ; write bufferable
|
||||||
|
|
||||||
ADD R3, R4, #0x70
|
; Flush cache
|
||||||
LDR R0, [R3]
|
mov r2, #0
|
||||||
ADD R0, R0, R4
|
mov r1, r2
|
||||||
LDR R1, [R3,#4]
|
flush_cache:
|
||||||
LDR R2, [R3,#8]
|
mov r0, #0
|
||||||
bl KernelMemcpy
|
mov r3, r2, lsl #30
|
||||||
|
flush_cache_inner_loop:
|
||||||
|
orr r12, r3, r0, lsl#5
|
||||||
|
mcr p15, 0, r1, c7, c10, 4 ; drain write buffer
|
||||||
|
mcr p15, 0, r12, c7, c14, 2 ; clean and flush dcache entry (index and segment)
|
||||||
|
add r0, #1
|
||||||
|
cmp r0, #0x20
|
||||||
|
bcc flush_cache_inner_loop
|
||||||
|
add r2, #1
|
||||||
|
cmp r2, #4
|
||||||
|
bcc flush_cache
|
||||||
|
|
||||||
ADD R3, R4, #0xA0
|
; Enable MPU
|
||||||
LDR R0, [R3]
|
ldr r0, =0x42078 ; alt vector select, enable itcm
|
||||||
ADD R0, R0, R4
|
mcr p15, 0, r0, c1, c0, 0
|
||||||
LDR R1, [R3,#4]
|
mcr p15, 0, r1, c7, c5, 0 ; flush dcache
|
||||||
LDR R2, [R3,#8]
|
mcr p15, 0, r1, c7, c6, 0 ; flush icache
|
||||||
bl KernelMemcpy
|
mcr p15, 0, r1, c7, c10, 4 ; drain write buffer
|
||||||
|
|
||||||
ADD R3, R4, #0xD0
|
; Jump to payload
|
||||||
LDR R0, [R3]
|
ldr r0, =payload_addr
|
||||||
CMP R0, #0
|
bx r0
|
||||||
BEQ invalidateDataCache
|
|
||||||
ADD R0, R0, R4
|
|
||||||
LDR R1, [R3,#4]
|
|
||||||
LDR R2, [R3,#8]
|
|
||||||
bl KernelMemcpy
|
|
||||||
|
|
||||||
invalidateDataCache:
|
|
||||||
MOV R2, #0
|
|
||||||
MOV R1, R2
|
|
||||||
loc_809460C:
|
|
||||||
MOV R0, #0
|
|
||||||
MOV R3, R2,LSL#30
|
|
||||||
loc_8094614:
|
|
||||||
ORR R12, R3, R0,LSL#5
|
|
||||||
MCR p15, 0, R1,c7,c10, 4
|
|
||||||
MCR p15, 0, R12,c7,c14, 2
|
|
||||||
ADD R0, R0, #1
|
|
||||||
CMP R0, #0x20
|
|
||||||
BCC loc_8094614
|
|
||||||
ADD R2, R2, #1
|
|
||||||
CMP R2, #4
|
|
||||||
BCC loc_809460C
|
|
||||||
|
|
||||||
jumpToEntrypoint:
|
|
||||||
MCR p15, 0, R1,c7,c10, 4
|
|
||||||
LDR R0, =0x42078
|
|
||||||
MCR p15, 0, R0,c1,c0, 0
|
|
||||||
MCR p15, 0, R1,c7,c5, 0
|
|
||||||
MCR p15, 0, R1,c7,c6, 0
|
|
||||||
MCR p15, 0, R1,c7,c10, 4
|
|
||||||
LDR R4, =buffer
|
|
||||||
MOV R1, #0x1FFFFFFC
|
|
||||||
LDR R2, [R4,#8]
|
|
||||||
STR R2, [R1]
|
|
||||||
LDR R0, [R4,#0xC]
|
|
||||||
BX R0
|
|
||||||
.pool
|
.pool
|
||||||
|
|
||||||
KernelMemcpy:
|
|
||||||
MOV R12, LR
|
|
||||||
STMFD SP!, {R0-R4}
|
|
||||||
ADD R2, R2, R0
|
|
||||||
|
|
||||||
kmemcpyLoop:
|
|
||||||
LDR R3, [R0],#4
|
|
||||||
STR R3, [R1],#4
|
|
||||||
CMP R0, R2
|
|
||||||
BLT kmemcpyLoop
|
|
||||||
LDMFD SP!, {R0-R4}
|
|
||||||
MOV LR, R12
|
|
||||||
BX LR
|
|
||||||
.pool
|
|
||||||
|
|
||||||
KernelCodeEnd:
|
|
||||||
|
|
||||||
.close
|
.close
|
||||||
|
|||||||
98
pathchanger/pathchanger.c
Normal file
98
pathchanger/pathchanger.c
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
typedef uint8_t u8;
|
||||||
|
|
||||||
|
static u8 *memsearch(u8 *startPos, const void *pattern, int size, int patternSize)
|
||||||
|
{
|
||||||
|
const u8 *patternc = (const u8 *)pattern;
|
||||||
|
|
||||||
|
//Preprocessing
|
||||||
|
int table[256];
|
||||||
|
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < 256; ++i)
|
||||||
|
table[i] = patternSize + 1;
|
||||||
|
for(i = 0; i < patternSize; ++i)
|
||||||
|
table[patternc[i]] = patternSize - i;
|
||||||
|
|
||||||
|
//Searching
|
||||||
|
int j = 0;
|
||||||
|
|
||||||
|
while(j <= size - patternSize)
|
||||||
|
{
|
||||||
|
if(memcmp(patternc, startPos + j, patternSize) == 0)
|
||||||
|
return startPos + j;
|
||||||
|
j += table[startPos[j + patternSize]];
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fsize(FILE *fp)
|
||||||
|
{
|
||||||
|
fseek(fp, 0, SEEK_END);
|
||||||
|
int size = ftell(fp);
|
||||||
|
rewind(fp);
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void error(FILE *payload, const char *message)
|
||||||
|
{
|
||||||
|
fclose(payload);
|
||||||
|
printf("%s, are you sure you're using an AuReiNand payload?\n", message);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
if(argc == 1)
|
||||||
|
{
|
||||||
|
printf("Usage: %s <AuReiNand payload path>\n", argv[0]);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE *payload;
|
||||||
|
size_t size;
|
||||||
|
|
||||||
|
payload = fopen(argv[1], "rb+");
|
||||||
|
size = fsize(payload);
|
||||||
|
if(size > 0x20000)
|
||||||
|
error(payload, "The input file is too large");
|
||||||
|
|
||||||
|
u8 *buffer = (u8 *)malloc(size);
|
||||||
|
fread(buffer, 1, size, payload);
|
||||||
|
|
||||||
|
u8 pattern[] = {'s', 0, 'd', 0, 'm', 0, 'c', 0, ':', 0, '/', 0};
|
||||||
|
|
||||||
|
u8 *found = memsearch(buffer, pattern, size, sizeof(pattern));
|
||||||
|
|
||||||
|
if(found == NULL)
|
||||||
|
{
|
||||||
|
free(buffer);
|
||||||
|
error(payload, "Pattern not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
u8 input[38] = {0};
|
||||||
|
u8 payloadname[2 * (sizeof(input) - 1)] = {0};
|
||||||
|
|
||||||
|
printf("Enter the payload's path (37 characters max): ");
|
||||||
|
scanf("%37s", input);
|
||||||
|
|
||||||
|
unsigned int i;
|
||||||
|
for (i = 0; i < sizeof(input) - 1; i++)
|
||||||
|
payloadname[2 * i] = input[i];
|
||||||
|
|
||||||
|
memcpy(found + 12, payloadname, sizeof(payloadname));
|
||||||
|
|
||||||
|
rewind(payload);
|
||||||
|
fwrite(buffer, 1, size, payload);
|
||||||
|
|
||||||
|
free(buffer);
|
||||||
|
fclose(payload);
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
47
screeninit/Makefile
Executable file
47
screeninit/Makefile
Executable file
@@ -0,0 +1,47 @@
|
|||||||
|
rwildcard = $(foreach d, $(wildcard $1*), $(filter $(subst *, %, $2), $d) $(call rwildcard, $d/, $2))
|
||||||
|
|
||||||
|
ifeq ($(strip $(DEVKITARM)),)
|
||||||
|
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
|
||||||
|
endif
|
||||||
|
|
||||||
|
include $(DEVKITARM)/3ds_rules
|
||||||
|
|
||||||
|
CC := arm-none-eabi-gcc
|
||||||
|
AS := arm-none-eabi-as
|
||||||
|
LD := arm-none-eabi-ld
|
||||||
|
OC := arm-none-eabi-objcopy
|
||||||
|
|
||||||
|
name := $(shell basename $(CURDIR))
|
||||||
|
|
||||||
|
dir_source := source
|
||||||
|
dir_build := build
|
||||||
|
|
||||||
|
ASFLAGS := -mlittle-endian -mcpu=mpcore
|
||||||
|
CFLAGS := -Wall -Wextra -MMD -MP -marm $(ASFLAGS) -fno-builtin -std=c11 -Wno-main -O2 -flto -ffast-math -mthumb -mthumb-interwork
|
||||||
|
LDFLAGS := -nostdlib
|
||||||
|
|
||||||
|
objects = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \
|
||||||
|
$(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \
|
||||||
|
$(call rwildcard, $(dir_source), *.s *.c)))
|
||||||
|
|
||||||
|
.PHONY: all
|
||||||
|
all: $(name).bin
|
||||||
|
|
||||||
|
.PHONY: clean
|
||||||
|
clean:
|
||||||
|
@rm -rf $(dir_build)
|
||||||
|
|
||||||
|
$(name).bin: $(dir_build)/$(name).elf
|
||||||
|
$(OC) -S -O binary $< $@
|
||||||
|
|
||||||
|
$(dir_build)/$(name).elf: $(objects)
|
||||||
|
$(CC) $(LDFLAGS) -T linker.ld $(OUTPUT_OPTION) $^
|
||||||
|
|
||||||
|
$(dir_build)/%.o: $(dir_source)/%.c
|
||||||
|
@mkdir -p "$(@D)"
|
||||||
|
$(COMPILE.c) $(OUTPUT_OPTION) $<
|
||||||
|
|
||||||
|
$(dir_build)/%.o: $(dir_source)/%.s
|
||||||
|
@mkdir -p "$(@D)"
|
||||||
|
$(COMPILE.s) $(OUTPUT_OPTION) $<
|
||||||
|
include $(call rwildcard, $(dir_build), *.d)
|
||||||
12
screeninit/linker.ld
Executable file
12
screeninit/linker.ld
Executable file
@@ -0,0 +1,12 @@
|
|||||||
|
ENTRY(_start)
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
. = 0x24F03000;
|
||||||
|
.text.start : { *(.text.start) }
|
||||||
|
.text : { *(.text) }
|
||||||
|
.data : { *(.data) }
|
||||||
|
.bss : { *(.bss COMMON) }
|
||||||
|
.rodata : { *(.rodata) }
|
||||||
|
. = ALIGN(4);
|
||||||
|
}
|
||||||
|
|
||||||
105
screeninit/source/main.c
Executable file
105
screeninit/source/main.c
Executable file
@@ -0,0 +1,105 @@
|
|||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
void main(void)
|
||||||
|
{
|
||||||
|
const u32 brightness[4] = {0x5F, 0x4C, 0x39, 0x26};
|
||||||
|
u32 brightnessLevel = *(vu32 *)0x24F03008;
|
||||||
|
vu32 *const arm11 = (u32 *)0x1FFFFFF8;
|
||||||
|
|
||||||
|
*(vu32 *)0x10141200 = 0x1007F;
|
||||||
|
*(vu32 *)0x10202014 = 0x00000001;
|
||||||
|
*(vu32 *)0x1020200C &= 0xFFFEFFFE;
|
||||||
|
*(vu32 *)0x10202240 = brightness[brightnessLevel];
|
||||||
|
*(vu32 *)0x10202A40 = brightness[brightnessLevel];
|
||||||
|
*(vu32 *)0x10202244 = 0x1023E;
|
||||||
|
*(vu32 *)0x10202A44 = 0x1023E;
|
||||||
|
|
||||||
|
// Top screen
|
||||||
|
*(vu32 *)0x10400400 = 0x000001c2;
|
||||||
|
*(vu32 *)0x10400404 = 0x000000d1;
|
||||||
|
*(vu32 *)0x10400408 = 0x000001c1;
|
||||||
|
*(vu32 *)0x1040040c = 0x000001c1;
|
||||||
|
*(vu32 *)0x10400410 = 0x00000000;
|
||||||
|
*(vu32 *)0x10400414 = 0x000000cf;
|
||||||
|
*(vu32 *)0x10400418 = 0x000000d1;
|
||||||
|
*(vu32 *)0x1040041c = 0x01c501c1;
|
||||||
|
*(vu32 *)0x10400420 = 0x00010000;
|
||||||
|
*(vu32 *)0x10400424 = 0x0000019d;
|
||||||
|
*(vu32 *)0x10400428 = 0x00000002;
|
||||||
|
*(vu32 *)0x1040042c = 0x00000192;
|
||||||
|
*(vu32 *)0x10400430 = 0x00000192;
|
||||||
|
*(vu32 *)0x10400434 = 0x00000192;
|
||||||
|
*(vu32 *)0x10400438 = 0x00000001;
|
||||||
|
*(vu32 *)0x1040043c = 0x00000002;
|
||||||
|
*(vu32 *)0x10400440 = 0x01960192;
|
||||||
|
*(vu32 *)0x10400444 = 0x00000000;
|
||||||
|
*(vu32 *)0x10400448 = 0x00000000;
|
||||||
|
*(vu32 *)0x1040045C = 0x00f00190;
|
||||||
|
*(vu32 *)0x10400460 = 0x01c100d1;
|
||||||
|
*(vu32 *)0x10400464 = 0x01920002;
|
||||||
|
*(vu32 *)0x10400468 = 0x18300000;
|
||||||
|
*(vu32 *)0x10400470 = 0x80341;
|
||||||
|
*(vu32 *)0x10400474 = 0x00010501;
|
||||||
|
*(vu32 *)0x10400478 = 0;
|
||||||
|
*(vu32 *)0x10400490 = 0x000002D0;
|
||||||
|
*(vu32 *)0x1040049C = 0x00000000;
|
||||||
|
|
||||||
|
// Disco register
|
||||||
|
for(u32 i = 0; i < 256; i++)
|
||||||
|
*(vu32 *)0x10400484 = 0x10101 * i;
|
||||||
|
|
||||||
|
// Bottom screen
|
||||||
|
*(vu32 *)0x10400500 = 0x000001c2;
|
||||||
|
*(vu32 *)0x10400504 = 0x000000d1;
|
||||||
|
*(vu32 *)0x10400508 = 0x000001c1;
|
||||||
|
*(vu32 *)0x1040050c = 0x000001c1;
|
||||||
|
*(vu32 *)0x10400510 = 0x000000cd;
|
||||||
|
*(vu32 *)0x10400514 = 0x000000cf;
|
||||||
|
*(vu32 *)0x10400518 = 0x000000d1;
|
||||||
|
*(vu32 *)0x1040051c = 0x01c501c1;
|
||||||
|
*(vu32 *)0x10400520 = 0x00010000;
|
||||||
|
*(vu32 *)0x10400524 = 0x0000019d;
|
||||||
|
*(vu32 *)0x10400528 = 0x00000052;
|
||||||
|
*(vu32 *)0x1040052c = 0x00000192;
|
||||||
|
*(vu32 *)0x10400530 = 0x00000192;
|
||||||
|
*(vu32 *)0x10400534 = 0x0000004f;
|
||||||
|
*(vu32 *)0x10400538 = 0x00000050;
|
||||||
|
*(vu32 *)0x1040053c = 0x00000052;
|
||||||
|
*(vu32 *)0x10400540 = 0x01980194;
|
||||||
|
*(vu32 *)0x10400544 = 0x00000000;
|
||||||
|
*(vu32 *)0x10400548 = 0x00000011;
|
||||||
|
*(vu32 *)0x1040055C = 0x00f00140;
|
||||||
|
*(vu32 *)0x10400560 = 0x01c100d1;
|
||||||
|
*(vu32 *)0x10400564 = 0x01920052;
|
||||||
|
*(vu32 *)0x10400568 = 0x18300000 + 0x46500;
|
||||||
|
*(vu32 *)0x10400570 = 0x80301;
|
||||||
|
*(vu32 *)0x10400574 = 0x00010501;
|
||||||
|
*(vu32 *)0x10400578 = 0;
|
||||||
|
*(vu32 *)0x10400590 = 0x000002D0;
|
||||||
|
*(vu32 *)0x1040059C = 0x00000000;
|
||||||
|
|
||||||
|
// Disco register
|
||||||
|
for(u32 i = 0; i < 256; i++)
|
||||||
|
*(vu32 *)0x10400584 = 0x10101 * i;
|
||||||
|
|
||||||
|
*(vu32 *)0x10400468 = 0x18300000;
|
||||||
|
*(vu32 *)0x1040046c = 0x18300000;
|
||||||
|
*(vu32 *)0x10400494 = 0x18300000;
|
||||||
|
*(vu32 *)0x10400498 = 0x18300000;
|
||||||
|
*(vu32 *)0x10400568 = 0x18346500;
|
||||||
|
*(vu32 *)0x1040056c = 0x18346500;
|
||||||
|
|
||||||
|
//Set CakeBrah framebuffers
|
||||||
|
*((vu32 *)0x23FFFE00) = 0x18300000;
|
||||||
|
*((vu32 *)0x23FFFE04) = 0x18300000;
|
||||||
|
*((vu32 *)0x23FFFE08) = 0x18346500;
|
||||||
|
|
||||||
|
//Clear ARM11 entry offset
|
||||||
|
*arm11 = 0;
|
||||||
|
|
||||||
|
//Wait for the entry to be set
|
||||||
|
while(!*arm11);
|
||||||
|
|
||||||
|
//Jump to it
|
||||||
|
((void (*)())*arm11)();
|
||||||
|
}
|
||||||
10
screeninit/source/start.s
Normal file
10
screeninit/source/start.s
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
.section .text.start
|
||||||
|
.align 4
|
||||||
|
.global _start
|
||||||
|
_start:
|
||||||
|
@ Disable interrupts
|
||||||
|
CPSID aif
|
||||||
|
|
||||||
|
b main
|
||||||
|
|
||||||
|
.word 0
|
||||||
19
screeninit/source/types.h
Executable file
19
screeninit/source/types.h
Executable file
@@ -0,0 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* types.h
|
||||||
|
* by Reisyukaku
|
||||||
|
* Copyright (c) 2015 All Rights Reserved
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
//Common data types
|
||||||
|
typedef uint8_t u8;
|
||||||
|
typedef uint16_t u16;
|
||||||
|
typedef uint32_t u32;
|
||||||
|
typedef uint64_t u64;
|
||||||
|
typedef volatile u8 vu8;
|
||||||
|
typedef volatile u16 vu16;
|
||||||
|
typedef volatile u32 vu32;
|
||||||
|
typedef volatile u64 vu64;
|
||||||
@@ -8,19 +8,22 @@
|
|||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
#define HID_PAD (*(vu16 *)0x10146000 ^ 0xFFF)
|
#define HID_PAD (*(vu32 *)0x10146000 ^ 0xFFF)
|
||||||
#define BUTTON_R1 (1 << 8)
|
#define BUTTON_R1 (1 << 8)
|
||||||
#define BUTTON_L1 (1 << 9)
|
#define BUTTON_L1 (1 << 9)
|
||||||
#define BUTTON_A 1
|
#define BUTTON_A 1
|
||||||
#define BUTTON_B (1 << 1)
|
#define BUTTON_B (1 << 1)
|
||||||
#define BUTTON_SELECT (1 << 2)
|
#define BUTTON_X (1 << 10)
|
||||||
#define BUTTON_START (1 << 3)
|
#define BUTTON_Y (1 << 11)
|
||||||
#define BUTTON_RIGHT (1 << 4)
|
#define BUTTON_SELECT (1 << 2)
|
||||||
#define BUTTON_LEFT (1 << 5)
|
#define BUTTON_START (1 << 3)
|
||||||
#define BUTTON_UP (1 << 6)
|
#define BUTTON_RIGHT (1 << 4)
|
||||||
#define BUTTON_DOWN (1 << 7)
|
#define BUTTON_LEFT (1 << 5)
|
||||||
#define BUTTON_L1R1 ((1 << 8) | (1 << 9))
|
#define BUTTON_UP (1 << 6)
|
||||||
#define SAFE_MODE (BUTTON_L1R1 | BUTTON_A | BUTTON_UP)
|
#define BUTTON_DOWN (1 << 7)
|
||||||
#define OPTION_BUTTONS (BUTTON_L1R1 | BUTTON_A)
|
#define BUTTON_L1R1 (BUTTON_R1 | BUTTON_L1)
|
||||||
#define PAYLOAD_BUTTONS ((BUTTON_L1 | BUTTON_A) ^ 0xFFF)
|
#define SAFE_MODE (BUTTON_L1R1 | BUTTON_A | BUTTON_UP)
|
||||||
#define MENU_BUTTONS (BUTTON_LEFT | BUTTON_RIGHT | BUTTON_UP | BUTTON_DOWN | BUTTON_A | BUTTON_START)
|
#define OVERRIDE_BUTTONS (BUTTON_B ^ 0xFFF)
|
||||||
|
#define SINGLE_PAYLOAD_BUTTONS (BUTTON_LEFT | BUTTON_RIGHT | BUTTON_UP | BUTTON_DOWN | BUTTON_START | BUTTON_X | BUTTON_Y)
|
||||||
|
#define L_PAYLOAD_BUTTONS (BUTTON_R1 | BUTTON_SELECT)
|
||||||
|
#define MENU_BUTTONS (BUTTON_LEFT | BUTTON_RIGHT | BUTTON_UP | BUTTON_DOWN | BUTTON_A | BUTTON_START)
|
||||||
184
source/config.c
Normal file
184
source/config.c
Normal file
@@ -0,0 +1,184 @@
|
|||||||
|
/*
|
||||||
|
* config.c
|
||||||
|
* by Aurora Wright
|
||||||
|
* Copyright (c) 2016 All Rights Reserved
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "utils.h"
|
||||||
|
#include "screeninit.h"
|
||||||
|
#include "draw.h"
|
||||||
|
#include "fs.h"
|
||||||
|
#include "buttons.h"
|
||||||
|
|
||||||
|
void configureCFW(const char *configPath)
|
||||||
|
{
|
||||||
|
initScreens();
|
||||||
|
|
||||||
|
drawString(CONFIG_TITLE, 10, 10, COLOR_TITLE);
|
||||||
|
drawString("Press A to select, START to save and reboot", 10, 30, COLOR_WHITE);
|
||||||
|
|
||||||
|
const char *multiOptionsText[] = { "Screen-init brightness: 4( ) 3( ) 2( ) 1( )",
|
||||||
|
"New 3DS CPU: Off( ) Clock( ) L2( ) Clock+L2( )" };
|
||||||
|
|
||||||
|
const char *singleOptionsText[] = { "( ) Autoboot SysNAND",
|
||||||
|
"( ) Use SysNAND FIRM as default (A9LH-only)",
|
||||||
|
"( ) Force A9LH detection",
|
||||||
|
"( ) Use second EmuNAND as default",
|
||||||
|
"( ) Enable region/language emulation",
|
||||||
|
"( ) Use developer UNITINFO",
|
||||||
|
"( ) Show current NAND in System Settings",
|
||||||
|
"( ) Show GBA boot screen in patched AGB_FIRM",
|
||||||
|
"( ) Enable splash screen with no screen-init" };
|
||||||
|
|
||||||
|
struct multiOption {
|
||||||
|
int posXs[4];
|
||||||
|
int posY;
|
||||||
|
u32 enabled;
|
||||||
|
} multiOptions[] = {
|
||||||
|
{ .posXs = {26, 31, 36, 41} },
|
||||||
|
{ .posXs = {17, 26, 32, 44} }
|
||||||
|
};
|
||||||
|
|
||||||
|
//Calculate the amount of the various kinds of options and pre-select the first single one
|
||||||
|
u32 multiOptionsAmount = sizeof(multiOptions) / sizeof(struct multiOption),
|
||||||
|
singleOptionsAmount = sizeof(singleOptionsText) / sizeof(char *),
|
||||||
|
totalIndexes = multiOptionsAmount + singleOptionsAmount - 1,
|
||||||
|
selectedOption = multiOptionsAmount;
|
||||||
|
|
||||||
|
struct singleOption {
|
||||||
|
int posY;
|
||||||
|
u32 enabled;
|
||||||
|
} singleOptions[singleOptionsAmount];
|
||||||
|
|
||||||
|
//Parse the existing options
|
||||||
|
for(u32 i = 0; i < multiOptionsAmount; i++)
|
||||||
|
multiOptions[i].enabled = MULTICONFIG(i);
|
||||||
|
for(u32 i = 0; i < singleOptionsAmount; i++)
|
||||||
|
singleOptions[i].enabled = CONFIG(i);
|
||||||
|
|
||||||
|
//Character to display a selected option
|
||||||
|
char selected = 'x';
|
||||||
|
|
||||||
|
int endPos = 42;
|
||||||
|
|
||||||
|
//Display all the multiple choice options in white
|
||||||
|
for(u32 i = 0; i < multiOptionsAmount; i++)
|
||||||
|
{
|
||||||
|
multiOptions[i].posY = endPos + SPACING_Y;
|
||||||
|
endPos = drawString(multiOptionsText[i], 10, multiOptions[i].posY, COLOR_WHITE);
|
||||||
|
drawCharacter(selected, 10 + multiOptions[i].posXs[multiOptions[i].enabled] * SPACING_X, multiOptions[i].posY, COLOR_WHITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
endPos += SPACING_Y / 2;
|
||||||
|
u32 color = COLOR_RED;
|
||||||
|
|
||||||
|
//Display all the normal options in white except for the first one
|
||||||
|
for(u32 i = 0; i < singleOptionsAmount; i++)
|
||||||
|
{
|
||||||
|
singleOptions[i].posY = endPos + SPACING_Y;
|
||||||
|
endPos = drawString(singleOptionsText[i], 10, singleOptions[i].posY, color);
|
||||||
|
if(singleOptions[i].enabled) drawCharacter(selected, 10 + SPACING_X, singleOptions[i].posY, color);
|
||||||
|
color = COLOR_WHITE;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 pressed = 0;
|
||||||
|
|
||||||
|
//Boring configuration menu
|
||||||
|
while(pressed != BUTTON_START)
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
pressed = waitInput();
|
||||||
|
}
|
||||||
|
while(!(pressed & MENU_BUTTONS));
|
||||||
|
|
||||||
|
if(pressed != BUTTON_A)
|
||||||
|
{
|
||||||
|
//Remember the previously selected option
|
||||||
|
u32 oldSelectedOption = selectedOption;
|
||||||
|
|
||||||
|
switch(pressed)
|
||||||
|
{
|
||||||
|
case BUTTON_UP:
|
||||||
|
selectedOption = !selectedOption ? totalIndexes : selectedOption - 1;
|
||||||
|
break;
|
||||||
|
case BUTTON_DOWN:
|
||||||
|
selectedOption = selectedOption == totalIndexes ? 0 : selectedOption + 1;
|
||||||
|
break;
|
||||||
|
case BUTTON_LEFT:
|
||||||
|
selectedOption = 0;
|
||||||
|
break;
|
||||||
|
case BUTTON_RIGHT:
|
||||||
|
selectedOption = totalIndexes;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(selectedOption == oldSelectedOption) continue;
|
||||||
|
|
||||||
|
//The user moved to a different option, print the old option in white and the new one in red. Only print 'x's if necessary
|
||||||
|
if(oldSelectedOption < multiOptionsAmount)
|
||||||
|
{
|
||||||
|
drawString(multiOptionsText[oldSelectedOption], 10, multiOptions[oldSelectedOption].posY, COLOR_WHITE);
|
||||||
|
drawCharacter(selected, 10 + multiOptions[oldSelectedOption].posXs[multiOptions[oldSelectedOption].enabled] * SPACING_X, multiOptions[oldSelectedOption].posY, COLOR_WHITE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
u32 singleOldSelected = oldSelectedOption - multiOptionsAmount;
|
||||||
|
drawString(singleOptionsText[singleOldSelected], 10, singleOptions[singleOldSelected].posY, COLOR_WHITE);
|
||||||
|
if(singleOptions[singleOldSelected].enabled) drawCharacter(selected, 10 + SPACING_X, singleOptions[singleOldSelected].posY, COLOR_WHITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(selectedOption < multiOptionsAmount)
|
||||||
|
drawString(multiOptionsText[selectedOption], 10, multiOptions[selectedOption].posY, COLOR_RED);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
u32 singleSelected = selectedOption - multiOptionsAmount;
|
||||||
|
drawString(singleOptionsText[singleSelected], 10, singleOptions[singleSelected].posY, COLOR_RED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//The selected option's status changed, print the 'x's accordingly
|
||||||
|
if(selectedOption < multiOptionsAmount)
|
||||||
|
{
|
||||||
|
u32 oldEnabled = multiOptions[selectedOption].enabled;
|
||||||
|
drawCharacter(selected, 10 + multiOptions[selectedOption].posXs[oldEnabled] * SPACING_X, multiOptions[selectedOption].posY, COLOR_BLACK);
|
||||||
|
multiOptions[selectedOption].enabled = oldEnabled == 3 ? 0 : oldEnabled + 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
u32 oldEnabled = singleOptions[selectedOption - multiOptionsAmount].enabled;
|
||||||
|
singleOptions[selectedOption - multiOptionsAmount].enabled = !oldEnabled;
|
||||||
|
if(oldEnabled) drawCharacter(selected, 10 + SPACING_X, singleOptions[selectedOption - multiOptionsAmount].posY, COLOR_BLACK);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//In any case, if the current option is enabled (or a multiple choice option is selected) we must display a red 'x'
|
||||||
|
if(selectedOption < multiOptionsAmount)
|
||||||
|
drawCharacter(selected, 10 + multiOptions[selectedOption].posXs[multiOptions[selectedOption].enabled] * SPACING_X, multiOptions[selectedOption].posY, COLOR_RED);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
u32 singleSelected = selectedOption - multiOptionsAmount;
|
||||||
|
if(singleOptions[singleSelected].enabled) drawCharacter(selected, 10 + SPACING_X, singleOptions[singleSelected].posY, COLOR_RED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Preserve the last-used boot options (last 12 bits)
|
||||||
|
config &= 0x3F;
|
||||||
|
|
||||||
|
//Parse and write the new configuration
|
||||||
|
for(u32 i = 0; i < multiOptionsAmount; i++)
|
||||||
|
config |= multiOptions[i].enabled << (i * 2 + 6);
|
||||||
|
for(u32 i = 0; i < singleOptionsAmount; i++)
|
||||||
|
config |= singleOptions[i].enabled << (i + 16);
|
||||||
|
|
||||||
|
fileWrite(&config, configPath, 4);
|
||||||
|
|
||||||
|
//Zero the last booted FIRM flag
|
||||||
|
CFG_BOOTENV = 0;
|
||||||
|
|
||||||
|
mcuReboot();
|
||||||
|
}
|
||||||
19
source/config.h
Normal file
19
source/config.h
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* config.h
|
||||||
|
* by Aurora Wright
|
||||||
|
* Copyright (c) 2016 All Rights Reserved
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
#define CFG_BOOTENV (*(vu32 *)0x10010000)
|
||||||
|
|
||||||
|
#define CONFIG(a) ((config >> (a + 16)) & 1)
|
||||||
|
#define MULTICONFIG(a) ((config >> (a * 2 + 6)) & 3)
|
||||||
|
#define BOOTCONFIG(a, b) ((config >> a) & b)
|
||||||
|
|
||||||
|
extern u32 config;
|
||||||
|
|
||||||
|
void configureCFW(const char *configPath);
|
||||||
179
source/crypto.c
179
source/crypto.c
@@ -229,80 +229,173 @@ static void aes(void *dst, const void *src, u32 blockCount, void *iv, u32 mode,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void sha_wait_idle()
|
||||||
|
{
|
||||||
|
while(*REG_SHA_CNT & 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sha(void *res, const void *src, u32 size, u32 mode)
|
||||||
|
{
|
||||||
|
sha_wait_idle();
|
||||||
|
*REG_SHA_CNT = mode | SHA_CNT_OUTPUT_ENDIAN | SHA_NORMAL_ROUND;
|
||||||
|
|
||||||
|
const u32 *src32 = (const u32 *)src;
|
||||||
|
int i;
|
||||||
|
while(size >= 0x40)
|
||||||
|
{
|
||||||
|
sha_wait_idle();
|
||||||
|
for(i = 0; i < 4; ++i)
|
||||||
|
{
|
||||||
|
*REG_SHA_INFIFO = *src32++;
|
||||||
|
*REG_SHA_INFIFO = *src32++;
|
||||||
|
*REG_SHA_INFIFO = *src32++;
|
||||||
|
*REG_SHA_INFIFO = *src32++;
|
||||||
|
}
|
||||||
|
|
||||||
|
size -= 0x40;
|
||||||
|
}
|
||||||
|
|
||||||
|
sha_wait_idle();
|
||||||
|
memcpy((void *)REG_SHA_INFIFO, src32, size);
|
||||||
|
|
||||||
|
*REG_SHA_CNT = (*REG_SHA_CNT & ~SHA_NORMAL_ROUND) | SHA_FINAL_ROUND;
|
||||||
|
|
||||||
|
while(*REG_SHA_CNT & SHA_FINAL_ROUND);
|
||||||
|
sha_wait_idle();
|
||||||
|
|
||||||
|
u32 hashSize = SHA_256_HASH_SIZE;
|
||||||
|
if(mode == SHA_224_MODE)
|
||||||
|
hashSize = SHA_224_HASH_SIZE;
|
||||||
|
else if(mode == SHA_1_MODE)
|
||||||
|
hashSize = SHA_1_HASH_SIZE;
|
||||||
|
|
||||||
|
memcpy(res, (void *)REG_SHA_HASH, hashSize);
|
||||||
|
}
|
||||||
|
|
||||||
/****************************************************************
|
/****************************************************************
|
||||||
* Nand/FIRM Crypto stuff
|
* Nand/FIRM Crypto stuff
|
||||||
****************************************************************/
|
****************************************************************/
|
||||||
|
|
||||||
//Nand key#2 (0x12C10)
|
static u8 nandCTR[0x10],
|
||||||
static const u8 key2[0x10] = {
|
nandSlot;
|
||||||
0x42, 0x3F, 0x81, 0x7A, 0x23, 0x52, 0x58, 0x31, 0x6E, 0x75, 0x8E, 0x3A, 0x39, 0x43, 0x2E, 0xD0
|
|
||||||
};
|
|
||||||
|
|
||||||
//Get Nand CTR key
|
static u32 fatStart;
|
||||||
static void getNandCTR(u8 *buf, u32 console){
|
|
||||||
u8 *addr = (console ? (u8 *)0x080D8BBC : (u8 *)0x080D797C) + 0x0F;
|
//Initialize the CTRNAND crypto
|
||||||
for(u8 keyLen = 0x10; keyLen; keyLen--)
|
void ctrNandInit(void)
|
||||||
*(buf++) = *(addr--);
|
{
|
||||||
|
u8 cid[0x10];
|
||||||
|
u8 shaSum[0x20];
|
||||||
|
|
||||||
|
sdmmc_get_cid(1, (u32 *)cid);
|
||||||
|
sha(shaSum, cid, 0x10, SHA_256_MODE);
|
||||||
|
memcpy(nandCTR, shaSum, 0x10);
|
||||||
|
|
||||||
|
if(console)
|
||||||
|
{
|
||||||
|
u8 keyY0x5[0x10] = {0x4D, 0x80, 0x4F, 0x4E, 0x99, 0x90, 0x19, 0x46, 0x13, 0xA2, 0x04, 0xAC, 0x58, 0x44, 0x60, 0xBE};
|
||||||
|
aes_setkey(0x05, keyY0x5, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||||
|
nandSlot = 0x05;
|
||||||
|
fatStart = 0x5CAD7;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nandSlot = 0x04;
|
||||||
|
fatStart = 0x5CAE5;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Read firm0 from NAND and write to buffer
|
//Read and decrypt from the selected CTRNAND
|
||||||
void nandFirm0(u8 *outbuf, u32 size, u32 console){
|
u32 ctrNandRead(u32 sector, u32 sectorCount, u8 *outbuf)
|
||||||
u8 CTR[0x10];
|
{
|
||||||
getNandCTR(CTR, console);
|
u8 tmpCTR[0x10];
|
||||||
|
memcpy(tmpCTR, nandCTR, 0x10);
|
||||||
|
aes_advctr(tmpCTR, ((sector + fatStart) * 0x200) / AES_BLOCK_SIZE, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||||
|
|
||||||
sdmmc_nand_readsectors(0x0B130000 / 0x200, size / 0x200, outbuf);
|
//Read
|
||||||
|
u32 result;
|
||||||
|
if(!firmSource)
|
||||||
|
result = sdmmc_nand_readsectors(sector + fatStart, sectorCount, outbuf);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sector += emuOffset;
|
||||||
|
result = sdmmc_sdcard_readsectors(sector + fatStart, sectorCount, outbuf);
|
||||||
|
}
|
||||||
|
|
||||||
aes_advctr(CTR, 0x0B130000/0x10, AES_INPUT_BE | AES_INPUT_NORMAL);
|
//Decrypt
|
||||||
aes_use_keyslot(0x06);
|
aes_use_keyslot(nandSlot);
|
||||||
aes(outbuf, outbuf, size / AES_BLOCK_SIZE, CTR, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
|
aes(outbuf, outbuf, sectorCount * 0x200 / AES_BLOCK_SIZE, tmpCTR, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Decrypts the N3DS arm9bin
|
//Decrypt a FIRM ExeFS
|
||||||
void decryptArm9Bin(u8 *arm9Section, u32 mode){
|
void decryptExeFs(u8 *inbuf)
|
||||||
|
{
|
||||||
|
u8 *exeFsOffset = inbuf + *(u32 *)(inbuf + 0x1A0) * 0x200;
|
||||||
|
u32 exeFsSize = *(u32 *)(inbuf + 0x1A4) * 0x200;
|
||||||
|
u8 ncchCTR[0x10] = {0};
|
||||||
|
|
||||||
|
for(u32 i = 0; i < 8; i++)
|
||||||
|
ncchCTR[7 - i] = *(inbuf + 0x108 + i);
|
||||||
|
ncchCTR[8] = 2;
|
||||||
|
|
||||||
|
aes_setkey(0x2C, inbuf, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||||
|
aes_setiv(ncchCTR, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||||
|
aes_use_keyslot(0x2C);
|
||||||
|
aes(inbuf - 0x200, exeFsOffset, exeFsSize / AES_BLOCK_SIZE, ncchCTR, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
//ARM9Loader replacement
|
||||||
|
void arm9Loader(u8 *arm9Section, u32 mode)
|
||||||
|
{
|
||||||
//Firm keys
|
//Firm keys
|
||||||
u8 keyY[0x10];
|
u8 keyY[0x10];
|
||||||
u8 CTR[0x10];
|
u8 arm9BinCTR[0x10];
|
||||||
u8 slot = mode ? 0x16 : 0x15;
|
u8 arm9BinSlot = mode ? 0x16 : 0x15;
|
||||||
|
|
||||||
//Setup keys needed for arm9bin decryption
|
//Setup keys needed for arm9bin decryption
|
||||||
memcpy(keyY, arm9Section + 0x10, 0x10);
|
memcpy(keyY, arm9Section + 0x10, 0x10);
|
||||||
memcpy(CTR, arm9Section + 0x20, 0x10);
|
memcpy(arm9BinCTR, arm9Section + 0x20, 0x10);
|
||||||
u32 size = 0;
|
|
||||||
|
//Calculate the size of the ARM9 binary
|
||||||
|
u32 arm9BinSize = 0;
|
||||||
//http://stackoverflow.com/questions/12791077/atoi-implementation-in-c
|
//http://stackoverflow.com/questions/12791077/atoi-implementation-in-c
|
||||||
for(u8 *tmp = arm9Section + 0x30; *tmp; tmp++)
|
for(u8 *tmp = arm9Section + 0x30; *tmp; tmp++)
|
||||||
size = (size << 3) + (size << 1) + (*tmp) - '0';
|
arm9BinSize = (arm9BinSize << 3) + (arm9BinSize << 1) + *tmp - '0';
|
||||||
|
|
||||||
if(mode){
|
if(mode)
|
||||||
|
{
|
||||||
|
const u8 key2[0x10] = {0x42, 0x3F, 0x81, 0x7A, 0x23, 0x52, 0x58, 0x31, 0x6E, 0x75, 0x8E, 0x3A, 0x39, 0x43, 0x2E, 0xD0};
|
||||||
u8 keyX[0x10];
|
u8 keyX[0x10];
|
||||||
|
|
||||||
//Set 0x11 to key2 for the arm9bin and misc keys
|
//Set 0x11 to key2 for the arm9bin and misc keys
|
||||||
aes_setkey(0x11, key2, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL);
|
aes_setkey(0x11, key2, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||||
aes_use_keyslot(0x11);
|
aes_use_keyslot(0x11);
|
||||||
aes(keyX, arm9Section + 0x60, 1, NULL, AES_ECB_DECRYPT_MODE, 0);
|
aes(keyX, arm9Section + 0x60, 1, NULL, AES_ECB_DECRYPT_MODE, 0);
|
||||||
aes_setkey(slot, keyX, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
aes_setkey(arm9BinSlot, keyX, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
aes_setkey(slot, keyY, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL);
|
aes_setkey(arm9BinSlot, keyY, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||||
aes_setiv(CTR, AES_INPUT_BE | AES_INPUT_NORMAL);
|
aes_setiv(arm9BinCTR, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||||
aes_use_keyslot(slot);
|
aes_use_keyslot(arm9BinSlot);
|
||||||
|
|
||||||
//Decrypt arm9bin
|
//Decrypt arm9bin
|
||||||
aes(arm9Section + 0x800, arm9Section + 0x800, size/AES_BLOCK_SIZE, CTR, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
|
aes(arm9Section + 0x800, arm9Section + 0x800, arm9BinSize / AES_BLOCK_SIZE, arm9BinCTR, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||||
}
|
|
||||||
|
|
||||||
//Sets the N3DS 9.6 KeyXs
|
//Set >=9.6 KeyXs
|
||||||
void setKeyXs(u8 *arm9Section){
|
if(mode)
|
||||||
|
{
|
||||||
|
u8 keyData[] = {0xDD, 0xDA, 0xA4, 0xC6, 0x2C, 0xC4, 0x50, 0xE9, 0xDA, 0xB6, 0x9B, 0x0D, 0x9D, 0x2A, 0x21, 0x98};
|
||||||
|
u8 decKey[0x10];
|
||||||
|
|
||||||
u8 *keyData = arm9Section + 0x89814;
|
//Set keys 0x19..0x1F keyXs
|
||||||
u8 *decKey = keyData + 0x10;
|
aes_use_keyslot(0x11);
|
||||||
|
for(u8 slot = 0x19; slot < 0x20; slot++)
|
||||||
//Set keys 0x19..0x1F keyXs
|
{
|
||||||
aes_setkey(0x11, key2, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL);
|
aes(decKey, keyData, 1, NULL, AES_ECB_DECRYPT_MODE, 0);
|
||||||
aes_use_keyslot(0x11);
|
aes_setkey(slot, decKey, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||||
for(u8 slot = 0x19; slot < 0x20; slot++){
|
keyData[0xF] += 1;
|
||||||
aes(decKey, keyData, 1, NULL, AES_ECB_DECRYPT_MODE, 0);
|
}
|
||||||
aes_setkey(slot, decKey, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
|
||||||
*(keyData + 0xF) += 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -53,7 +53,37 @@
|
|||||||
#define AES_KEYX 1
|
#define AES_KEYX 1
|
||||||
#define AES_KEYY 2
|
#define AES_KEYY 2
|
||||||
|
|
||||||
//NAND/FIRM stuff
|
/**************************SHA****************************/
|
||||||
void nandFirm0(u8 *outbuf, u32 size, u32 console);
|
#define REG_SHA_CNT ((vu32 *)0x1000A000)
|
||||||
void decryptArm9Bin(u8 *arm9Section, u32 mode);
|
#define REG_SHA_BLKCNT ((vu32 *)0x1000A004)
|
||||||
void setKeyXs(u8 *arm9Section);
|
#define REG_SHA_HASH ((vu32 *)0x1000A040)
|
||||||
|
#define REG_SHA_INFIFO ((vu32 *)0x1000A080)
|
||||||
|
|
||||||
|
#define SHA_CNT_STATE 0x00000003
|
||||||
|
#define SHA_CNT_UNK2 0x00000004
|
||||||
|
#define SHA_CNT_OUTPUT_ENDIAN 0x00000008
|
||||||
|
#define SHA_CNT_MODE 0x00000030
|
||||||
|
#define SHA_CNT_ENABLE 0x00010000
|
||||||
|
#define SHA_CNT_ACTIVE 0x00020000
|
||||||
|
|
||||||
|
#define SHA_HASH_READY 0x00000000
|
||||||
|
#define SHA_NORMAL_ROUND 0x00000001
|
||||||
|
#define SHA_FINAL_ROUND 0x00000002
|
||||||
|
|
||||||
|
#define SHA_OUTPUT_BE SHA_CNT_OUTPUT_ENDIAN
|
||||||
|
#define SHA_OUTPUT_LE 0
|
||||||
|
|
||||||
|
#define SHA_256_MODE 0
|
||||||
|
#define SHA_224_MODE 0x00000010
|
||||||
|
#define SHA_1_MODE 0x00000020
|
||||||
|
|
||||||
|
#define SHA_256_HASH_SIZE (256 / 8)
|
||||||
|
#define SHA_224_HASH_SIZE (224 / 8)
|
||||||
|
#define SHA_1_HASH_SIZE (160 / 8)
|
||||||
|
|
||||||
|
extern u32 emuOffset, console, firmSource;
|
||||||
|
|
||||||
|
void ctrNandInit(void);
|
||||||
|
u32 ctrNandRead(u32 sector, u32 sectorCount, u8 *outbuf);
|
||||||
|
void decryptExeFs(u8 *inbuf);
|
||||||
|
void arm9Loader(u8 *arm9Section, u32 mode);
|
||||||
@@ -7,6 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "draw.h"
|
#include "draw.h"
|
||||||
|
#include "screeninit.h"
|
||||||
#include "fs.h"
|
#include "fs.h"
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include "font.h"
|
#include "font.h"
|
||||||
@@ -20,59 +21,70 @@ static const struct fb {
|
|||||||
u8 *bottom;
|
u8 *bottom;
|
||||||
} *const fb = (struct fb *)0x23FFFE00;
|
} *const fb = (struct fb *)0x23FFFE00;
|
||||||
|
|
||||||
static int strlen(const char *string){
|
static inline int strlen(const char *string)
|
||||||
|
{
|
||||||
char *stringEnd = (char *)string;
|
char *stringEnd = (char *)string;
|
||||||
while(*stringEnd) stringEnd++;
|
while(*stringEnd) stringEnd++;
|
||||||
|
|
||||||
return stringEnd - string;
|
return stringEnd - string;
|
||||||
}
|
}
|
||||||
|
|
||||||
void clearScreens(void){
|
void clearScreens(void)
|
||||||
|
{
|
||||||
memset32(fb->top_left, 0, 0x46500);
|
memset32(fb->top_left, 0, 0x46500);
|
||||||
memset32(fb->top_right, 0, 0x46500);
|
memset32(fb->top_right, 0, 0x46500);
|
||||||
memset32(fb->bottom, 0, 0x38400);
|
memset32(fb->bottom, 0, 0x38400);
|
||||||
}
|
}
|
||||||
|
|
||||||
void loadSplash(void){
|
void loadSplash(void)
|
||||||
clearScreens();
|
{
|
||||||
|
initScreens();
|
||||||
|
|
||||||
//Don't delay boot if no splash image is on the SD
|
//Don't delay boot if no splash image is on the SD
|
||||||
if(fileRead(fb->top_left, "/aurei/splash.bin", 0x46500) +
|
if(fileRead(fb->top_left, "/aurei/splash.bin", 0x46500) +
|
||||||
fileRead(fb->bottom, "/aurei/splashbottom.bin", 0x38400)){
|
fileRead(fb->bottom, "/aurei/splashbottom.bin", 0x38400))
|
||||||
u64 i = 0x1300000; while(--i) __asm("mov r0, r0"); //Less Ghetto sleep func
|
{
|
||||||
|
u64 i = 0x1400000;
|
||||||
|
while(--i) __asm("mov r0, r0"); //Less Ghetto sleep func
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void drawCharacter(char character, int posX, int posY, u32 color){
|
void drawCharacter(char character, int posX, int posY, u32 color)
|
||||||
|
{
|
||||||
u8 *const select = fb->top_left;
|
u8 *const select = fb->top_left;
|
||||||
|
|
||||||
for(int y = 0; y < 8; y++){
|
for(int y = 0; y < 8; y++)
|
||||||
|
{
|
||||||
char charPos = font[character * 8 + y];
|
char charPos = font[character * 8 + y];
|
||||||
|
|
||||||
for(int x = 7; x >= 0; x--){
|
for(int x = 7; x >= 0; x--)
|
||||||
int screenPos = (posX * SCREEN_TOP_HEIGHT * 3 + (SCREEN_TOP_HEIGHT - y - posY - 1) * 3) + (7 - x) * 3 * SCREEN_TOP_HEIGHT;
|
if ((charPos >> x) & 1)
|
||||||
|
{
|
||||||
|
int screenPos = (posX * SCREEN_TOP_HEIGHT * 3 + (SCREEN_TOP_HEIGHT - y - posY - 1) * 3) + (7 - x) * 3 * SCREEN_TOP_HEIGHT;
|
||||||
|
|
||||||
if ((charPos >> x) & 1) {
|
|
||||||
select[screenPos] = color >> 16;
|
select[screenPos] = color >> 16;
|
||||||
select[screenPos + 1] = color >> 8;
|
select[screenPos + 1] = color >> 8;
|
||||||
select[screenPos + 2] = color;
|
select[screenPos + 2] = color;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int drawString(const char *string, int posX, int posY, u32 color){
|
int drawString(const char *string, int posX, int posY, u32 color)
|
||||||
int length = strlen(string);
|
{
|
||||||
|
for(int i = 0, line_i = 0; i < strlen(string); i++, line_i++)
|
||||||
for(int i = 0, line_i = 0; i < length; i++, line_i++){
|
{
|
||||||
if(string[i] == '\n'){
|
if(string[i] == '\n')
|
||||||
|
{
|
||||||
posY += SPACING_Y;
|
posY += SPACING_Y;
|
||||||
line_i = 0;
|
line_i = 0;
|
||||||
i++;
|
i++;
|
||||||
} else if(line_i >= (SCREEN_TOP_WIDTH - posX) / SPACING_X){
|
}
|
||||||
|
else if(line_i >= (SCREEN_TOP_WIDTH - posX) / SPACING_X)
|
||||||
|
{
|
||||||
// Make sure we never get out of the screen.
|
// Make sure we never get out of the screen.
|
||||||
posY += SPACING_Y;
|
posY += SPACING_Y;
|
||||||
line_i = 2; // Little offset so we know the same string continues.
|
line_i = 2; //Little offset so we know the same string continues.
|
||||||
if(string[i] == ' ') i++; // Spaces at the start look weird
|
if(string[i] == ' ') i++; //Spaces at the start look weird
|
||||||
}
|
}
|
||||||
|
|
||||||
drawCharacter(string[i], posX + line_i * SPACING_X, posY, color);
|
drawCharacter(string[i], posX + line_i * SPACING_X, posY, color);
|
||||||
|
|||||||
@@ -10,8 +10,12 @@
|
|||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
#define SPACING_Y 10
|
#define SPACING_Y 10
|
||||||
#define SPACING_X 8
|
#define SPACING_X 8
|
||||||
|
#define COLOR_TITLE 0xFF9900
|
||||||
|
#define COLOR_WHITE 0xFFFFFF
|
||||||
|
#define COLOR_RED 0x0000FF
|
||||||
|
#define COLOR_BLACK 0x000000
|
||||||
|
|
||||||
void loadSplash(void);
|
void loadSplash(void);
|
||||||
void clearScreens(void);
|
void clearScreens(void);
|
||||||
|
|||||||
@@ -8,32 +8,45 @@
|
|||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include "fatfs/sdmmc/sdmmc.h"
|
#include "fatfs/sdmmc/sdmmc.h"
|
||||||
|
|
||||||
void getEmunandSect(u32 *off, u32 *head, u32 emuNAND){
|
void getEmunandSect(u32 *off, u32 *head, u32 *emuNAND)
|
||||||
u8 *const temp = (u8 *)0x24300000;
|
{
|
||||||
|
static u8 *const temp = (u8 *)0x24300000;
|
||||||
|
|
||||||
u32 nandSize = getMMCDevice(0)->total_size;
|
const u32 nandSize = getMMCDevice(0)->total_size;
|
||||||
u32 nandOffset = emuNAND == 1 ? 0 :
|
u32 nandOffset = *emuNAND == 1 ? 0 :
|
||||||
(nandSize > 0x200000 ? 0x400000 : 0x200000);
|
(nandSize > 0x200000 ? 0x400000 : 0x200000);
|
||||||
|
|
||||||
//Check for RedNAND
|
//Check for RedNAND
|
||||||
if(sdmmc_sdcard_readsectors(nandOffset + 1, 1, temp) == 0){
|
if(sdmmc_sdcard_readsectors(nandOffset + 1, 1, temp) == 0)
|
||||||
if(*(u32 *)(temp + 0x100) == NCSD_MAGIC){
|
{
|
||||||
|
if(*(u32 *)(temp + 0x100) == NCSD_MAGIC)
|
||||||
|
{
|
||||||
*off = nandOffset + 1;
|
*off = nandOffset + 1;
|
||||||
*head = nandOffset + 1;
|
*head = nandOffset + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Check for Gateway emuNAND
|
//Check for Gateway emuNAND
|
||||||
else if(sdmmc_sdcard_readsectors(nandOffset + nandSize, 1, temp) == 0){
|
else if(sdmmc_sdcard_readsectors(nandOffset + nandSize, 1, temp) == 0)
|
||||||
if(*(u32 *)(temp + 0x100) == NCSD_MAGIC){
|
{
|
||||||
|
if(*(u32 *)(temp + 0x100) == NCSD_MAGIC)
|
||||||
|
{
|
||||||
*off = nandOffset;
|
*off = nandOffset;
|
||||||
*head = nandOffset + nandSize;
|
*head = nandOffset + nandSize;
|
||||||
}
|
}
|
||||||
//Fallback to the first emuNAND if there's no second one
|
|
||||||
else if(emuNAND == 2) getEmunandSect(off, head, 1);
|
/* Fallback to the first emuNAND if there's no second one,
|
||||||
|
or to SysNAND if there isn't any */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
(*emuNAND)--;
|
||||||
|
if(*emuNAND) getEmunandSect(off, head, emuNAND);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 getSDMMC(u8 *pos, u32 size){
|
u32 getSDMMC(u8 *pos, u32 size)
|
||||||
|
{
|
||||||
//Look for struct code
|
//Look for struct code
|
||||||
const u8 pattern[] = {0x21, 0x20, 0x18, 0x20};
|
const u8 pattern[] = {0x21, 0x20, 0x18, 0x20};
|
||||||
const u8 *off = memsearch(pos, pattern, size, 4) - 1;
|
const u8 *off = memsearch(pos, pattern, size, 4) - 1;
|
||||||
@@ -41,7 +54,8 @@ u32 getSDMMC(u8 *pos, u32 size){
|
|||||||
return *(u32 *)(off + 0x0A) + *(u32 *)(off + 0x0E);
|
return *(u32 *)(off + 0x0A) + *(u32 *)(off + 0x0E);
|
||||||
}
|
}
|
||||||
|
|
||||||
void getEmuRW(u8 *pos, u32 size, u32 *readOff, u32 *writeOff){
|
void getEmuRW(u8 *pos, u32 size, u32 *readOff, u32 *writeOff)
|
||||||
|
{
|
||||||
//Look for read/write code
|
//Look for read/write code
|
||||||
const u8 pattern[] = {0x1E, 0x00, 0xC8, 0x05};
|
const u8 pattern[] = {0x1E, 0x00, 0xC8, 0x05};
|
||||||
|
|
||||||
@@ -49,14 +63,16 @@ void getEmuRW(u8 *pos, u32 size, u32 *readOff, u32 *writeOff){
|
|||||||
*writeOff = (u32)memsearch((u8 *)(*readOff + 0xA), pattern, 0x100, 4) - 6;
|
*writeOff = (u32)memsearch((u8 *)(*readOff + 0xA), pattern, 0x100, 4) - 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 *getMPU(u8 *pos, u32 size){
|
u32 *getMPU(u8 *pos, u32 size)
|
||||||
|
{
|
||||||
//Look for MPU pattern
|
//Look for MPU pattern
|
||||||
const u8 pattern[] = {0x03, 0x00, 0x24, 0x00};
|
const u8 pattern[] = {0x03, 0x00, 0x24, 0x00};
|
||||||
|
|
||||||
return (u32 *)memsearch(pos, pattern, size, 4);
|
return (u32 *)memsearch(pos, pattern, size, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
void *getEmuCode(u8 *proc9Offset){
|
void *getEmuCode(u8 *proc9Offset)
|
||||||
|
{
|
||||||
const u8 pattern[] = {0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00};
|
const u8 pattern[] = {0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00};
|
||||||
|
|
||||||
//Looking for the last free space before Process9
|
//Looking for the last free space before Process9
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
#define NCSD_MAGIC (0x4453434E)
|
#define NCSD_MAGIC (0x4453434E)
|
||||||
|
|
||||||
void getEmunandSect(u32 *off, u32 *head, u32 emuNAND);
|
void getEmunandSect(u32 *off, u32 *head, u32 *emuNAND);
|
||||||
u32 getSDMMC(u8 *pos, u32 size);
|
u32 getSDMMC(u8 *pos, u32 size);
|
||||||
void getEmuRW(u8 *pos, u32 size, u32 *readOff, u32 *writeOff);
|
void getEmuRW(u8 *pos, u32 size, u32 *readOff, u32 *writeOff);
|
||||||
u32 *getMPU(u8 *pos, u32 size);
|
u32 *getMPU(u8 *pos, u32 size);
|
||||||
|
|||||||
@@ -10,6 +10,9 @@
|
|||||||
#include "diskio.h" /* FatFs lower layer API */
|
#include "diskio.h" /* FatFs lower layer API */
|
||||||
#include "sdmmc/sdmmc.h"
|
#include "sdmmc/sdmmc.h"
|
||||||
|
|
||||||
|
/* Definitions of physical drive number for each media */
|
||||||
|
#define SDCARD 0
|
||||||
|
#define CTRNAND 1
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------*/
|
/*-----------------------------------------------------------------------*/
|
||||||
/* Get Drive Status */
|
/* Get Drive Status */
|
||||||
@@ -34,7 +37,16 @@ DSTATUS disk_initialize (
|
|||||||
BYTE pdrv /* Physical drive nmuber to identify the drive */
|
BYTE pdrv /* Physical drive nmuber to identify the drive */
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
sdmmc_sdcard_init();
|
switch(pdrv)
|
||||||
|
{
|
||||||
|
case SDCARD:
|
||||||
|
sdmmc_sdcard_init();
|
||||||
|
break;
|
||||||
|
case CTRNAND:
|
||||||
|
ctrNandInit();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
return RES_OK;
|
return RES_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,11 +64,19 @@ DRESULT disk_read (
|
|||||||
UINT count /* Number of sectors to read */
|
UINT count /* Number of sectors to read */
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if (sdmmc_sdcard_readsectors(sector, count, buff)) {
|
switch(pdrv)
|
||||||
return RES_PARERR;
|
{
|
||||||
}
|
case SDCARD:
|
||||||
|
if(sdmmc_sdcard_readsectors(sector, count, (BYTE *)buff))
|
||||||
|
return RES_PARERR;
|
||||||
|
break;
|
||||||
|
case CTRNAND:
|
||||||
|
if(ctrNandRead(sector, count, (BYTE *)buff))
|
||||||
|
return RES_PARERR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
return RES_OK;
|
return RES_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -74,11 +94,10 @@ DRESULT disk_write (
|
|||||||
UINT count /* Number of sectors to write */
|
UINT count /* Number of sectors to write */
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if (sdmmc_sdcard_writesectors(sector, count, (BYTE *)buff)) {
|
if(pdrv == SDCARD && sdmmc_sdcard_writesectors(sector, count, (BYTE *)buff))
|
||||||
return RES_PARERR;
|
return RES_PARERR;
|
||||||
}
|
|
||||||
|
|
||||||
return RES_OK;
|
return RES_OK;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
565
source/fatfs/ff.c
Normal file → Executable file
565
source/fatfs/ff.c
Normal file → Executable file
File diff suppressed because it is too large
Load Diff
6
source/fatfs/ff.h
Normal file → Executable file
6
source/fatfs/ff.h
Normal file → Executable file
@@ -1,5 +1,5 @@
|
|||||||
/*---------------------------------------------------------------------------/
|
/*---------------------------------------------------------------------------/
|
||||||
/ FatFs - FAT file system module include R0.11 (C)ChaN, 2015
|
/ FatFs - FAT file system module include R0.11a (C)ChaN, 2015
|
||||||
/----------------------------------------------------------------------------/
|
/----------------------------------------------------------------------------/
|
||||||
/ FatFs module is a free software that opened under license policy of
|
/ FatFs module is a free software that opened under license policy of
|
||||||
/ following conditions.
|
/ following conditions.
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
|
|
||||||
#ifndef _FATFS
|
#ifndef _FATFS
|
||||||
#define _FATFS 32020 /* Revision ID */
|
#define _FATFS 64180 /* Revision ID */
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@@ -200,7 +200,7 @@ typedef enum {
|
|||||||
FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */
|
FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */
|
||||||
FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */
|
FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */
|
||||||
FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */
|
FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */
|
||||||
FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > _FS_SHARE */
|
FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > _FS_LOCK */
|
||||||
FR_INVALID_PARAMETER /* (19) Given parameter is invalid */
|
FR_INVALID_PARAMETER /* (19) Given parameter is invalid */
|
||||||
} FRESULT;
|
} FRESULT;
|
||||||
|
|
||||||
|
|||||||
75
source/fatfs/ffconf.h
Normal file → Executable file
75
source/fatfs/ffconf.h
Normal file → Executable file
@@ -1,21 +1,13 @@
|
|||||||
/*---------------------------------------------------------------------------/
|
/*---------------------------------------------------------------------------/
|
||||||
/ FatFs - FAT file system module configuration file R0.11 (C)ChaN, 2015
|
/ FatFs - FAT file system module configuration file R0.11a (C)ChaN, 2015
|
||||||
/---------------------------------------------------------------------------*/
|
/---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
#define _FFCONF 32020 /* Revision ID */
|
#define _FFCONF 64180 /* Revision ID */
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------/
|
/*---------------------------------------------------------------------------/
|
||||||
/ Functions and Buffer Configurations
|
/ Function Configurations
|
||||||
/---------------------------------------------------------------------------*/
|
/---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
#define _FS_TINY 0
|
|
||||||
/* This option switches tiny buffer configuration. (0:Normal or 1:Tiny)
|
|
||||||
/ At the tiny configuration, size of the file object (FIL) is reduced _MAX_SS
|
|
||||||
/ bytes. Instead of private sector buffer eliminated from the file object,
|
|
||||||
/ common sector buffer in the file system object (FATFS) is used for the file
|
|
||||||
/ data transfer. */
|
|
||||||
|
|
||||||
|
|
||||||
#define _FS_READONLY 0
|
#define _FS_READONLY 0
|
||||||
/* This option switches read-only configuration. (0:Read/Write or 1:Read-only)
|
/* This option switches read-only configuration. (0:Read/Write or 1:Read-only)
|
||||||
/ Read-only configuration removes writing API functions, f_write(), f_sync(),
|
/ Read-only configuration removes writing API functions, f_write(), f_sync(),
|
||||||
@@ -23,7 +15,7 @@
|
|||||||
/ and optional writing functions as well. */
|
/ and optional writing functions as well. */
|
||||||
|
|
||||||
|
|
||||||
#define _FS_MINIMIZE 0
|
#define _FS_MINIMIZE 1
|
||||||
/* This option defines minimization level to remove some basic API functions.
|
/* This option defines minimization level to remove some basic API functions.
|
||||||
/
|
/
|
||||||
/ 0: All basic functions are enabled.
|
/ 0: All basic functions are enabled.
|
||||||
@@ -42,7 +34,7 @@
|
|||||||
/ 2: Enable with LF-CRLF conversion. */
|
/ 2: Enable with LF-CRLF conversion. */
|
||||||
|
|
||||||
|
|
||||||
#define _USE_FIND 0
|
#define _USE_FIND 1
|
||||||
/* This option switches filtered directory read feature and related functions,
|
/* This option switches filtered directory read feature and related functions,
|
||||||
/ f_findfirst() and f_findnext(). (0:Disable or 1:Enable) */
|
/ f_findfirst() and f_findnext(). (0:Disable or 1:Enable) */
|
||||||
|
|
||||||
@@ -73,23 +65,28 @@
|
|||||||
/* This option specifies the OEM code page to be used on the target system.
|
/* This option specifies the OEM code page to be used on the target system.
|
||||||
/ Incorrect setting of the code page can cause a file open failure.
|
/ Incorrect setting of the code page can cause a file open failure.
|
||||||
/
|
/
|
||||||
/ 1 - ASCII (No extended character. Non-LFN cfg. only)
|
/ 1 - ASCII (No extended character. Non-LFN cfg. only)
|
||||||
/ 437 - U.S.
|
/ 437 - U.S.
|
||||||
/ 720 - Arabic
|
/ 720 - Arabic
|
||||||
/ 737 - Greek
|
/ 737 - Greek
|
||||||
/ 775 - Baltic
|
/ 771 - KBL
|
||||||
/ 850 - Multilingual Latin 1
|
/ 775 - Baltic
|
||||||
/ 852 - Latin 2
|
/ 850 - Latin 1
|
||||||
/ 855 - Cyrillic
|
/ 852 - Latin 2
|
||||||
/ 857 - Turkish
|
/ 855 - Cyrillic
|
||||||
/ 858 - Multilingual Latin 1 + Euro
|
/ 857 - Turkish
|
||||||
/ 862 - Hebrew
|
/ 860 - Portuguese
|
||||||
/ 866 - Russian
|
/ 861 - Icelandic
|
||||||
/ 874 - Thai
|
/ 862 - Hebrew
|
||||||
/ 932 - Japanese Shift_JIS (DBCS)
|
/ 863 - Canadian French
|
||||||
/ 936 - Simplified Chinese GBK (DBCS)
|
/ 864 - Arabic
|
||||||
/ 949 - Korean (DBCS)
|
/ 865 - Nordic
|
||||||
/ 950 - Traditional Chinese Big5 (DBCS)
|
/ 866 - Russian
|
||||||
|
/ 869 - Greek 2
|
||||||
|
/ 932 - Japanese (DBCS)
|
||||||
|
/ 936 - Simplified Chinese (DBCS)
|
||||||
|
/ 949 - Korean (DBCS)
|
||||||
|
/ 950 - Traditional Chinese (DBCS)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
@@ -115,7 +112,7 @@
|
|||||||
/ to 1. This option also affects behavior of string I/O functions. */
|
/ to 1. This option also affects behavior of string I/O functions. */
|
||||||
|
|
||||||
|
|
||||||
#define _STRF_ENCODE 0
|
#define _STRF_ENCODE 3
|
||||||
/* When _LFN_UNICODE is 1, this option selects the character encoding on the file to
|
/* When _LFN_UNICODE is 1, this option selects the character encoding on the file to
|
||||||
/ be read/written via string I/O functions, f_gets(), f_putc(), f_puts and f_printf().
|
/ be read/written via string I/O functions, f_gets(), f_putc(), f_puts and f_printf().
|
||||||
/
|
/
|
||||||
@@ -141,7 +138,7 @@
|
|||||||
/ Drive/Volume Configurations
|
/ Drive/Volume Configurations
|
||||||
/---------------------------------------------------------------------------*/
|
/---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
#define _VOLUMES 1
|
#define _VOLUMES 2
|
||||||
/* Number of volumes (logical drives) to be used. */
|
/* Number of volumes (logical drives) to be used. */
|
||||||
|
|
||||||
|
|
||||||
@@ -195,15 +192,23 @@
|
|||||||
/ System Configurations
|
/ System Configurations
|
||||||
/---------------------------------------------------------------------------*/
|
/---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#define _FS_TINY 0
|
||||||
|
/* This option switches tiny buffer configuration. (0:Normal or 1:Tiny)
|
||||||
|
/ At the tiny configuration, size of the file object (FIL) is reduced _MAX_SS
|
||||||
|
/ bytes. Instead of private sector buffer eliminated from the file object,
|
||||||
|
/ common sector buffer in the file system object (FATFS) is used for the file
|
||||||
|
/ data transfer. */
|
||||||
|
|
||||||
|
|
||||||
#define _FS_NORTC 1
|
#define _FS_NORTC 1
|
||||||
#define _NORTC_MON 2
|
#define _NORTC_MON 1
|
||||||
#define _NORTC_MDAY 1
|
#define _NORTC_MDAY 1
|
||||||
#define _NORTC_YEAR 2015
|
#define _NORTC_YEAR 2015
|
||||||
/* The _FS_NORTC option switches timestamp feature. If the system does not have
|
/* The _FS_NORTC option switches timestamp feature. If the system does not have
|
||||||
/ an RTC function or valid timestamp is not needed, set _FS_NORTC to 1 to disable
|
/ an RTC function or valid timestamp is not needed, set _FS_NORTC to 1 to disable
|
||||||
/ the timestamp feature. All objects modified by FatFs will have a fixed timestamp
|
/ the timestamp feature. All objects modified by FatFs will have a fixed timestamp
|
||||||
/ defined by _NORTC_MON, _NORTC_MDAY and _NORTC_YEAR.
|
/ defined by _NORTC_MON, _NORTC_MDAY and _NORTC_YEAR.
|
||||||
/ When timestamp feature is enabled (_FS_NORTC == 0), get_fattime() function need
|
/ When timestamp feature is enabled (_FS_NORTC == 0), get_fattime() function need
|
||||||
/ to be added to the project to read current time form RTC. _NORTC_MON,
|
/ to be added to the project to read current time form RTC. _NORTC_MON,
|
||||||
/ _NORTC_MDAY and _NORTC_YEAR have no effect.
|
/ _NORTC_MDAY and _NORTC_YEAR have no effect.
|
||||||
/ These options have no effect at read-only configuration (_FS_READONLY == 1). */
|
/ These options have no effect at read-only configuration (_FS_READONLY == 1). */
|
||||||
@@ -253,7 +258,7 @@
|
|||||||
/ * Byte order on the memory is little-endian.
|
/ * Byte order on the memory is little-endian.
|
||||||
/
|
/
|
||||||
/ If it is the case, _WORD_ACCESS can also be set to 1 to reduce code size.
|
/ If it is the case, _WORD_ACCESS can also be set to 1 to reduce code size.
|
||||||
/ Following table shows allowable settings of some processor types.
|
/ Following table shows allowable settings of some type of processors.
|
||||||
/
|
/
|
||||||
/ ARM7TDMI 0 *2 ColdFire 0 *1 V850E 0 *2
|
/ ARM7TDMI 0 *2 ColdFire 0 *1 V850E 0 *2
|
||||||
/ Cortex-M3 0 *3 Z80 0/1 V850ES 0/1
|
/ Cortex-M3 0 *3 Z80 0/1 V850ES 0/1
|
||||||
|
|||||||
10
source/fatfs/integer.h
Normal file → Executable file
10
source/fatfs/integer.h
Normal file → Executable file
@@ -5,26 +5,26 @@
|
|||||||
#ifndef _FF_INTEGER
|
#ifndef _FF_INTEGER
|
||||||
#define _FF_INTEGER
|
#define _FF_INTEGER
|
||||||
|
|
||||||
#ifdef _WIN32 /* FatFs development platform */
|
#ifdef _WIN32 /* Development platform */
|
||||||
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <tchar.h>
|
#include <tchar.h>
|
||||||
|
|
||||||
#else /* Embedded platform */
|
#else /* Embedded platform */
|
||||||
|
|
||||||
/* This type MUST be 8 bit */
|
/* This type MUST be 8-bit */
|
||||||
typedef unsigned char BYTE;
|
typedef unsigned char BYTE;
|
||||||
|
|
||||||
/* These types MUST be 16 bit */
|
/* These types MUST be 16-bit */
|
||||||
typedef short SHORT;
|
typedef short SHORT;
|
||||||
typedef unsigned short WORD;
|
typedef unsigned short WORD;
|
||||||
typedef unsigned short WCHAR;
|
typedef unsigned short WCHAR;
|
||||||
|
|
||||||
/* These types MUST be 16 bit or 32 bit */
|
/* These types MUST be 16-bit or 32-bit */
|
||||||
typedef int INT;
|
typedef int INT;
|
||||||
typedef unsigned int UINT;
|
typedef unsigned int UINT;
|
||||||
|
|
||||||
/* These types MUST be 32 bit */
|
/* These types MUST be 32-bit */
|
||||||
typedef long LONG;
|
typedef long LONG;
|
||||||
typedef unsigned long DWORD;
|
typedef unsigned long DWORD;
|
||||||
|
|
||||||
|
|||||||
348
source/fatfs/option/ccsbcs.c
Executable file
348
source/fatfs/option/ccsbcs.c
Executable file
@@ -0,0 +1,348 @@
|
|||||||
|
/*------------------------------------------------------------------------*/
|
||||||
|
/* Unicode - Local code bidirectional converter (C)ChaN, 2015 */
|
||||||
|
/* (SBCS code pages) */
|
||||||
|
/*------------------------------------------------------------------------*/
|
||||||
|
/* 437 U.S.
|
||||||
|
/ 720 Arabic
|
||||||
|
/ 737 Greek
|
||||||
|
/ 771 KBL
|
||||||
|
/ 775 Baltic
|
||||||
|
/ 850 Latin 1
|
||||||
|
/ 852 Latin 2
|
||||||
|
/ 855 Cyrillic
|
||||||
|
/ 857 Turkish
|
||||||
|
/ 860 Portuguese
|
||||||
|
/ 861 Icelandic
|
||||||
|
/ 862 Hebrew
|
||||||
|
/ 863 Canadian French
|
||||||
|
/ 864 Arabic
|
||||||
|
/ 865 Nordic
|
||||||
|
/ 866 Russian
|
||||||
|
/ 869 Greek 2
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../ff.h"
|
||||||
|
|
||||||
|
|
||||||
|
#if _CODE_PAGE == 437
|
||||||
|
#define _TBLDEF 1
|
||||||
|
static
|
||||||
|
const WCHAR Tbl[] = { /* CP437(0x80-0xFF) to Unicode conversion table */
|
||||||
|
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
|
||||||
|
0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192,
|
||||||
|
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
|
||||||
|
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
|
||||||
|
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
|
||||||
|
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
|
||||||
|
0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
|
||||||
|
0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
|
||||||
|
};
|
||||||
|
|
||||||
|
#elif _CODE_PAGE == 720
|
||||||
|
#define _TBLDEF 1
|
||||||
|
static
|
||||||
|
const WCHAR Tbl[] = { /* CP720(0x80-0xFF) to Unicode conversion table */
|
||||||
|
0x0000, 0x0000, 0x00E9, 0x00E2, 0x0000, 0x00E0, 0x0000, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x0000, 0x0000, 0x0000,
|
||||||
|
0x0000, 0x0651, 0x0652, 0x00F4, 0x00A4, 0x0640, 0x00FB, 0x00F9, 0x0621, 0x0622, 0x0623, 0x0624, 0x00A3, 0x0625, 0x0626, 0x0627,
|
||||||
|
0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F, 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x00AB, 0x00BB,
|
||||||
|
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
|
||||||
|
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
|
||||||
|
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
|
||||||
|
0x0636, 0x0637, 0x0638, 0x0639, 0x063A, 0x0641, 0x00B5, 0x0642, 0x0643, 0x0644, 0x0645, 0x0646, 0x0647, 0x0648, 0x0649, 0x064A,
|
||||||
|
0x2261, 0x064B, 0x064C, 0x064D, 0x064E, 0x064F, 0x0650, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
|
||||||
|
};
|
||||||
|
|
||||||
|
#elif _CODE_PAGE == 737
|
||||||
|
#define _TBLDEF 1
|
||||||
|
static
|
||||||
|
const WCHAR Tbl[] = { /* CP737(0x80-0xFF) to Unicode conversion table */
|
||||||
|
0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, 0x03A0,
|
||||||
|
0x03A1, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, 0x03B8,
|
||||||
|
0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0, 0x03C1, 0x03C3, 0x03C2, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8,
|
||||||
|
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
|
||||||
|
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
|
||||||
|
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
|
||||||
|
0x03C9, 0x03AC, 0x03AD, 0x03AE, 0x03CA, 0x03AF, 0x03CC, 0x03CD, 0x03CB, 0x03CE, 0x0386, 0x0388, 0x0389, 0x038A, 0x038C, 0x038E,
|
||||||
|
0x038F, 0x00B1, 0x2265, 0x2264, 0x03AA, 0x03AB, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
|
||||||
|
};
|
||||||
|
|
||||||
|
#elif _CODE_PAGE == 771
|
||||||
|
#define _TBLDEF 1
|
||||||
|
static
|
||||||
|
const WCHAR Tbl[] = { /* CP771(0x80-0xFF) to Unicode conversion table */
|
||||||
|
0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F,
|
||||||
|
0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F,
|
||||||
|
0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
|
||||||
|
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x2558, 0x2510,
|
||||||
|
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
|
||||||
|
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x0104, 0x0105, 0x010C, 0x010D,
|
||||||
|
0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F,
|
||||||
|
0x0118, 0x0119, 0x0116, 0x0117, 0x012E, 0x012F, 0x0160, 0x0161, 0x0172, 0x0173, 0x016A, 0x016B, 0x017D, 0x017E, 0x25A0, 0x00A0
|
||||||
|
};
|
||||||
|
|
||||||
|
#elif _CODE_PAGE == 775
|
||||||
|
#define _TBLDEF 1
|
||||||
|
static
|
||||||
|
const WCHAR Tbl[] = { /* CP775(0x80-0xFF) to Unicode conversion table */
|
||||||
|
0x0106, 0x00FC, 0x00E9, 0x0101, 0x00E4, 0x0123, 0x00E5, 0x0107, 0x0142, 0x0113, 0x0156, 0x0157, 0x012B, 0x0179, 0x00C4, 0x00C5,
|
||||||
|
0x00C9, 0x00E6, 0x00C6, 0x014D, 0x00F6, 0x0122, 0x00A2, 0x015A, 0x015B, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x00A4,
|
||||||
|
0x0100, 0x012A, 0x00F3, 0x017B, 0x017C, 0x017A, 0x201D, 0x00A6, 0x00A9, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x0141, 0x00AB, 0x00BB,
|
||||||
|
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x0104, 0x010C, 0x0118, 0x0116, 0x2563, 0x2551, 0x2557, 0x255D, 0x012E, 0x0160, 0x2510,
|
||||||
|
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0172, 0x016A, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x017D,
|
||||||
|
0x0105, 0x010D, 0x0119, 0x0117, 0x012F, 0x0161, 0x0173, 0x016B, 0x017E, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
|
||||||
|
0x00D3, 0x00DF, 0x014C, 0x0143, 0x00F5, 0x00D5, 0x00B5, 0x0144, 0x0136, 0x0137, 0x013B, 0x013C, 0x0146, 0x0112, 0x0145, 0x2019,
|
||||||
|
0x00AD, 0x00B1, 0x201C, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x201E, 0x00B0, 0x2219, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0
|
||||||
|
};
|
||||||
|
|
||||||
|
#elif _CODE_PAGE == 850
|
||||||
|
#define _TBLDEF 1
|
||||||
|
static
|
||||||
|
const WCHAR Tbl[] = { /* CP850(0x80-0xFF) to Unicode conversion table */
|
||||||
|
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
|
||||||
|
0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x0192,
|
||||||
|
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
|
||||||
|
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0, 0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510,
|
||||||
|
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
|
||||||
|
0x00F0, 0x00D0, 0x00CA, 0x00CB, 0x00C8, 0x0131, 0x00CD, 0x00CE, 0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580,
|
||||||
|
0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x00FE, 0x00DE, 0x00DA, 0x00DB, 0x00D9, 0x00FD, 0x00DD, 0x00AF, 0x00B4,
|
||||||
|
0x00AD, 0x00B1, 0x2017, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8, 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0
|
||||||
|
};
|
||||||
|
|
||||||
|
#elif _CODE_PAGE == 852
|
||||||
|
#define _TBLDEF 1
|
||||||
|
static
|
||||||
|
const WCHAR Tbl[] = { /* CP852(0x80-0xFF) to Unicode conversion table */
|
||||||
|
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x016F, 0x0107, 0x00E7, 0x0142, 0x00EB, 0x0150, 0x0151, 0x00EE, 0x0179, 0x00C4, 0x0106,
|
||||||
|
0x00C9, 0x0139, 0x013A, 0x00F4, 0x00F6, 0x013D, 0x013E, 0x015A, 0x015B, 0x00D6, 0x00DC, 0x0164, 0x0165, 0x0141, 0x00D7, 0x010D,
|
||||||
|
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x0104, 0x0105, 0x017D, 0x017E, 0x0118, 0x0119, 0x00AC, 0x017A, 0x010C, 0x015F, 0x00AB, 0x00BB,
|
||||||
|
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x011A, 0x015E, 0x2563, 0x2551, 0x2557, 0x255D, 0x017B, 0x017C, 0x2510,
|
||||||
|
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0102, 0x0103, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
|
||||||
|
0x0111, 0x0110, 0x010E, 0x00CB, 0x010F, 0x0147, 0x00CD, 0x00CE, 0x011B, 0x2518, 0x250C, 0x2588, 0x2584, 0x0162, 0x016E, 0x2580,
|
||||||
|
0x00D3, 0x00DF, 0x00D4, 0x0143, 0x0144, 0x0148, 0x0160, 0x0161, 0x0154, 0x00DA, 0x0155, 0x0170, 0x00FD, 0x00DD, 0x0163, 0x00B4,
|
||||||
|
0x00AD, 0x02DD, 0x02DB, 0x02C7, 0x02D8, 0x00A7, 0x00F7, 0x00B8, 0x00B0, 0x00A8, 0x02D9, 0x0171, 0x0158, 0x0159, 0x25A0, 0x00A0
|
||||||
|
};
|
||||||
|
|
||||||
|
#elif _CODE_PAGE == 855
|
||||||
|
#define _TBLDEF 1
|
||||||
|
static
|
||||||
|
const WCHAR Tbl[] = { /* CP855(0x80-0xFF) to Unicode conversion table */
|
||||||
|
0x0452, 0x0402, 0x0453, 0x0403, 0x0451, 0x0401, 0x0454, 0x0404, 0x0455, 0x0405, 0x0456, 0x0406, 0x0457, 0x0407, 0x0458, 0x0408,
|
||||||
|
0x0459, 0x0409, 0x045A, 0x040A, 0x045B, 0x040B, 0x045C, 0x040C, 0x045E, 0x040E, 0x045F, 0x040F, 0x044E, 0x042E, 0x044A, 0x042A,
|
||||||
|
0x0430, 0x0410, 0x0431, 0x0411, 0x0446, 0x0426, 0x0434, 0x0414, 0x0435, 0x0415, 0x0444, 0x0424, 0x0433, 0x0413, 0x00AB, 0x00BB,
|
||||||
|
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x0445, 0x0425, 0x0438, 0x0418, 0x2563, 0x2551, 0x2557, 0x255D, 0x0439, 0x0419, 0x2510,
|
||||||
|
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x043A, 0x041A, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
|
||||||
|
0x043B, 0x041B, 0x043C, 0x041C, 0x043D, 0x041D, 0x043E, 0x041E, 0x043F, 0x2518, 0x250C, 0x2588, 0x2584, 0x041F, 0x044F, 0x2580,
|
||||||
|
0x042F, 0x0440, 0x0420, 0x0441, 0x0421, 0x0442, 0x0422, 0x0443, 0x0423, 0x0436, 0x0416, 0x0432, 0x0412, 0x044C, 0x042C, 0x2116,
|
||||||
|
0x00AD, 0x044B, 0x042B, 0x0437, 0x0417, 0x0448, 0x0428, 0x044D, 0x042D, 0x0449, 0x0429, 0x0447, 0x0427, 0x00A7, 0x25A0, 0x00A0
|
||||||
|
};
|
||||||
|
|
||||||
|
#elif _CODE_PAGE == 857
|
||||||
|
#define _TBLDEF 1
|
||||||
|
static
|
||||||
|
const WCHAR Tbl[] = { /* CP857(0x80-0xFF) to Unicode conversion table */
|
||||||
|
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x0131, 0x00C4, 0x00C5,
|
||||||
|
0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x0130, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x015E, 0x015F,
|
||||||
|
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x011E, 0x011F, 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
|
||||||
|
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0, 0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510,
|
||||||
|
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
|
||||||
|
0x00BA, 0x00AA, 0x00CA, 0x00CB, 0x00C8, 0x0000, 0x00CD, 0x00CE, 0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580,
|
||||||
|
0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x0000, 0x00D7, 0x00DA, 0x00DB, 0x00D9, 0x00EC, 0x00FF, 0x00AF, 0x00B4,
|
||||||
|
0x00AD, 0x00B1, 0x0000, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8, 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0
|
||||||
|
};
|
||||||
|
|
||||||
|
#elif _CODE_PAGE == 860
|
||||||
|
#define _TBLDEF 1
|
||||||
|
static
|
||||||
|
const WCHAR Tbl[] = { /* CP860(0x80-0xFF) to Unicode conversion table */
|
||||||
|
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E3, 0x00E0, 0x00C1, 0x00E7, 0x00EA, 0x00CA, 0x00E8, 0x00CD, 0x00D4, 0x00EC, 0x00C3, 0x00C2,
|
||||||
|
0x00C9, 0x00C0, 0x00C8, 0x00F4, 0x00F5, 0x00F2, 0x00DA, 0x00F9, 0x00CC, 0x00D5, 0x00DC, 0x00A2, 0x00A3, 0x00D9, 0x20A7, 0x00D3,
|
||||||
|
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x00D2, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
|
||||||
|
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x2558, 0x2510,
|
||||||
|
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
|
||||||
|
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
|
||||||
|
0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
|
||||||
|
0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
|
||||||
|
};
|
||||||
|
|
||||||
|
#elif _CODE_PAGE == 861
|
||||||
|
#define _TBLDEF 1
|
||||||
|
static
|
||||||
|
const WCHAR Tbl[] = { /* CP861(0x80-0xFF) to Unicode conversion table */
|
||||||
|
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E6, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00D0, 0x00F0, 0x00DE, 0x00C4, 0x00C5,
|
||||||
|
0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00FE, 0x00FB, 0x00DD, 0x00FD, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x20A7, 0x0192,
|
||||||
|
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00C1, 0x00CD, 0x00D3, 0x00DA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
|
||||||
|
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
|
||||||
|
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
|
||||||
|
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
|
||||||
|
0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
|
||||||
|
0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
|
||||||
|
};
|
||||||
|
|
||||||
|
#elif _CODE_PAGE == 862
|
||||||
|
#define _TBLDEF 1
|
||||||
|
static
|
||||||
|
const WCHAR Tbl[] = { /* CP862(0x80-0xFF) to Unicode conversion table */
|
||||||
|
0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF,
|
||||||
|
0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, 0x05E8, 0x05E9, 0x05EA, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192,
|
||||||
|
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
|
||||||
|
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
|
||||||
|
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
|
||||||
|
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
|
||||||
|
0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
|
||||||
|
0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
|
||||||
|
};
|
||||||
|
|
||||||
|
#elif _CODE_PAGE == 863
|
||||||
|
#define _TBLDEF 1
|
||||||
|
static
|
||||||
|
const WCHAR Tbl[] = { /* CP863(0x80-0xFF) to Unicode conversion table */
|
||||||
|
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00C2, 0x00E0, 0x00B6, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x2017, 0x00C0,
|
||||||
|
0x00C9, 0x00C8, 0x00CA, 0x00F4, 0x00CB, 0x00CF, 0x00FB, 0x00F9, 0x00A4, 0x00D4, 0x00DC, 0x00A2, 0x00A3, 0x00D9, 0x00DB, 0x0192,
|
||||||
|
0x00A6, 0x00B4, 0x00F3, 0x00FA, 0x00A8, 0x00BB, 0x00B3, 0x00AF, 0x00CE, 0x3210, 0x00AC, 0x00BD, 0x00BC, 0x00BE, 0x00AB, 0x00BB,
|
||||||
|
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
|
||||||
|
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
|
||||||
|
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
|
||||||
|
0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2219,
|
||||||
|
0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
|
||||||
|
};
|
||||||
|
|
||||||
|
#elif _CODE_PAGE == 864
|
||||||
|
#define _TBLDEF 1
|
||||||
|
static
|
||||||
|
const WCHAR Tbl[] = { /* CP864(0x80-0xFF) to Unicode conversion table */
|
||||||
|
0x00B0, 0x00B7, 0x2219, 0x221A, 0x2592, 0x2500, 0x2502, 0x253C, 0x2524, 0x252C, 0x251C, 0x2534, 0x2510, 0x250C, 0x2514, 0x2518,
|
||||||
|
0x03B2, 0x221E, 0x03C6, 0x00B1, 0x00BD, 0x00BC, 0x2248, 0x00AB, 0x00BB, 0xFEF7, 0xFEF8, 0x0000, 0x0000, 0xFEFB, 0xFEFC, 0x0000,
|
||||||
|
0x00A0, 0x00AD, 0xFE82, 0x00A3, 0x00A4, 0xFE84, 0x0000, 0x20AC, 0xFE8E, 0xFE8F, 0xFE95, 0xFE99, 0x060C, 0xFE9D, 0xFEA1, 0xFEA5,
|
||||||
|
0x0660, 0x0661, 0x0662, 0x0663, 0x0664, 0x0665, 0x0666, 0x0667, 0x0668, 0x0669, 0xFED1, 0x061B, 0xFEB1, 0xFEB5, 0xFEB9, 0x061F,
|
||||||
|
0x00A2, 0xFE80, 0xFE81, 0xFE83, 0xFE85, 0xFECA, 0xFE8B, 0xFE8D, 0xFE91, 0xFE93, 0xFE97, 0xFE9B, 0xFE9F, 0xFEA3, 0xFEA7, 0xFEA9,
|
||||||
|
0xFEAB, 0xFEAD, 0xFEAF, 0xFEB3, 0xFEB7, 0xFEBB, 0xFEBF, 0xFEC1, 0xFEC5, 0xFECB, 0xFECF, 0x00A6, 0x00AC, 0x00F7, 0x00D7, 0xFEC9,
|
||||||
|
0x0640, 0xFED3, 0xFED7, 0xFEDB, 0xFEDF, 0xFEE3, 0xFEE7, 0xFEEB, 0xFEED, 0xFEEF, 0xFEF3, 0xFEBD, 0xFECC, 0xFECE, 0xFECD, 0xFEE1,
|
||||||
|
0xFE7D, 0x0651, 0xFEE5, 0xFEE9, 0xFEEC, 0xFEF0, 0xFEF2, 0xFED0, 0xFED5, 0xFEF5, 0xFEF6, 0xFEDD, 0xFED9, 0xFEF1, 0x25A0, 0x0000
|
||||||
|
};
|
||||||
|
|
||||||
|
#elif _CODE_PAGE == 865
|
||||||
|
#define _TBLDEF 1
|
||||||
|
static
|
||||||
|
const WCHAR Tbl[] = { /* CP865(0x80-0xFF) to Unicode conversion table */
|
||||||
|
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
|
||||||
|
0x00C5, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x20A7, 0x0192,
|
||||||
|
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00A4,
|
||||||
|
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x2558, 0x2510,
|
||||||
|
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
|
||||||
|
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
|
||||||
|
0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
|
||||||
|
0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
|
||||||
|
};
|
||||||
|
|
||||||
|
#elif _CODE_PAGE == 866
|
||||||
|
#define _TBLDEF 1
|
||||||
|
static
|
||||||
|
const WCHAR Tbl[] = { /* CP866(0x80-0xFF) to Unicode conversion table */
|
||||||
|
0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F,
|
||||||
|
0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F,
|
||||||
|
0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
|
||||||
|
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
|
||||||
|
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
|
||||||
|
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
|
||||||
|
0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F,
|
||||||
|
0x0401, 0x0451, 0x0404, 0x0454, 0x0407, 0x0457, 0x040E, 0x045E, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x2116, 0x00A4, 0x25A0, 0x00A0
|
||||||
|
};
|
||||||
|
|
||||||
|
#elif _CODE_PAGE == 869
|
||||||
|
#define _TBLDEF 1
|
||||||
|
static
|
||||||
|
const WCHAR Tbl[] = { /* CP869(0x80-0xFF) to Unicode conversion table */
|
||||||
|
0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x0386, 0x00B7, 0x00B7, 0x00AC, 0x00A6, 0x2018, 0x2019, 0x0388, 0x2015, 0x0389,
|
||||||
|
0x038A, 0x03AA, 0x038C, 0x00B7, 0x00B7, 0x038E, 0x03AB, 0x00A9, 0x038F, 0x00B2, 0x00B3, 0x03AC, 0x00A3, 0x03AD, 0x03AE, 0x03AF,
|
||||||
|
0x03CA, 0x0390, 0x03CC, 0x03CD, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x00BD, 0x0398, 0x0399, 0x00AB, 0x00BB,
|
||||||
|
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x039A, 0x039B, 0x039C, 0x039D, 0x2563, 0x2551, 0x2557, 0x255D, 0x039E, 0x039F, 0x2510,
|
||||||
|
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0A30, 0x03A1, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x03A3,
|
||||||
|
0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9, 0x03B1, 0x03B2, 0x03B3, 0x2518, 0x250C, 0x2588, 0x2584, 0x03B4, 0x03B5, 0x2580,
|
||||||
|
0x03B6, 0x03B7, 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0, 0x03C1, 0x03C3, 0x03C2, 0x03C4, 0x0384,
|
||||||
|
0x00AD, 0x00B1, 0x03C5, 0x03C6, 0x03C7, 0x00A7, 0x03C8, 0x0385, 0x00B0, 0x00A8, 0x03C9, 0x03CB, 0x03B0, 0x03CE, 0x25A0, 0x00A0
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if !_TBLDEF || !_USE_LFN
|
||||||
|
#error This file is not needed at current configuration. Remove from the project.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
WCHAR ff_convert ( /* Converted character, Returns zero on error */
|
||||||
|
WCHAR chr, /* Character code to be converted */
|
||||||
|
UINT dir /* 0: Unicode to OEM code, 1: OEM code to Unicode */
|
||||||
|
)
|
||||||
|
{
|
||||||
|
WCHAR c;
|
||||||
|
|
||||||
|
|
||||||
|
if (chr < 0x80) { /* ASCII */
|
||||||
|
c = chr;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (dir) { /* OEM code to Unicode */
|
||||||
|
c = (chr >= 0x100) ? 0 : Tbl[chr - 0x80];
|
||||||
|
|
||||||
|
} else { /* Unicode to OEM code */
|
||||||
|
for (c = 0; c < 0x80; c++) {
|
||||||
|
if (chr == Tbl[c]) break;
|
||||||
|
}
|
||||||
|
c = (c + 0x80) & 0xFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
WCHAR ff_wtoupper ( /* Returns upper converted character */
|
||||||
|
WCHAR chr /* Unicode character to be upper converted */
|
||||||
|
)
|
||||||
|
{
|
||||||
|
static const WCHAR lower[] = { /* Lower case characters to be converted */
|
||||||
|
/* Latin Supplement */ 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF,
|
||||||
|
/* Latin Extended-A */ 0x101,0x103,0x105,0x107,0x109,0x10B,0x10D,0x10F,0x111,0x113,0x115,0x117,0x119,0x11B,0x11D,0x11F,0x121,0x123,0x125,0x127,0x129,0x12B,0x12D,0x12F,0x131,0x133,0x135,0x137,0x13A,0x13C,0x13E,0x140,0x142,0x144,0x146,0x148,0x14B,0x14D,0x14F,0x151,0x153,0x155,0x157,0x159,0x15B,0x15D,0x15F,0x161,0x163,0x165,0x167,0x169,0x16B,0x16D,0x16F,0x171,0x173,0x175,0x177,0x17A,0x17C,0x17E,
|
||||||
|
/* Latin Extended-B */ 0x183,0x185,0x188,0x18C,0x192,0x199,0x1A1,0x1A3,0x1A8,0x1AD,0x1B0,0x1B4,0x1B6,0x1B9,0x1BD,0x1C6,0x1C9,0x1CC,0x1CE,0x1D0,0x1D2,0x1D4,0x1D6,0x1D8,0x1DA,0x1DC,0x1DD,0x1DF,0x1E1,0x1E3,0x1E5,0x1E7,0x1E9,0x1EB,0x1ED,0x1EF,0x1F3,0x1F5,0x1FB,0x1FD,0x1FF,0x201,0x203,0x205,0x207,0x209,0x20B,0x20D,0x20F,0x211,0x213,0x215,0x217,
|
||||||
|
/* Greek, Coptic */ 0x3B1,0x3B2,0x3B3,0x3B4,0x3B5,0x3B6,0x3B7,0x3B8,0x3B9,0x3BA,0x3BB,0x3BC,0x3BD,0x3BE,0x3BF,0x3C0,0x3C1,0x3C3,0x3C4,0x3C5,0x3C6,0x3C7,0x3C8,0x3C9,0x3CA,0x3CB,0x3CC,0x3CD,0x3CE,0x3E3,0x3E5,0x3E7,0x3E9,0x3EB,
|
||||||
|
/* Cyrillic */ 0x430,0x431,0x432,0x433,0x434,0x435,0x436,0x437,0x438,0x439,0x43A,0x43B,0x43C,0x43D,0x43E,0x43F,0x440,0x441,0x442,0x443,0x444,0x445,0x446,0x447,0x448,0x449,0x44A,0x44B,0x44C,0x44D,0x44E,0x44F,0x452,0x453,0x454,0x455,0x456,0x457,0x458,0x459,0x45A,0x45B,0x45C,0x45E,0x45F,0x461,0x463,0x465,0x467,0x469,0x46B,0x46D,0x46F,0x471,0x473,0x475,0x477,0x479,0x47B,0x47D,0x47F,0x481,0x491,0x493,0x495,0x497,0x499,0x49B,0x49D,0x49F,0x4A1,0x4A3,0x4A5,0x4A7,0x4A9,0x4AB,0x4AD,0x4AF,0x4B1,0x4B3,0x4B5,0x4B7,0x4B9,0x4BB,0x4BD,0x4BF,0x4C2,0x4C4,0x4C8,0x4D1,0x4D3,0x4D5,0x4D7,0x4D9,0x4DB,0x4DD,0x4DF,0x4E1,0x4E3,0x4E5,0x4E7,0x4E9,0x4EB,0x4ED,0x4EF,0x4F1,0x4F3,0x4F5,0x4F9,
|
||||||
|
/* Armenian */ 0x561,0x562,0x563,0x564,0x565,0x566,0x567,0x568,0x569,0x56A,0x56B,0x56C,0x56D,0x56E,0x56F,0x570,0x571,0x572,0x573,0x574,0x575,0x576,0x577,0x578,0x579,0x57A,0x57B,0x57C,0x57D,0x57E,0x57F,0x580,0x581,0x582,0x583,0x584,0x585,0x586,
|
||||||
|
/* Latin Extended Additional */ 0x1E01,0x1E03,0x1E05,0x1E07,0x1E09,0x1E0B,0x1E0D,0x1E0F,0x1E11,0x1E13,0x1E15,0x1E17,0x1E19,0x1E1B,0x1E1D,0x1E1F,0x1E21,0x1E23,0x1E25,0x1E27,0x1E29,0x1E2B,0x1E2D,0x1E2F,0x1E31,0x1E33,0x1E35,0x1E37,0x1E39,0x1E3B,0x1E3D,0x1E3F,0x1E41,0x1E43,0x1E45,0x1E47,0x1E49,0x1E4B,0x1E4D,0x1E4F,0x1E51,0x1E53,0x1E55,0x1E57,0x1E59,0x1E5B,0x1E5D,0x1E5F,0x1E61,0x1E63,0x1E65,0x1E67,0x1E69,0x1E6B,0x1E6D,0x1E6F,0x1E71,0x1E73,0x1E75,0x1E77,0x1E79,0x1E7B,0x1E7D,0x1E7F,0x1E81,0x1E83,0x1E85,0x1E87,0x1E89,0x1E8B,0x1E8D,0x1E8F,0x1E91,0x1E93,0x1E95,0x1E97,0x1E99,0x1E9B,0x1E9D,0x1E9F,0x1EA1,0x1EA3,0x1EA5,0x1EA7,0x1EA9,0x1EAB,0x1EAD,0x1EAF,0x1EB1,0x1EB3,0x1EB5,0x1EB7,0x1EB9,0x1EBB,0x1EBD,0x1EBF,0x1EC1,0x1EC3,0x1EC5,0x1EC7,0x1EC9,0x1ECB,0x1ECD,0x1ECF,0x1ED1,0x1ED3,0x1ED5,0x1ED7,0x1ED9,0x1EDB,0x1EDD,0x1EDF,0x1EE1,0x1EE3,0x1EE5,0x1EE7,0x1EE9,0x1EEB,0x1EED,0x1EEF,0x1EF1,0x1EF3,0x1EF5,0x1EF7,0x1EF9,
|
||||||
|
/* Number forms */ 0x2170,0x2171,0x2172,0x2173,0x2174,0x2175,0x2176,0x2177,0x2178,0x2179,0x217A,0x217B,0x217C,0x217D,0x217E,0x217F,
|
||||||
|
/* Full-width */ 0xFF41,0xFF42,0xFF43,0xFF44,0xFF45,0xFF46,0xFF47,0xFF48,0xFF49,0xFF4A,0xFF4B,0xFF4C,0xFF4D,0xFF4E,0xFF4F,0xFF50,0xFF51,0xFF52,0xFF53,0xFF54,0xFF55,0xFF56,0xFF57,0xFF58,0xFF59,0xFF5A
|
||||||
|
};
|
||||||
|
static const WCHAR upper[] = { /* Upper case characters correspond to lower[] */
|
||||||
|
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0x178,
|
||||||
|
0x100,0x102,0x104,0x106,0x108,0x10A,0x10C,0x10E,0x110,0x112,0x114,0x116,0x118,0x11A,0x11C,0x11E,0x120,0x122,0x124,0x126,0x128,0x12A,0x12C,0x12E,0x130,0x132,0x134,0x136,0x139,0x13B,0x13D,0x13F,0x141,0x143,0x145,0x147,0x14A,0x14C,0x14E,0x150,0x152,0x154,0x156,0x158,0x15A,0x15C,0x15E,0x160,0x162,0x164,0x166,0x168,0x16A,0x16C,0x16E,0x170,0x172,0x174,0x176,0x179,0x17B,0x17D,
|
||||||
|
0x182,0x184,0x187,0x18B,0x191,0x198,0x1A0,0x1A2,0x1A7,0x1AC,0x1AF,0x1B3,0x1B5,0x1B8,0x1BC,0x1C4,0x1C7,0x1CA,0x1CD,0x1CF,0x1D1,0x1D3,0x1D5,0x1D7,0x1D9,0x1DB,0x18E,0x1DE,0x1E0,0x1E2,0x1E4,0x1E6,0x1E8,0x1EA,0x1EC,0x1EE,0x1F1,0x1F4,0x1FA,0x1FC,0x1FE,0x200,0x202,0x204,0x206,0x208,0x20A,0x20C,0x20E,0x210,0x212,0x214,0x216,
|
||||||
|
0x391,0x392,0x393,0x394,0x395,0x396,0x397,0x398,0x399,0x39A,0x39B,0x39C,0x39D,0x39E,0x39F,0x3A0,0x3A1,0x3A3,0x3A4,0x3A5,0x3A6,0x3A7,0x3A8,0x3A9,0x3AA,0x3AB,0x38C,0x38E,0x38F,0x3E2,0x3E4,0x3E6,0x3E8,0x3EA,
|
||||||
|
0x410,0x411,0x412,0x413,0x414,0x415,0x416,0x417,0x418,0x419,0x41A,0x41B,0x41C,0x41D,0x41E,0x41F,0x420,0x421,0x422,0x423,0x424,0x425,0x426,0x427,0x428,0x429,0x42A,0x42B,0x42C,0x42D,0x42E,0x42F,0x402,0x403,0x404,0x405,0x406,0x407,0x408,0x409,0x40A,0x40B,0x40C,0x40E,0x40F,0x460,0x462,0x464,0x466,0x468,0x46A,0x46C,0x46E,0x470,0x472,0x474,0x476,0x478,0x47A,0x47C,0x47E,0x480,0x490,0x492,0x494,0x496,0x498,0x49A,0x49C,0x49E,0x4A0,0x4A2,0x4A4,0x4A6,0x4A8,0x4AA,0x4AC,0x4AE,0x4B0,0x4B2,0x4B4,0x4B6,0x4B8,0x4BA,0x4BC,0x4BE,0x4C1,0x4C3,0x5C7,0x4D0,0x4D2,0x4D4,0x4D6,0x4D8,0x4DA,0x4DC,0x4DE,0x4E0,0x4E2,0x4E4,0x4E6,0x4E8,0x4EA,0x4EC,0x4EE,0x4F0,0x4F2,0x4F4,0x4F8,
|
||||||
|
0x531,0x532,0x533,0x534,0x535,0x536,0x537,0x538,0x539,0x53A,0x53B,0x53C,0x53D,0x53E,0x53F,0x540,0x541,0x542,0x543,0x544,0x545,0x546,0x547,0x548,0x549,0x54A,0x54B,0x54C,0x54D,0x54E,0x54F,0x550,0x551,0x552,0x553,0x554,0x555,0x556,
|
||||||
|
0x1E00,0x1E02,0x1E04,0x1E06,0x1E08,0x1E0A,0x1E0C,0x1E0E,0x1E10,0x1E12,0x1E14,0x1E16,0x1E18,0x1E1A,0x1E1C,0x1E1E,0x1E20,0x1E22,0x1E24,0x1E26,0x1E28,0x1E2A,0x1E2C,0x1E2E,0x1E30,0x1E32,0x1E34,0x1E36,0x1E38,0x1E3A,0x1E3C,0x1E3E,0x1E40,0x1E42,0x1E44,0x1E46,0x1E48,0x1E4A,0x1E4C,0x1E4E,0x1E50,0x1E52,0x1E54,0x1E56,0x1E58,0x1E5A,0x1E5C,0x1E5E,0x1E60,0x1E62,0x1E64,0x1E66,0x1E68,0x1E6A,0x1E6C,0x1E6E,0x1E70,0x1E72,0x1E74,0x1E76,0x1E78,0x1E7A,0x1E7C,0x1E7E,0x1E80,0x1E82,0x1E84,0x1E86,0x1E88,0x1E8A,0x1E8C,0x1E8E,0x1E90,0x1E92,0x1E94,0x1E96,0x1E98,0x1E9A,0x1E9C,0x1E9E,0x1EA0,0x1EA2,0x1EA4,0x1EA6,0x1EA8,0x1EAA,0x1EAC,0x1EAE,0x1EB0,0x1EB2,0x1EB4,0x1EB6,0x1EB8,0x1EBA,0x1EBC,0x1EBE,0x1EC0,0x1EC2,0x1EC4,0x1EC6,0x1EC8,0x1ECA,0x1ECC,0x1ECE,0x1ED0,0x1ED2,0x1ED4,0x1ED6,0x1ED8,0x1EDA,0x1EDC,0x1EDE,0x1EE0,0x1EE2,0x1EE4,0x1EE6,0x1EE8,0x1EEA,0x1EEC,0x1EEE,0x1EF0,0x1EF2,0x1EF4,0x1EF6,0x1EF8,
|
||||||
|
0x2160,0x2161,0x2162,0x2163,0x2164,0x2165,0x2166,0x2167,0x2168,0x2169,0x216A,0x216B,0x216C,0x216D,0x216E,0x216F,
|
||||||
|
0xFF21,0xFF22,0xFF23,0xFF24,0xFF25,0xFF26,0xFF27,0xFF28,0xFF29,0xFF2A,0xFF2B,0xFF2C,0xFF2D,0xFF2E,0xFF2F,0xFF30,0xFF31,0xFF32,0xFF33,0xFF34,0xFF35,0xFF36,0xFF37,0xFF38,0xFF39,0xFF3A
|
||||||
|
};
|
||||||
|
UINT i, n, hi, li;
|
||||||
|
|
||||||
|
|
||||||
|
if (chr < 0x80) { /* ASCII characters (acceleration) */
|
||||||
|
if (chr >= 0x61 && chr <= 0x7A) chr -= 0x20;
|
||||||
|
|
||||||
|
} else { /* Non ASCII characters (table search) */
|
||||||
|
n = 12; li = 0; hi = sizeof lower / sizeof lower[0];
|
||||||
|
do {
|
||||||
|
i = li + (hi - li) / 2;
|
||||||
|
if (chr == lower[i]) break;
|
||||||
|
if (chr > lower[i]) li = i; else hi = i;
|
||||||
|
} while (--n);
|
||||||
|
if (n) chr = upper[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return chr;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -2,3 +2,4 @@
|
|||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include "../../types.h"
|
#include "../../types.h"
|
||||||
|
#include "../../crypto.h"
|
||||||
@@ -402,3 +402,44 @@ int sdmmc_sdcard_init()
|
|||||||
return result | SD_Init();
|
return result | SD_Init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int sdmmc_get_cid(int isNand, uint32_t *info)
|
||||||
|
{
|
||||||
|
struct mmcdevice *device;
|
||||||
|
if(isNand)
|
||||||
|
device = &handleNAND;
|
||||||
|
else
|
||||||
|
device = &handleSD;
|
||||||
|
|
||||||
|
inittarget(device);
|
||||||
|
// use cmd7 to put sd card in standby mode
|
||||||
|
// CMD7
|
||||||
|
{
|
||||||
|
sdmmc_send_command(device,0x10507,0);
|
||||||
|
//if((device->error & 0x4)) return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get sd card info
|
||||||
|
// use cmd10 to read CID
|
||||||
|
{
|
||||||
|
sdmmc_send_command(device,0x1060A,device->initarg << 0x10);
|
||||||
|
//if((device->error & 0x4)) return -2;
|
||||||
|
|
||||||
|
for( int i = 0; i < 4; ++i ) {
|
||||||
|
info[i] = device->ret[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// put sd card back to transfer mode
|
||||||
|
// CMD7
|
||||||
|
{
|
||||||
|
sdmmc_send_command(device,0x10507,device->initarg << 0x10);
|
||||||
|
//if((device->error & 0x4)) return -3;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isNand)
|
||||||
|
{
|
||||||
|
inittarget(&handleSD);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -122,6 +122,7 @@ int sdmmc_sdcard_init();
|
|||||||
u32 sdmmc_sdcard_readsectors(u32 sector_no, u32 numsectors, vu8 *out);
|
u32 sdmmc_sdcard_readsectors(u32 sector_no, u32 numsectors, vu8 *out);
|
||||||
u32 sdmmc_sdcard_writesectors(u32 sector_no, u32 numsectors, vu8 *in);
|
u32 sdmmc_sdcard_writesectors(u32 sector_no, u32 numsectors, vu8 *in);
|
||||||
mmcdevice *getMMCDevice(int drive);
|
mmcdevice *getMMCDevice(int drive);
|
||||||
|
int sdmmc_get_cid( int isNand, uint32_t *info);
|
||||||
|
|
||||||
u32 sdmmc_nand_readsectors(u32 sector_no, u32 numsectors, vu8 *out);
|
u32 sdmmc_nand_readsectors(u32 sector_no, u32 numsectors, vu8 *out);
|
||||||
u32 sdmmc_nand_writesectors(u32 sector_no, u32 numsectors, vu8 *in);
|
u32 sdmmc_nand_writesectors(u32 sector_no, u32 numsectors, vu8 *in);
|
||||||
519
source/firm.c
519
source/firm.c
@@ -5,179 +5,287 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "firm.h"
|
#include "firm.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include "utils.h"
|
||||||
|
#include "fs.h"
|
||||||
#include "patches.h"
|
#include "patches.h"
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include "fs.h"
|
|
||||||
#include "emunand.h"
|
#include "emunand.h"
|
||||||
#include "crypto.h"
|
#include "crypto.h"
|
||||||
#include "draw.h"
|
#include "draw.h"
|
||||||
#include "screeninit.h"
|
#include "screeninit.h"
|
||||||
#include "loader.h"
|
#include "loader.h"
|
||||||
#include "utils.h"
|
|
||||||
#include "buttons.h"
|
#include "buttons.h"
|
||||||
#include "../build/patches.h"
|
#include "../build/patches.h"
|
||||||
|
|
||||||
//FIRM patches version
|
|
||||||
#define PATCH_VER 2
|
|
||||||
|
|
||||||
static firmHeader *const firm = (firmHeader *)0x24000000;
|
static firmHeader *const firm = (firmHeader *)0x24000000;
|
||||||
static const firmSectionHeader *section;
|
static const firmSectionHeader *section;
|
||||||
static u8 *arm9Section;
|
|
||||||
static const char *patchedFirms[] = { "/aurei/patched_firmware_sys.bin",
|
|
||||||
"/aurei/patched_firmware_emu.bin",
|
|
||||||
"/aurei/patched_firmware_em2.bin",
|
|
||||||
"/aurei/patched_firmware90.bin" };
|
|
||||||
static u32 firmSize,
|
|
||||||
console,
|
|
||||||
mode,
|
|
||||||
emuNAND,
|
|
||||||
a9lhSetup,
|
|
||||||
selectedFirm,
|
|
||||||
usePatchedFirm;
|
|
||||||
|
|
||||||
void setupCFW(void){
|
u32 config,
|
||||||
|
console,
|
||||||
|
firmSource,
|
||||||
|
emuOffset;
|
||||||
|
|
||||||
|
void main(void)
|
||||||
|
{
|
||||||
|
u32 bootType,
|
||||||
|
firmType,
|
||||||
|
nandType,
|
||||||
|
a9lhInstalled,
|
||||||
|
updatedSys,
|
||||||
|
needConfig,
|
||||||
|
newConfig,
|
||||||
|
emuHeader;
|
||||||
|
|
||||||
//Determine if booting with A9LH
|
|
||||||
u32 a9lhBoot = (PDN_SPI_CNT == 0x0) ? 1 : 0;
|
|
||||||
//Retrieve the last booted FIRM
|
|
||||||
u8 previousFirm = CFG_BOOTENV;
|
|
||||||
//Detect the console being used
|
//Detect the console being used
|
||||||
console = (PDN_MPCORE_CFG == 1) ? 0 : 1;
|
console = (PDN_MPCORE_CFG == 1) ? 0 : 1;
|
||||||
//Get pressed buttons
|
|
||||||
u16 pressed = HID_PAD;
|
//Mount filesystems. CTRNAND will be mounted only if/when needed
|
||||||
|
mountFs();
|
||||||
|
|
||||||
//Attempt to read the configuration file
|
//Attempt to read the configuration file
|
||||||
const char configPath[] = "aurei/config.bin";
|
const char configPath[] = "/aurei/config.bin";
|
||||||
u32 config = 0;
|
if(fileRead(&config, configPath, 4)) needConfig = 1;
|
||||||
u32 needConfig = fileRead(&config, configPath, 3) ? 1 : 2;
|
else
|
||||||
|
{
|
||||||
//Determine if A9LH is installed and the user has an updated sysNAND
|
config = 0;
|
||||||
u32 updatedSys;
|
needConfig = 2;
|
||||||
|
|
||||||
if(a9lhBoot || (config >> 2) & 0x1){
|
|
||||||
if(pressed == SAFE_MODE)
|
|
||||||
error("Using Safe Mode would brick you, or remove A9LH!");
|
|
||||||
|
|
||||||
a9lhSetup = 1;
|
|
||||||
//Check setting for > 9.2 sysNAND
|
|
||||||
updatedSys = config & 0x1;
|
|
||||||
} else{
|
|
||||||
a9lhSetup = 0;
|
|
||||||
updatedSys = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If booting with A9LH, it's a MCU reboot and a previous configuration exists,
|
//Determine if this is a firmlaunch boot
|
||||||
try to force boot options */
|
if(*(vu8 *)0x23F00005)
|
||||||
if(a9lhBoot && previousFirm && needConfig == 1){
|
{
|
||||||
//Always force a sysNAND boot when quitting AGB_FIRM
|
if(needConfig == 2) mcuReboot();
|
||||||
if(previousFirm == 0x7){
|
|
||||||
if(!updatedSys) mode = (config >> 12) & 0x1;
|
bootType = 1;
|
||||||
emuNAND = 0;
|
|
||||||
needConfig = 0;
|
//'0' = NATIVE_FIRM, '1' = TWL_FIRM, '2' = AGB_FIRM
|
||||||
//Else, force the last used boot options unless A, L or R are pressed
|
firmType = *(vu8 *)0x23F00005 - '0';
|
||||||
} else if(!(pressed & OPTION_BUTTONS)){
|
|
||||||
mode = (config >> 12) & 0x1;
|
nandType = BOOTCONFIG(0, 3);
|
||||||
emuNAND = (config >> 13) & 0x3;
|
firmSource = BOOTCONFIG(2, 1);
|
||||||
needConfig = 0;
|
a9lhInstalled = BOOTCONFIG(3, 1);
|
||||||
|
updatedSys = (a9lhInstalled && CONFIG(1)) ? 1 : 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bootType = 0;
|
||||||
|
firmType = 0;
|
||||||
|
|
||||||
|
//Determine if booting with A9LH
|
||||||
|
u32 a9lhBoot = !PDN_SPI_CNT ? 1 : 0;
|
||||||
|
|
||||||
|
//Retrieve the last booted FIRM
|
||||||
|
u32 previousFirm = CFG_BOOTENV;
|
||||||
|
|
||||||
|
//Get pressed buttons
|
||||||
|
u32 pressed = HID_PAD;
|
||||||
|
|
||||||
|
//Determine if we need to autoboot sysNAND
|
||||||
|
u32 autoBootSys = CONFIG(0);
|
||||||
|
|
||||||
|
//Determine if A9LH is installed and the user has an updated sysNAND
|
||||||
|
if(a9lhBoot || CONFIG(2))
|
||||||
|
{
|
||||||
|
if(pressed == SAFE_MODE)
|
||||||
|
error("Using Safe Mode would brick you, or remove A9LH!");
|
||||||
|
|
||||||
|
a9lhInstalled = 1;
|
||||||
|
|
||||||
|
//Check setting for > 9.2 sysNAND
|
||||||
|
updatedSys = CONFIG(1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
a9lhInstalled = 0;
|
||||||
|
updatedSys = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
newConfig = a9lhInstalled << 3;
|
||||||
|
|
||||||
|
/* If booting with A9LH, it's a MCU reboot and a previous configuration exists,
|
||||||
|
try to force boot options */
|
||||||
|
if(a9lhBoot && previousFirm && needConfig == 1)
|
||||||
|
{
|
||||||
|
//Always force a sysNAND boot when quitting AGB_FIRM
|
||||||
|
if(previousFirm == 7)
|
||||||
|
{
|
||||||
|
nandType = 0;
|
||||||
|
firmSource = updatedSys ? 0 : BOOTCONFIG(2, 1);
|
||||||
|
needConfig = 0;
|
||||||
|
|
||||||
|
//Flag to prevent multiple boot options-forcing
|
||||||
|
newConfig |= 1 << 4;
|
||||||
|
}
|
||||||
|
/* Else, force the last used boot options unless a payload button or A/L/R are pressed
|
||||||
|
or the no-forcing flag is set */
|
||||||
|
else if(!(pressed & OVERRIDE_BUTTONS) && !BOOTCONFIG(4, 1))
|
||||||
|
{
|
||||||
|
nandType = BOOTCONFIG(0, 3);
|
||||||
|
firmSource = BOOTCONFIG(2, 1);
|
||||||
|
needConfig = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Boot options aren't being forced
|
||||||
|
if(needConfig)
|
||||||
|
{
|
||||||
|
/* If L and R/Select or one of the single payload buttons are pressed and, if not using A9LH,
|
||||||
|
the Safe Mode combo is not pressed, chainload an external payload */
|
||||||
|
if(((pressed & SINGLE_PAYLOAD_BUTTONS) || ((pressed & BUTTON_L1) && (pressed & L_PAYLOAD_BUTTONS)))
|
||||||
|
&& pressed != SAFE_MODE)
|
||||||
|
loadPayload();
|
||||||
|
|
||||||
|
//If no configuration file exists or SELECT is held, load configuration menu
|
||||||
|
if(needConfig == 2 || (pressed & BUTTON_SELECT))
|
||||||
|
configureCFW(configPath);
|
||||||
|
|
||||||
|
//If screens are inited or the corresponding option is set, load splash screen
|
||||||
|
if(PDN_GPU_CNT != 1 || CONFIG(8)) loadSplash();
|
||||||
|
|
||||||
|
//Determine if we need to boot an emuNAND or sysNAND
|
||||||
|
nandType = (pressed & BUTTON_L1) ? autoBootSys : ((pressed & BUTTON_R1) ? updatedSys : !autoBootSys);
|
||||||
|
|
||||||
|
/* If we're booting emuNAND the second emuNAND is set as default and B isn't pressed,
|
||||||
|
or vice-versa, boot the second emuNAND */
|
||||||
|
if(nandType && ((!(pressed & BUTTON_B)) == CONFIG(3))) nandType++;
|
||||||
|
|
||||||
|
//Determine the NAND we should take the FIRM from
|
||||||
|
firmSource = (pressed & BUTTON_R1) ? !nandType : (nandType != 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(needConfig){
|
//If we need to boot emuNAND, make sure it exists
|
||||||
|
if(nandType)
|
||||||
|
{
|
||||||
|
getEmunandSect(&emuOffset, &emuHeader, &nandType);
|
||||||
|
if(!nandType) firmSource = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* If L and one of the payload buttons are pressed, and if not using A9LH
|
//Same if we're using emuNAND as the FIRM source
|
||||||
the Safe Mode combo is not pressed, chainload an external payload */
|
else if(firmSource)
|
||||||
if((pressed & BUTTON_L1) && (pressed & PAYLOAD_BUTTONS) &&
|
getEmunandSect(&emuOffset, &emuHeader, &firmSource);
|
||||||
pressed != SAFE_MODE) loadPayload();
|
|
||||||
|
|
||||||
//If no configuration file exists or SELECT is held, load configuration menu
|
if(!bootType)
|
||||||
if(needConfig == 2 || (pressed & BUTTON_SELECT))
|
{
|
||||||
configureCFW(configPath, patchedFirms[3]);
|
newConfig |= nandType | (firmSource << 2);
|
||||||
|
|
||||||
//If screens are inited, load splash screen
|
/* If the boot configuration is different from previously, overwrite it.
|
||||||
if(PDN_GPU_CNT != 0x1) loadSplash();
|
Just the no-forcing flag being set is not enough */
|
||||||
|
if((newConfig & 0x2F) != (config & 0x3F))
|
||||||
|
{
|
||||||
|
//Preserve user settings (last 26 bits)
|
||||||
|
newConfig |= config & 0xFFFFFFC0;
|
||||||
|
|
||||||
/* If L is pressed, boot 9.0 FIRM */
|
fileWrite(&newConfig, configPath, 4);
|
||||||
mode = ((config >> 3) & 0x1) ? ((!(pressed & BUTTON_L1R1)) ? 0 : 1) :
|
|
||||||
((pressed & BUTTON_L1) ? 0 : 1);
|
|
||||||
|
|
||||||
/* If L or R aren't pressed on a 9.0/9.2 sysNAND, or the 9.0 FIRM is selected
|
|
||||||
or R is pressed on a > 9.2 sysNAND, boot emuNAND */
|
|
||||||
if((updatedSys && (!mode || (pressed & BUTTON_R1))) ||
|
|
||||||
(!updatedSys && mode && !(pressed & BUTTON_R1))){
|
|
||||||
//If not 9.0 FIRM and B is pressed, attempt booting the second emuNAND
|
|
||||||
emuNAND = (mode && ((!(pressed & BUTTON_B)) == ((config >> 4) & 0x1))) ? 2 : 1;
|
|
||||||
} else emuNAND = 0;
|
|
||||||
|
|
||||||
u32 tempConfig = (PATCH_VER << 17) | (a9lhSetup << 16) | (emuNAND << 13) | (mode << 12);
|
|
||||||
|
|
||||||
/* If tha FIRM patches version is different or user switched to/from A9LH,
|
|
||||||
delete all patched FIRMs */
|
|
||||||
if((tempConfig & 0xFF0000) != (config & 0xFF0000))
|
|
||||||
deleteFirms(patchedFirms, sizeof(patchedFirms) / sizeof(char *));
|
|
||||||
|
|
||||||
//If the boot configuration is different from previously, overwrite it
|
|
||||||
if((tempConfig & 0xFFF000) != (config & 0xFFF000)){
|
|
||||||
//Preserve user settings (first 12 bits)
|
|
||||||
tempConfig |= config & 0xFFF;
|
|
||||||
fileWrite(&tempConfig, configPath, 3);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Determine which patched FIRM we need to write or attempt to use (if any).
|
loadFirm(firmType, !firmType && (nandType == 2 || updatedSys == !firmSource));
|
||||||
Patched 9.0 FIRM is only needed if "Use pre-patched FIRMs" is set */
|
|
||||||
selectedFirm = mode ? (emuNAND ? (emuNAND == 1 ? 2 : 3) : 1) :
|
|
||||||
(((config >> 1) & 0x1) ? 4 : 0);
|
|
||||||
|
|
||||||
//If "Use pre-patched FIRMs" is set and the appropriate FIRM exists, use it
|
if(!firmType) patchNativeFirm(nandType, emuHeader, a9lhInstalled);
|
||||||
usePatchedFirm = (((config >> 1) & 0x1) && fileExists(patchedFirms[selectedFirm - 1])) ? 1 : 0;
|
else patchTwlAgbFirm(firmType);
|
||||||
|
|
||||||
|
launchFirm(bootType);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Load FIRM into FCRAM
|
//Load FIRM into FCRAM
|
||||||
void loadFirm(void){
|
static inline void loadFirm(u32 firmType, u32 externalFirm)
|
||||||
|
{
|
||||||
//If not using an A9LH setup or the patched FIRM, load 9.0 FIRM from NAND
|
|
||||||
if(!usePatchedFirm && !a9lhSetup && !mode){
|
|
||||||
//Read FIRM from NAND and write to FCRAM
|
|
||||||
firmSize = console ? 0xF2000 : 0xE9000;
|
|
||||||
nandFirm0((u8 *)firm, firmSize, console);
|
|
||||||
//Check for correct decryption
|
|
||||||
if(memcmp(firm, "FIRM", 4) != 0)
|
|
||||||
error("Couldn't decrypt NAND FIRM0 (O3DS not on 9.x?)");
|
|
||||||
}
|
|
||||||
//Load FIRM from SD
|
|
||||||
else{
|
|
||||||
const char *path = usePatchedFirm ? patchedFirms[selectedFirm - 1] :
|
|
||||||
(mode ? "/aurei/firmware.bin" : "/aurei/firmware90.bin");
|
|
||||||
firmSize = fileSize(path);
|
|
||||||
if(!firmSize) error("aurei/firmware(90).bin doesn't exist");
|
|
||||||
fileRead(firm, path, firmSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
section = firm->section;
|
section = firm->section;
|
||||||
|
|
||||||
//Check that the loaded FIRM matches the console
|
u32 firmSize;
|
||||||
if((((u32)section[2].address >> 8) & 0xFF) != (console ? 0x60 : 0x68))
|
|
||||||
error("aurei/firmware(90).bin doesn't match this\nconsole, or it's encrypted");
|
|
||||||
|
|
||||||
arm9Section = (u8 *)firm + section[2].offset;
|
if(externalFirm)
|
||||||
|
{
|
||||||
|
const char path[] = "/aurei/firmware.bin";
|
||||||
|
firmSize = fileSize(path);
|
||||||
|
|
||||||
if(console && !usePatchedFirm) decryptArm9Bin(arm9Section, mode);
|
if(firmSize)
|
||||||
|
{
|
||||||
|
fileRead(firm, path, firmSize);
|
||||||
|
|
||||||
|
//Check that the loaded FIRM matches the console
|
||||||
|
if((((u32)section[2].address >> 8) & 0xFF) != (console ? 0x60 : 0x68)) firmSize = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else firmSize = 0;
|
||||||
|
|
||||||
|
if(!firmSize)
|
||||||
|
{
|
||||||
|
const char *firmFolders[3][2] = {{ "00000002", "20000002" },
|
||||||
|
{ "00000102", "20000102" },
|
||||||
|
{ "00000202", "20000202" }};
|
||||||
|
|
||||||
|
firmRead(firm, firmFolders[firmType][console]);
|
||||||
|
decryptExeFs((u8 *)firm);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//NAND redirection
|
static inline void patchNativeFirm(u32 nandType, u32 emuHeader, u32 a9lhInstalled)
|
||||||
static void loadEmu(u8 *proc9Offset){
|
{
|
||||||
|
u8 *arm9Section = (u8 *)firm + section[2].offset;
|
||||||
|
|
||||||
u32 emuOffset,
|
u32 nativeFirmType;
|
||||||
emuHeader = 0,
|
|
||||||
emuRead,
|
|
||||||
emuWrite;
|
|
||||||
|
|
||||||
//Look for emuNAND
|
if(console)
|
||||||
getEmunandSect(&emuOffset, &emuHeader, emuNAND);
|
{
|
||||||
|
//Determine if we're booting the 9.0 FIRM
|
||||||
|
nativeFirmType = (arm9Section[0x51] == 0xFF) ? 0 : 1;
|
||||||
|
|
||||||
//No emuNAND detected
|
//Decrypt ARM9Bin and patch ARM9 entrypoint to skip arm9loader
|
||||||
if(!emuHeader) error("No emuNAND has been detected");
|
arm9Loader(arm9Section, nativeFirmType);
|
||||||
|
firm->arm9Entry = (u8 *)0x801B01C;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//Determine if we're booting the 9.0 FIRM
|
||||||
|
u8 firm90Hash[0x10] = {0x27, 0x2D, 0xFE, 0xEB, 0xAF, 0x3F, 0x6B, 0x3B, 0xF5, 0xDE, 0x4C, 0x41, 0xDE, 0x95, 0x27, 0x6A};
|
||||||
|
nativeFirmType = (memcmp(section[2].hash, firm90Hash, 0x10) == 0) ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(nativeFirmType || nandType)
|
||||||
|
{
|
||||||
|
//Find the Process9 NCCH location
|
||||||
|
u8 *proc9Offset = getProc9(arm9Section, section[2].size);
|
||||||
|
|
||||||
|
//Apply emuNAND patches
|
||||||
|
if(nandType) patchEmuNAND(arm9Section, proc9Offset, emuHeader);
|
||||||
|
|
||||||
|
//Apply FIRM reboot patches, not on 9.0 FIRM as it breaks firmlaunchhax
|
||||||
|
if(nativeFirmType) patchReboots(arm9Section, proc9Offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Apply FIRM0/1 writes patches on sysNAND to protect A9LH
|
||||||
|
if(a9lhInstalled && !nandType)
|
||||||
|
{
|
||||||
|
u16 *writeOffset = getFirmWrite(arm9Section, section[2].size);
|
||||||
|
*writeOffset = writeBlock[0];
|
||||||
|
*(writeOffset + 1) = writeBlock[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
//Apply signature checks patches
|
||||||
|
u32 sigOffset,
|
||||||
|
sigOffset2;
|
||||||
|
|
||||||
|
getSigChecks(arm9Section, section[2].size, &sigOffset, &sigOffset2);
|
||||||
|
*(u16 *)sigOffset = sigPatch[0];
|
||||||
|
*(u16 *)sigOffset2 = sigPatch[0];
|
||||||
|
*((u16 *)sigOffset2 + 1) = sigPatch[1];
|
||||||
|
|
||||||
|
if(CONFIG(5))
|
||||||
|
{
|
||||||
|
//Apply UNITINFO patch
|
||||||
|
u8 *unitInfoOffset = getUnitInfoValueSet(arm9Section, section[2].size);
|
||||||
|
*unitInfoOffset = unitInfoPatch;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Replace the FIRM loader with the injector
|
||||||
|
injectLoader();
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void patchEmuNAND(u8 *arm9Section, u8 *proc9Offset, u32 emuHeader)
|
||||||
|
{
|
||||||
//Copy emuNAND code
|
//Copy emuNAND code
|
||||||
void *emuCodeOffset = getEmuCode(proc9Offset);
|
void *emuCodeOffset = getEmuCode(proc9Offset);
|
||||||
memcpy(emuCodeOffset, emunand, emunand_size);
|
memcpy(emuCodeOffset, emunand, emunand_size);
|
||||||
@@ -196,7 +304,10 @@ static void loadEmu(u8 *proc9Offset){
|
|||||||
u32 branchOffset = (u32)emuCodeOffset - (u32)firm -
|
u32 branchOffset = (u32)emuCodeOffset - (u32)firm -
|
||||||
section[2].offset + (u32)section[2].address;
|
section[2].offset + (u32)section[2].address;
|
||||||
|
|
||||||
//Add emunand hooks
|
//Add emuNAND hooks
|
||||||
|
u32 emuRead,
|
||||||
|
emuWrite;
|
||||||
|
|
||||||
getEmuRW(arm9Section, section[2].size, &emuRead, &emuWrite);
|
getEmuRW(arm9Section, section[2].size, &emuRead, &emuWrite);
|
||||||
*(u16 *)emuRead = nandRedir[0];
|
*(u16 *)emuRead = nandRedir[0];
|
||||||
*((u16 *)emuRead + 1) = nandRedir[1];
|
*((u16 *)emuRead + 1) = nandRedir[1];
|
||||||
@@ -212,93 +323,103 @@ static void loadEmu(u8 *proc9Offset){
|
|||||||
*(mpuOffset + 9) = mpuPatch[2];
|
*(mpuOffset + 9) = mpuPatch[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
//Patches
|
static inline void patchReboots(u8 *arm9Section, u8 *proc9Offset)
|
||||||
void patchFirm(void){
|
{
|
||||||
|
//Calculate offset for the firmlaunch code
|
||||||
|
void *rebootOffset = getReboot(arm9Section, section[2].size);
|
||||||
|
|
||||||
//Skip patching
|
//Calculate offset for the fOpen function
|
||||||
if(usePatchedFirm) return;
|
u32 fOpenOffset = getfOpen(proc9Offset, rebootOffset);
|
||||||
|
|
||||||
if(mode || emuNAND){
|
//Copy firmlaunch code
|
||||||
//Find the Process9 NCCH location
|
memcpy(rebootOffset, reboot, reboot_size);
|
||||||
u8 *proc9Offset = getProc9(arm9Section, section[2].size);
|
|
||||||
|
|
||||||
//Apply emuNAND patches
|
//Put the fOpen offset in the right location
|
||||||
if(emuNAND) loadEmu(proc9Offset);
|
u32 *pos_fopen = (u32 *)memsearch(rebootOffset, "OPEN", reboot_size, 4);
|
||||||
|
*pos_fopen = fOpenOffset;
|
||||||
|
}
|
||||||
|
|
||||||
//Patch FIRM reboots, not on 9.0 FIRM as it breaks firmlaunchhax
|
static inline void injectLoader(void)
|
||||||
if(mode){
|
{
|
||||||
//Calculate offset for the firmlaunch code
|
u32 loaderSize;
|
||||||
void *rebootOffset = getReboot(arm9Section, section[2].size);
|
|
||||||
//Calculate offset for the fOpen function
|
|
||||||
u32 fOpenOffset = getfOpen(proc9Offset, rebootOffset);
|
|
||||||
|
|
||||||
//Copy firmlaunch code
|
void *loaderOffset = getLoader((u8 *)firm + section[0].offset, section[0].size, &loaderSize);
|
||||||
memcpy(rebootOffset, reboot, reboot_size);
|
|
||||||
|
|
||||||
//Put the fOpen offset in the right location
|
//Check that the injector CXI isn't larger than the original
|
||||||
u32 *pos_fopen = (u32 *)memsearch(rebootOffset, "OPEN", reboot_size, 4);
|
if((u32)injector_size <= loaderSize)
|
||||||
*pos_fopen = fOpenOffset;
|
{
|
||||||
|
memcpy(loaderOffset, injector, injector_size);
|
||||||
|
|
||||||
//Patch path for emuNAND-patched FIRM
|
//Patch content size and ExeFS size to match the repaced loader's ones
|
||||||
if(emuNAND){
|
|
||||||
void *pos_path = memsearch(rebootOffset, L"sy", reboot_size, 4);
|
|
||||||
memcpy(pos_path, emuNAND == 1 ? L"emu" : L"em2", 5);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(a9lhSetup && !emuNAND){
|
|
||||||
//Patch FIRM partitions writes on sysNAND to protect A9LH
|
|
||||||
u16 *writeOffset = getFirmWrite(arm9Section, section[2].size);
|
|
||||||
*writeOffset = writeBlock[0];
|
|
||||||
*(writeOffset + 1) = writeBlock[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
//Disable signature checks
|
|
||||||
u32 sigOffset,
|
|
||||||
sigOffset2;
|
|
||||||
|
|
||||||
getSigChecks(arm9Section, section[2].size, &sigOffset, &sigOffset2);
|
|
||||||
*(u16 *)sigOffset = sigPatch[0];
|
|
||||||
*(u16 *)sigOffset2 = sigPatch[0];
|
|
||||||
*((u16 *)sigOffset2 + 1) = sigPatch[1];
|
|
||||||
|
|
||||||
//Replace the FIRM loader with the injector
|
|
||||||
u32 loaderOffset,
|
|
||||||
loaderSize;
|
|
||||||
|
|
||||||
getLoader((u8 *)firm + section[0].offset, section[0].size, &loaderOffset, &loaderSize);
|
|
||||||
if(injector_size <= (int)loaderSize){
|
|
||||||
memset((void *)loaderOffset, 0, loaderSize);
|
|
||||||
memcpy((void *)loaderOffset, injector, injector_size);
|
|
||||||
*((u32 *)loaderOffset + 0x41) = loaderSize / 0x200;
|
*((u32 *)loaderOffset + 0x41) = loaderSize / 0x200;
|
||||||
*((u32 *)loaderOffset + 0x69) = loaderSize / 0x200 - 5;
|
*((u32 *)loaderOffset + 0x69) = loaderSize / 0x200 - 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Patch ARM9 entrypoint on N3DS to skip arm9loader
|
|
||||||
if(console)
|
|
||||||
firm->arm9Entry = (u8 *)0x801B01C;
|
|
||||||
|
|
||||||
//Write patched FIRM to SD if needed
|
|
||||||
if(selectedFirm)
|
|
||||||
if(!fileWrite(firm, patchedFirms[selectedFirm - 1], firmSize))
|
|
||||||
error("Couldn't write the patched FIRM (no free space?)");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void launchFirm(void){
|
static inline void patchTwlAgbFirm(u32 firmType)
|
||||||
|
{
|
||||||
|
//On N3DS, decrypt ARM9Bin and patch ARM9 entrypoint to skip arm9loader
|
||||||
|
if(console)
|
||||||
|
{
|
||||||
|
arm9Loader((u8 *)firm + section[3].offset, 0);
|
||||||
|
firm->arm9Entry = (u8 *)0x801301C;
|
||||||
|
}
|
||||||
|
|
||||||
if(console && mode) setKeyXs(arm9Section);
|
const patchData twlPatches[] = {
|
||||||
|
{{0x1650C0, 0x165D64}, {{ 6, 0x00, 0x20, 0x4E, 0xB0, 0x70, 0xBD }}, 0},
|
||||||
|
{{0x173A0E, 0x17474A}, { .type1 = 0x2001 }, 1},
|
||||||
|
{{0x174802, 0x17553E}, { .type1 = 0x2000 }, 2},
|
||||||
|
{{0x174964, 0x1756A0}, { .type1 = 0x2000 }, 2},
|
||||||
|
{{0x174D52, 0x175A8E}, { .type1 = 0x2001 }, 2},
|
||||||
|
{{0x174D5E, 0x175A9A}, { .type1 = 0x2001 }, 2},
|
||||||
|
{{0x174D6A, 0x175AA6}, { .type1 = 0x2001 }, 2},
|
||||||
|
{{0x174E56, 0x175B92}, { .type1 = 0x2001 }, 1},
|
||||||
|
{{0x174E58, 0x175B94}, { .type1 = 0x4770 }, 1}
|
||||||
|
},
|
||||||
|
agbPatches[] = {
|
||||||
|
{{0x9D2A8, 0x9DF64}, {{ 6, 0x00, 0x20, 0x4E, 0xB0, 0x70, 0xBD }}, 0},
|
||||||
|
{{0xD7A12, 0xD8B8A}, { .type1 = 0xEF26 }, 1}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Calculate the amount of patches to apply. Only count the boot screen patch for AGB_FIRM
|
||||||
|
if the matching option was enabled (keep it as last) */
|
||||||
|
u32 numPatches = firmType == 1 ? (sizeof(twlPatches) / sizeof(patchData)) : (sizeof(agbPatches) / sizeof(patchData) - !CONFIG(7));
|
||||||
|
const patchData *patches = firmType == 1 ? twlPatches : agbPatches;
|
||||||
|
|
||||||
|
//Patch
|
||||||
|
for(u32 i = 0; i < numPatches; i++)
|
||||||
|
{
|
||||||
|
switch(patches[i].type)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
memcpy((u8 *)firm + patches[i].offset[console], patches[i].patch.type0 + 1, patches[i].patch.type0[0]);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
*(u16 *)((u8 *)firm + patches[i].offset[console] + 2) = 0;
|
||||||
|
case 1:
|
||||||
|
*(u16 *)((u8 *)firm + patches[i].offset[console]) = patches[i].patch.type1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void launchFirm(u32 bootType)
|
||||||
|
{
|
||||||
//Copy firm partitions to respective memory locations
|
//Copy firm partitions to respective memory locations
|
||||||
memcpy(section[0].address, (u8 *)firm + section[0].offset, section[0].size);
|
for(u32 i = 0; i < 4 && section[i].size; i++)
|
||||||
memcpy(section[1].address, (u8 *)firm + section[1].offset, section[1].size);
|
memcpy(section[i].address, (u8 *)firm + section[i].offset, section[i].size);
|
||||||
memcpy(section[2].address, arm9Section, section[2].size);
|
|
||||||
|
|
||||||
//Fixes N3DS 3D
|
//Determine the ARM11 entry to use
|
||||||
deinitScreens();
|
vu32 *arm11;
|
||||||
|
if(bootType) arm11 = (u32 *)0x1FFFFFFC;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
deinitScreens();
|
||||||
|
arm11 = (u32 *)0x1FFFFFF8;
|
||||||
|
}
|
||||||
|
|
||||||
//Set ARM11 kernel entrypoint
|
//Set ARM11 kernel entrypoint
|
||||||
*(vu32 *)0x1FFFFFF8 = (u32)firm->arm11Entry;
|
*arm11 = (u32)firm->arm11Entry;
|
||||||
|
|
||||||
//Final jump to arm9 kernel
|
//Final jump to arm9 kernel
|
||||||
((void (*)())firm->arm9Entry)();
|
((void (*)())firm->arm9Entry)();
|
||||||
|
|||||||
@@ -8,8 +8,8 @@
|
|||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
#define PDN_MPCORE_CFG (*(vu8 *)0x10140FFC)
|
#define PDN_MPCORE_CFG (*(vu32 *)0x10140FFC)
|
||||||
#define PDN_SPI_CNT (*(vu8 *)0x101401C0)
|
#define PDN_SPI_CNT (*(vu32 *)0x101401C0)
|
||||||
|
|
||||||
//FIRM Header layout
|
//FIRM Header layout
|
||||||
typedef struct firmSectionHeader {
|
typedef struct firmSectionHeader {
|
||||||
@@ -29,7 +29,19 @@ typedef struct firmHeader {
|
|||||||
firmSectionHeader section[4];
|
firmSectionHeader section[4];
|
||||||
} firmHeader;
|
} firmHeader;
|
||||||
|
|
||||||
void setupCFW(void);
|
typedef struct patchData {
|
||||||
void loadFirm(void);
|
u32 offset[2];
|
||||||
void patchFirm(void);
|
union {
|
||||||
void launchFirm(void);
|
u8 type0[8];
|
||||||
|
u16 type1;
|
||||||
|
} patch;
|
||||||
|
u32 type;
|
||||||
|
} patchData;
|
||||||
|
|
||||||
|
static inline void loadFirm(u32 firmType, u32 externalFirm);
|
||||||
|
static inline void patchNativeFirm(u32 emuNAND, u32 emuHeader, u32 a9lhSetup);
|
||||||
|
static inline void patchEmuNAND(u8 *arm9Section, u8 *proc9Offset, u32 emuHeader);
|
||||||
|
static inline void patchReboots(u8 *arm9Section, u8 *proc9Offset);
|
||||||
|
static inline void injectLoader(void);
|
||||||
|
static inline void patchTwlAgbFirm(u32 firmType);
|
||||||
|
static inline void launchFirm(u32 bootType);
|
||||||
92
source/fs.c
92
source/fs.c
@@ -5,31 +5,40 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "fs.h"
|
#include "fs.h"
|
||||||
|
#include "memory.h"
|
||||||
#include "fatfs/ff.h"
|
#include "fatfs/ff.h"
|
||||||
|
|
||||||
static FATFS fs;
|
static FATFS sdFs,
|
||||||
|
nandFs;
|
||||||
|
|
||||||
|
u32 mountFs(void)
|
||||||
|
{
|
||||||
|
if(f_mount(&sdFs, "0:", 1) != FR_OK) return 0;
|
||||||
|
f_mount(&nandFs, "1:", 0);
|
||||||
|
|
||||||
u32 mountSD(void){
|
|
||||||
if(f_mount(&fs, "0:", 1) != FR_OK) return 0;
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 fileRead(void *dest, const char *path, u32 size){
|
u32 fileRead(void *dest, const char *path, u32 size)
|
||||||
|
{
|
||||||
FRESULT fr;
|
FRESULT fr;
|
||||||
FIL fp;
|
FIL fp;
|
||||||
unsigned int br = 0;
|
unsigned int br = 0;
|
||||||
|
|
||||||
fr = f_open(&fp, path, FA_READ);
|
fr = f_open(&fp, path, FA_READ);
|
||||||
if(fr == FR_OK){
|
if(fr == FR_OK)
|
||||||
|
{
|
||||||
if(!size) size = f_size(&fp);
|
if(!size) size = f_size(&fp);
|
||||||
fr = f_read(&fp, dest, size, &br);
|
fr = f_read(&fp, dest, size, &br);
|
||||||
}
|
}
|
||||||
|
|
||||||
f_close(&fp);
|
f_close(&fp);
|
||||||
|
|
||||||
return fr ? 0 : 1;
|
return fr ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 fileWrite(const void *buffer, const char *path, u32 size){
|
u32 fileWrite(const void *buffer, const char *path, u32 size)
|
||||||
|
{
|
||||||
FRESULT fr;
|
FRESULT fr;
|
||||||
FIL fp;
|
FIL fp;
|
||||||
unsigned int br = 0;
|
unsigned int br = 0;
|
||||||
@@ -38,10 +47,12 @@ u32 fileWrite(const void *buffer, const char *path, u32 size){
|
|||||||
if(fr == FR_OK) fr = f_write(&fp, buffer, size, &br);
|
if(fr == FR_OK) fr = f_write(&fp, buffer, size, &br);
|
||||||
|
|
||||||
f_close(&fp);
|
f_close(&fp);
|
||||||
|
|
||||||
return fr ? 0 : 1;
|
return fr ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 fileSize(const char *path){
|
u32 fileSize(const char *path)
|
||||||
|
{
|
||||||
FIL fp;
|
FIL fp;
|
||||||
u32 size = 0;
|
u32 size = 0;
|
||||||
|
|
||||||
@@ -49,19 +60,70 @@ u32 fileSize(const char *path){
|
|||||||
size = f_size(&fp);
|
size = f_size(&fp);
|
||||||
|
|
||||||
f_close(&fp);
|
f_close(&fp);
|
||||||
|
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 fileExists(const char *path){
|
u32 defPayloadExists(void)
|
||||||
FIL fp;
|
{
|
||||||
u32 exists = 0;
|
DIR dir;
|
||||||
|
FILINFO info = { .lfname = NULL };
|
||||||
|
|
||||||
if(f_open(&fp, path, FA_READ) == FR_OK) exists = 1;
|
FRESULT result = f_findfirst(&dir, &info, "/aurei/payloads", "def_*.bin");
|
||||||
|
|
||||||
f_close(&fp);
|
f_closedir(&dir);
|
||||||
return exists;
|
|
||||||
|
return (result == FR_OK && info.fname[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void fileDelete(const char *path){
|
void firmRead(void *dest, const char *firmFolder)
|
||||||
f_unlink(path);
|
{
|
||||||
|
char path[48] = "1:/title/00040138/00000000/content";
|
||||||
|
memcpy(&path[18], firmFolder, 8);
|
||||||
|
|
||||||
|
DIR dir;
|
||||||
|
FILINFO info = { .lfname = NULL };
|
||||||
|
|
||||||
|
f_opendir(&dir, path);
|
||||||
|
|
||||||
|
u32 id = 0;
|
||||||
|
|
||||||
|
//Parse the target directory
|
||||||
|
while(f_readdir(&dir, &info) == FR_OK)
|
||||||
|
{
|
||||||
|
//We've parsed the whole folder
|
||||||
|
if(!info.fname[0]) break;
|
||||||
|
|
||||||
|
//Not a cxi
|
||||||
|
if(info.fname[9] != 'a' && info.fname[9] != 'A') continue;
|
||||||
|
|
||||||
|
//Convert the .app name to an integer
|
||||||
|
u32 tempId = 0;
|
||||||
|
for(char *tmp = info.fname; *tmp != '.'; tmp++)
|
||||||
|
{
|
||||||
|
tempId <<= 4;
|
||||||
|
tempId += *tmp > '9' ? *tmp - 'A' + 10 : *tmp - '0';
|
||||||
|
}
|
||||||
|
|
||||||
|
//Found a newer cxi
|
||||||
|
if(tempId > id) id = tempId;
|
||||||
|
}
|
||||||
|
|
||||||
|
f_closedir(&dir);
|
||||||
|
|
||||||
|
//Complete the string with the .app name
|
||||||
|
memcpy(&path[34], "/00000000.app", 14);
|
||||||
|
|
||||||
|
u32 i = 42;
|
||||||
|
|
||||||
|
//Convert back the .app name from integer to array
|
||||||
|
while(id > 0)
|
||||||
|
{
|
||||||
|
//Last digit of the .app
|
||||||
|
static const char hexDigits[] = "0123456789ABCDEF";
|
||||||
|
path[i--] = hexDigits[id & 0xF];
|
||||||
|
id >>= 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
fileRead(dest, path, 0);
|
||||||
}
|
}
|
||||||
@@ -8,9 +8,9 @@
|
|||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
u32 mountSD(void);
|
u32 mountFs(void);
|
||||||
u32 fileRead(void *dest, const char *path, u32 size);
|
u32 fileRead(void *dest, const char *path, u32 size);
|
||||||
u32 fileWrite(const void *buffer, const char *path, u32 size);
|
u32 fileWrite(const void *buffer, const char *path, u32 size);
|
||||||
u32 fileSize(const char *path);
|
u32 fileSize(const char *path);
|
||||||
u32 fileExists(const char *path);
|
u32 defPayloadExists(void);
|
||||||
void fileDelete(const char *path);
|
void firmRead(void *dest, const char *firmFolder);
|
||||||
40
source/i2c.c
40
source/i2c.c
@@ -10,11 +10,13 @@ static const struct { u8 bus_id, reg_addr; } dev_data[] = {
|
|||||||
{2, 0xA4}, {2, 0x9A}, {2, 0xA0},
|
{2, 0xA4}, {2, 0x9A}, {2, 0xA0},
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline u8 i2cGetDeviceBusId(u8 device_id) {
|
static inline u8 i2cGetDeviceBusId(u8 device_id)
|
||||||
|
{
|
||||||
return dev_data[device_id].bus_id;
|
return dev_data[device_id].bus_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline u8 i2cGetDeviceRegAddr(u8 device_id) {
|
static inline u8 i2cGetDeviceRegAddr(u8 device_id)
|
||||||
|
{
|
||||||
return dev_data[device_id].reg_addr;
|
return dev_data[device_id].reg_addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -26,7 +28,8 @@ static vu8* reg_data_addrs[] = {
|
|||||||
(vu8*)(I2C3_REG_OFF + I2C_REG_DATA),
|
(vu8*)(I2C3_REG_OFF + I2C_REG_DATA),
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline vu8* i2cGetDataReg(u8 bus_id) {
|
static inline vu8* i2cGetDataReg(u8 bus_id)
|
||||||
|
{
|
||||||
return reg_data_addrs[bus_id];
|
return reg_data_addrs[bus_id];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,22 +41,27 @@ static vu8* reg_cnt_addrs[] = {
|
|||||||
(vu8*)(I2C3_REG_OFF + I2C_REG_CNT),
|
(vu8*)(I2C3_REG_OFF + I2C_REG_CNT),
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline vu8* i2cGetCntReg(u8 bus_id) {
|
static inline vu8* i2cGetCntReg(u8 bus_id)
|
||||||
|
{
|
||||||
return reg_cnt_addrs[bus_id];
|
return reg_cnt_addrs[bus_id];
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
static inline void i2cWaitBusy(u8 bus_id) {
|
static inline void i2cWaitBusy(u8 bus_id)
|
||||||
|
{
|
||||||
while (*i2cGetCntReg(bus_id) & 0x80);
|
while (*i2cGetCntReg(bus_id) & 0x80);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline u32 i2cGetResult(u8 bus_id) {
|
static inline u32 i2cGetResult(u8 bus_id)
|
||||||
|
{
|
||||||
i2cWaitBusy(bus_id);
|
i2cWaitBusy(bus_id);
|
||||||
|
|
||||||
return (*i2cGetCntReg(bus_id) >> 4) & 1;
|
return (*i2cGetCntReg(bus_id) >> 4) & 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void i2cStop(u8 bus_id, u8 arg0) {
|
static void i2cStop(u8 bus_id, u8 arg0)
|
||||||
|
{
|
||||||
*i2cGetCntReg(bus_id) = (arg0 << 5) | 0xC0;
|
*i2cGetCntReg(bus_id) = (arg0 << 5) | 0xC0;
|
||||||
i2cWaitBusy(bus_id);
|
i2cWaitBusy(bus_id);
|
||||||
*i2cGetCntReg(bus_id) = 0xC5;
|
*i2cGetCntReg(bus_id) = 0xC5;
|
||||||
@@ -61,32 +69,40 @@ static void i2cStop(u8 bus_id, u8 arg0) {
|
|||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
static u32 i2cSelectDevice(u8 bus_id, u8 dev_reg) {
|
static u32 i2cSelectDevice(u8 bus_id, u8 dev_reg)
|
||||||
|
{
|
||||||
i2cWaitBusy(bus_id);
|
i2cWaitBusy(bus_id);
|
||||||
*i2cGetDataReg(bus_id) = dev_reg;
|
*i2cGetDataReg(bus_id) = dev_reg;
|
||||||
*i2cGetCntReg(bus_id) = 0xC2;
|
*i2cGetCntReg(bus_id) = 0xC2;
|
||||||
|
|
||||||
return i2cGetResult(bus_id);
|
return i2cGetResult(bus_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 i2cSelectRegister(u8 bus_id, u8 reg) {
|
static u32 i2cSelectRegister(u8 bus_id, u8 reg)
|
||||||
|
{
|
||||||
i2cWaitBusy(bus_id);
|
i2cWaitBusy(bus_id);
|
||||||
*i2cGetDataReg(bus_id) = reg;
|
*i2cGetDataReg(bus_id) = reg;
|
||||||
*i2cGetCntReg(bus_id) = 0xC0;
|
*i2cGetCntReg(bus_id) = 0xC0;
|
||||||
|
|
||||||
return i2cGetResult(bus_id);
|
return i2cGetResult(bus_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
u32 i2cWriteRegister(u8 dev_id, u8 reg, u8 data) {
|
u32 i2cWriteRegister(u8 dev_id, u8 reg, u8 data)
|
||||||
|
{
|
||||||
u8 bus_id = i2cGetDeviceBusId(dev_id);
|
u8 bus_id = i2cGetDeviceBusId(dev_id);
|
||||||
u8 dev_addr = i2cGetDeviceRegAddr(dev_id);
|
u8 dev_addr = i2cGetDeviceRegAddr(dev_id);
|
||||||
|
|
||||||
for (int i = 0; i < 8; i++) {
|
for (u32 i = 0; i < 8; i++)
|
||||||
if (i2cSelectDevice(bus_id, dev_addr) && i2cSelectRegister(bus_id, reg)) {
|
{
|
||||||
|
if (i2cSelectDevice(bus_id, dev_addr) && i2cSelectRegister(bus_id, reg))
|
||||||
|
{
|
||||||
i2cWaitBusy(bus_id);
|
i2cWaitBusy(bus_id);
|
||||||
*i2cGetDataReg(bus_id) = data;
|
*i2cGetDataReg(bus_id) = data;
|
||||||
*i2cGetCntReg(bus_id) = 0xC1;
|
*i2cGetCntReg(bus_id) = 0xC1;
|
||||||
i2cStop(bus_id, 0);
|
i2cStop(bus_id, 0);
|
||||||
|
|
||||||
if (i2cGetResult(bus_id))
|
if (i2cGetResult(bus_id))
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,8 +12,10 @@
|
|||||||
|
|
||||||
#define PAYLOAD_ADDRESS 0x24F00000
|
#define PAYLOAD_ADDRESS 0x24F00000
|
||||||
|
|
||||||
void loadPayload(void){
|
void loadPayload(void)
|
||||||
if(fileExists("aurei/payloads/default.bin")){
|
{
|
||||||
|
if(defPayloadExists())
|
||||||
|
{
|
||||||
initScreens();
|
initScreens();
|
||||||
memcpy((void *)PAYLOAD_ADDRESS, loader, loader_size);
|
memcpy((void *)PAYLOAD_ADDRESS, loader, loader_size);
|
||||||
((void (*)())PAYLOAD_ADDRESS)();
|
((void (*)())PAYLOAD_ADDRESS)();
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
/*
|
|
||||||
* main.c
|
|
||||||
* by Reisyukaku / Aurora Wright
|
|
||||||
* Copyright (c) 2016 All Rights Reserved
|
|
||||||
*
|
|
||||||
* Minimalist CFW for (N)3DS
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "fs.h"
|
|
||||||
#include "firm.h"
|
|
||||||
|
|
||||||
void main(void){
|
|
||||||
mountSD();
|
|
||||||
setupCFW();
|
|
||||||
loadFirm();
|
|
||||||
patchFirm();
|
|
||||||
launchFirm();
|
|
||||||
}
|
|
||||||
@@ -8,40 +8,43 @@
|
|||||||
|
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
|
|
||||||
void memcpy(void *dest, const void *src, u32 size){
|
void memcpy(void *dest, const void *src, u32 size)
|
||||||
|
{
|
||||||
u8 *destc = (u8 *)dest;
|
u8 *destc = (u8 *)dest;
|
||||||
const u8 *srcc = (const u8 *)src;
|
const u8 *srcc = (const u8 *)src;
|
||||||
|
|
||||||
for(u32 i = 0; i < size; i++)
|
for(u32 i = 0; i < size; i++)
|
||||||
destc[i] = srcc[i];
|
destc[i] = srcc[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
void memset(void *dest, int filler, u32 size){
|
void memset32(void *dest, u32 filler, u32 size)
|
||||||
u8 *destc = (u8 *)dest;
|
{
|
||||||
for(u32 i = 0; i < size; i++)
|
|
||||||
destc[i] = (u8)filler;
|
|
||||||
}
|
|
||||||
|
|
||||||
void memset32(void *dest, u32 filler, u32 size){
|
|
||||||
u32 *dest32 = (u32 *)dest;
|
u32 *dest32 = (u32 *)dest;
|
||||||
|
|
||||||
for (u32 i = 0; i < size / 4; i++)
|
for (u32 i = 0; i < size / 4; i++)
|
||||||
dest32[i] = filler;
|
dest32[i] = filler;
|
||||||
}
|
}
|
||||||
|
|
||||||
int memcmp(const void *buf1, const void *buf2, u32 size){
|
int memcmp(const void *buf1, const void *buf2, u32 size)
|
||||||
|
{
|
||||||
const u8 *buf1c = (const u8 *)buf1;
|
const u8 *buf1c = (const u8 *)buf1;
|
||||||
const u8 *buf2c = (const u8 *)buf2;
|
const u8 *buf2c = (const u8 *)buf2;
|
||||||
for(u32 i = 0; i < size; i++){
|
|
||||||
|
for(u32 i = 0; i < size; i++)
|
||||||
|
{
|
||||||
int cmp = buf1c[i] - buf2c[i];
|
int cmp = buf1c[i] - buf2c[i];
|
||||||
if(cmp) return cmp;
|
if(cmp) return cmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSize){
|
u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSize)
|
||||||
|
{
|
||||||
const u8 *patternc = (const u8 *)pattern;
|
const u8 *patternc = (const u8 *)pattern;
|
||||||
|
|
||||||
//Preprocessing
|
//Preprocessing
|
||||||
int table[256];
|
u32 table[256];
|
||||||
|
|
||||||
for(u32 i = 0; i < 256; ++i)
|
for(u32 i = 0; i < 256; ++i)
|
||||||
table[i] = patternSize + 1;
|
table[i] = patternSize + 1;
|
||||||
@@ -51,7 +54,8 @@ u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSize){
|
|||||||
//Searching
|
//Searching
|
||||||
u32 j = 0;
|
u32 j = 0;
|
||||||
|
|
||||||
while(j <= size - patternSize){
|
while(j <= size - patternSize)
|
||||||
|
{
|
||||||
if(memcmp(patternc, startPos + j, patternSize) == 0)
|
if(memcmp(patternc, startPos + j, patternSize) == 0)
|
||||||
return startPos + j;
|
return startPos + j;
|
||||||
j += table[startPos[j + patternSize]];
|
j += table[startPos[j + patternSize]];
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
void memcpy(void *dest, const void *src, u32 size);
|
void memcpy(void *dest, const void *src, u32 size);
|
||||||
void memset(void *dest, int filler, u32 size);
|
|
||||||
void memset32(void *dest, u32 filler, u32 size);
|
void memset32(void *dest, u32 filler, u32 size);
|
||||||
int memcmp(const void *buf1, const void *buf2, u32 size);
|
int memcmp(const void *buf1, const void *buf2, u32 size);
|
||||||
u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSize);
|
u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSize);
|
||||||
@@ -19,15 +19,19 @@ const u16 sigPatch[2] = {0x2000, 0x4770};
|
|||||||
|
|
||||||
const u16 writeBlock[2] = {0x2000, 0x46C0};
|
const u16 writeBlock[2] = {0x2000, 0x46C0};
|
||||||
|
|
||||||
|
const u8 unitInfoPatch = 0xE3;
|
||||||
|
|
||||||
/**************************************************
|
/**************************************************
|
||||||
* Functions
|
* Functions
|
||||||
**************************************************/
|
**************************************************/
|
||||||
|
|
||||||
u8 *getProc9(u8 *pos, u32 size){
|
u8 *getProc9(u8 *pos, u32 size)
|
||||||
|
{
|
||||||
return memsearch(pos, "ess9", size, 4);
|
return memsearch(pos, "ess9", size, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
void getSigChecks(u8 *pos, u32 size, u32 *off, u32 *off2){
|
void getSigChecks(u8 *pos, u32 size, u32 *off, u32 *off2)
|
||||||
|
{
|
||||||
//Look for signature checks
|
//Look for signature checks
|
||||||
const u8 pattern[] = {0xC0, 0x1C, 0x76, 0xE7},
|
const u8 pattern[] = {0xC0, 0x1C, 0x76, 0xE7},
|
||||||
pattern2[] = {0xB5, 0x22, 0x4D, 0x0C};
|
pattern2[] = {0xB5, 0x22, 0x4D, 0x0C};
|
||||||
@@ -36,16 +40,19 @@ void getSigChecks(u8 *pos, u32 size, u32 *off, u32 *off2){
|
|||||||
*off2 = (u32)memsearch(pos, pattern2, size, 4) - 1;
|
*off2 = (u32)memsearch(pos, pattern2, size, 4) - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *getReboot(u8 *pos, u32 size){
|
void *getReboot(u8 *pos, u32 size)
|
||||||
|
{
|
||||||
//Look for FIRM reboot code
|
//Look for FIRM reboot code
|
||||||
const u8 pattern[] = {0xDE, 0x1F, 0x8D, 0xE2};
|
const u8 pattern[] = {0xDE, 0x1F, 0x8D, 0xE2};
|
||||||
|
|
||||||
return memsearch(pos, pattern, size, 4) - 0x10;
|
return memsearch(pos, pattern, size, 4) - 0x10;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 getfOpen(u8 *proc9Offset, void *rebootOffset){
|
u32 getfOpen(u8 *proc9Offset, void *rebootOffset)
|
||||||
|
{
|
||||||
//Offset Process9 code gets loaded to in memory (defined in ExHeader)
|
//Offset Process9 code gets loaded to in memory (defined in ExHeader)
|
||||||
u32 p9MemAddr = *(u32 *)(proc9Offset + 0xC);
|
u32 p9MemAddr = *(u32 *)(proc9Offset + 0xC);
|
||||||
|
|
||||||
//Process9 code offset (start of NCCH + ExeFS offset + ExeFS header size)
|
//Process9 code offset (start of NCCH + ExeFS offset + ExeFS header size)
|
||||||
u32 p9CodeOff = (u32)(proc9Offset - 0x204) + (*(u32 *)(proc9Offset - 0x64) * 0x200) + 0x200;
|
u32 p9CodeOff = (u32)(proc9Offset - 0x204) + (*(u32 *)(proc9Offset - 0x64) * 0x200) + 0x200;
|
||||||
|
|
||||||
@@ -53,7 +60,8 @@ u32 getfOpen(u8 *proc9Offset, void *rebootOffset){
|
|||||||
return (u32)rebootOffset + 9 - (-((*(u32 *)rebootOffset & 0x00FFFFFF) << 2) & 0xFFFFF) - p9CodeOff + p9MemAddr;
|
return (u32)rebootOffset + 9 - (-((*(u32 *)rebootOffset & 0x00FFFFFF) << 2) & 0xFFFFF) - p9CodeOff + p9MemAddr;
|
||||||
}
|
}
|
||||||
|
|
||||||
u16 *getFirmWrite(u8 *pos, u32 size){
|
u16 *getFirmWrite(u8 *pos, u32 size)
|
||||||
|
{
|
||||||
//Look for FIRM writing code
|
//Look for FIRM writing code
|
||||||
u8 *const off = memsearch(pos, "exe:", size, 4);
|
u8 *const off = memsearch(pos, "exe:", size, 4);
|
||||||
const u8 pattern[] = {0x00, 0x28, 0x01, 0xDA};
|
const u8 pattern[] = {0x00, 0x28, 0x01, 0xDA};
|
||||||
@@ -61,9 +69,19 @@ u16 *getFirmWrite(u8 *pos, u32 size){
|
|||||||
return (u16 *)memsearch(off - 0x100, pattern, 0x100, 4);
|
return (u16 *)memsearch(off - 0x100, pattern, 0x100, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
void getLoader(u8 *pos, u32 size, u32 *loaderOffset, u32 *loaderSize){
|
u8 *getUnitInfoValueSet(u8 *pos, u32 size)
|
||||||
|
{
|
||||||
|
//Look for UNITINFO value being set
|
||||||
|
const u8 pattern[] = {0x01, 0x10, 0xA0, 0x13};
|
||||||
|
|
||||||
|
return memsearch(pos, pattern, size, 4) + 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *getLoader(u8 *pos, u32 size, u32 *loaderSize)
|
||||||
|
{
|
||||||
u8 *const off = memsearch(pos, "loade", size, 5);
|
u8 *const off = memsearch(pos, "loade", size, 5);
|
||||||
|
|
||||||
*loaderOffset = (u32)off - 0x200;
|
|
||||||
*loaderSize = *(u32 *)(off - 0xFC) * 0x200;
|
*loaderSize = *(u32 *)(off - 0xFC) * 0x200;
|
||||||
|
|
||||||
|
return off - 0x200;
|
||||||
}
|
}
|
||||||
@@ -15,6 +15,7 @@ const u32 mpuPatch[3];
|
|||||||
const u16 nandRedir[2];
|
const u16 nandRedir[2];
|
||||||
const u16 sigPatch[2];
|
const u16 sigPatch[2];
|
||||||
const u16 writeBlock[2];
|
const u16 writeBlock[2];
|
||||||
|
const u8 unitInfoPatch;
|
||||||
|
|
||||||
/**************************************************
|
/**************************************************
|
||||||
* Functions
|
* Functions
|
||||||
@@ -24,4 +25,5 @@ void getSigChecks(u8 *pos, u32 size, u32 *off, u32 *off2);
|
|||||||
void *getReboot(u8 *pos, u32 size);
|
void *getReboot(u8 *pos, u32 size);
|
||||||
u32 getfOpen(u8 *proc9Offset, void *rebootOffset);
|
u32 getfOpen(u8 *proc9Offset, void *rebootOffset);
|
||||||
u16 *getFirmWrite(u8 *pos, u32 size);
|
u16 *getFirmWrite(u8 *pos, u32 size);
|
||||||
void getLoader(u8 *pos, u32 size, u32 *loaderOffset, u32 *loaderSize);
|
u8 *getUnitInfoValueSet(u8 *pos, u32 size);
|
||||||
|
void *getLoader(u8 *pos, u32 size, u32 *loaderSize);
|
||||||
@@ -8,18 +8,25 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "screeninit.h"
|
#include "screeninit.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include "memory.h"
|
||||||
#include "draw.h"
|
#include "draw.h"
|
||||||
#include "i2c.h"
|
#include "i2c.h"
|
||||||
|
#include "../build/screeninit.h"
|
||||||
|
|
||||||
static vu32 *const arm11 = (u32 *)0x1FFFFFF8;
|
#define SCREENINIT_ADDRESS 0x24F03000
|
||||||
|
|
||||||
void deinitScreens(void){
|
vu32 *arm11Entry = (u32 *)0x1FFFFFF8;
|
||||||
void __attribute__((naked)) ARM11(void){
|
|
||||||
|
void deinitScreens(void)
|
||||||
|
{
|
||||||
|
void __attribute__((naked)) ARM11(void)
|
||||||
|
{
|
||||||
//Disable interrupts
|
//Disable interrupts
|
||||||
__asm(".word 0xF10C01C0");
|
__asm(".word 0xF10C01C0");
|
||||||
|
|
||||||
//Clear ARM11 entry offset
|
//Clear ARM11 entry offset
|
||||||
*arm11 = 0;
|
*arm11Entry = 0;
|
||||||
|
|
||||||
//Shutdown LCDs
|
//Shutdown LCDs
|
||||||
*(vu32 *)0x10202A44 = 0;
|
*(vu32 *)0x10202A44 = 0;
|
||||||
@@ -27,125 +34,33 @@ void deinitScreens(void){
|
|||||||
*(vu32 *)0x10202014 = 0;
|
*(vu32 *)0x10202014 = 0;
|
||||||
|
|
||||||
//Wait for the entry to be set
|
//Wait for the entry to be set
|
||||||
while(!*arm11);
|
while(!*arm11Entry);
|
||||||
|
|
||||||
//Jump to it
|
//Jump to it
|
||||||
((void (*)())*arm11)();
|
((void (*)())*arm11Entry)();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(PDN_GPU_CNT != 0x1){
|
if(PDN_GPU_CNT != 1)
|
||||||
*arm11 = (u32)ARM11;
|
{
|
||||||
while(*arm11);
|
*arm11Entry = (u32)ARM11;
|
||||||
|
while(*arm11Entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void initScreens(void){
|
void initScreens(void)
|
||||||
void __attribute__((naked)) ARM11(void){
|
{
|
||||||
//Disable interrupts
|
if(PDN_GPU_CNT == 1)
|
||||||
__asm(".word 0xF10C01C0");
|
{
|
||||||
|
memcpy((void *)SCREENINIT_ADDRESS, screeninit, screeninit_size);
|
||||||
|
|
||||||
*(vu32 *)0x10141200 = 0x1007F;
|
//Write brightness level for the stub to pick up
|
||||||
*(vu32 *)0x10202014 = 0x00000001;
|
*(vu32 *)(SCREENINIT_ADDRESS + 8) = MULTICONFIG(0);
|
||||||
*(vu32 *)0x1020200C &= 0xFFFEFFFE;
|
|
||||||
*(vu32 *)0x10202240 = 0x45;
|
|
||||||
*(vu32 *)0x10202A40 = 0x45;
|
|
||||||
*(vu32 *)0x10202244 = 0x1023E;
|
|
||||||
*(vu32 *)0x10202A44 = 0x1023E;
|
|
||||||
|
|
||||||
// Top screen
|
*arm11Entry = SCREENINIT_ADDRESS;
|
||||||
*(vu32 *)0x10400400 = 0x000001c2;
|
while(*arm11Entry);
|
||||||
*(vu32 *)0x10400404 = 0x000000d1;
|
|
||||||
*(vu32 *)0x10400408 = 0x000001c1;
|
|
||||||
*(vu32 *)0x1040040c = 0x000001c1;
|
|
||||||
*(vu32 *)0x10400410 = 0x00000000;
|
|
||||||
*(vu32 *)0x10400414 = 0x000000cf;
|
|
||||||
*(vu32 *)0x10400418 = 0x000000d1;
|
|
||||||
*(vu32 *)0x1040041c = 0x01c501c1;
|
|
||||||
*(vu32 *)0x10400420 = 0x00010000;
|
|
||||||
*(vu32 *)0x10400424 = 0x0000019d;
|
|
||||||
*(vu32 *)0x10400428 = 0x00000002;
|
|
||||||
*(vu32 *)0x1040042c = 0x00000192;
|
|
||||||
*(vu32 *)0x10400430 = 0x00000192;
|
|
||||||
*(vu32 *)0x10400434 = 0x00000192;
|
|
||||||
*(vu32 *)0x10400438 = 0x00000001;
|
|
||||||
*(vu32 *)0x1040043c = 0x00000002;
|
|
||||||
*(vu32 *)0x10400440 = 0x01960192;
|
|
||||||
*(vu32 *)0x10400444 = 0x00000000;
|
|
||||||
*(vu32 *)0x10400448 = 0x00000000;
|
|
||||||
*(vu32 *)0x1040045C = 0x00f00190;
|
|
||||||
*(vu32 *)0x10400460 = 0x01c100d1;
|
|
||||||
*(vu32 *)0x10400464 = 0x01920002;
|
|
||||||
*(vu32 *)0x10400468 = 0x18300000;
|
|
||||||
*(vu32 *)0x10400470 = 0x80341;
|
|
||||||
*(vu32 *)0x10400474 = 0x00010501;
|
|
||||||
*(vu32 *)0x10400478 = 0;
|
|
||||||
*(vu32 *)0x10400490 = 0x000002D0;
|
|
||||||
*(vu32 *)0x1040049C = 0x00000000;
|
|
||||||
|
|
||||||
// Disco register
|
//Turn on backlight
|
||||||
for(vu32 i = 0; i < 256; i++)
|
|
||||||
*(vu32 *)0x10400484 = 0x10101 * i;
|
|
||||||
|
|
||||||
// Bottom screen
|
|
||||||
*(vu32 *)0x10400500 = 0x000001c2;
|
|
||||||
*(vu32 *)0x10400504 = 0x000000d1;
|
|
||||||
*(vu32 *)0x10400508 = 0x000001c1;
|
|
||||||
*(vu32 *)0x1040050c = 0x000001c1;
|
|
||||||
*(vu32 *)0x10400510 = 0x000000cd;
|
|
||||||
*(vu32 *)0x10400514 = 0x000000cf;
|
|
||||||
*(vu32 *)0x10400518 = 0x000000d1;
|
|
||||||
*(vu32 *)0x1040051c = 0x01c501c1;
|
|
||||||
*(vu32 *)0x10400520 = 0x00010000;
|
|
||||||
*(vu32 *)0x10400524 = 0x0000019d;
|
|
||||||
*(vu32 *)0x10400528 = 0x00000052;
|
|
||||||
*(vu32 *)0x1040052c = 0x00000192;
|
|
||||||
*(vu32 *)0x10400530 = 0x00000192;
|
|
||||||
*(vu32 *)0x10400534 = 0x0000004f;
|
|
||||||
*(vu32 *)0x10400538 = 0x00000050;
|
|
||||||
*(vu32 *)0x1040053c = 0x00000052;
|
|
||||||
*(vu32 *)0x10400540 = 0x01980194;
|
|
||||||
*(vu32 *)0x10400544 = 0x00000000;
|
|
||||||
*(vu32 *)0x10400548 = 0x00000011;
|
|
||||||
*(vu32 *)0x1040055C = 0x00f00140;
|
|
||||||
*(vu32 *)0x10400560 = 0x01c100d1;
|
|
||||||
*(vu32 *)0x10400564 = 0x01920052;
|
|
||||||
*(vu32 *)0x10400568 = 0x18300000 + 0x46500;
|
|
||||||
*(vu32 *)0x10400570 = 0x80301;
|
|
||||||
*(vu32 *)0x10400574 = 0x00010501;
|
|
||||||
*(vu32 *)0x10400578 = 0;
|
|
||||||
*(vu32 *)0x10400590 = 0x000002D0;
|
|
||||||
*(vu32 *)0x1040059C = 0x00000000;
|
|
||||||
|
|
||||||
// Disco register
|
|
||||||
for(vu32 i = 0; i < 256; i++)
|
|
||||||
*(vu32 *)0x10400584 = 0x10101 * i;
|
|
||||||
|
|
||||||
// Enable backlight
|
|
||||||
i2cWriteRegister(I2C_DEV_MCU, 0x22, 0x2A);
|
i2cWriteRegister(I2C_DEV_MCU, 0x22, 0x2A);
|
||||||
|
|
||||||
*(vu32 *)0x10400468 = 0x18300000;
|
|
||||||
*(vu32 *)0x1040046c = 0x18300000;
|
|
||||||
*(vu32 *)0x10400494 = 0x18300000;
|
|
||||||
*(vu32 *)0x10400498 = 0x18300000;
|
|
||||||
*(vu32 *)0x10400568 = 0x18346500;
|
|
||||||
*(vu32 *)0x1040056c = 0x18346500;
|
|
||||||
|
|
||||||
//Set CakeBrah framebuffers
|
|
||||||
*((vu32 *)0x23FFFE00) = 0x18300000;
|
|
||||||
*((vu32 *)0x23FFFE04) = 0x18300000;
|
|
||||||
*((vu32 *)0x23FFFE08) = 0x18346500;
|
|
||||||
|
|
||||||
//Clear ARM11 entry offset
|
|
||||||
*arm11 = 0;
|
|
||||||
|
|
||||||
//Wait for the entry to be set
|
|
||||||
while(!*arm11);
|
|
||||||
//Jump to it
|
|
||||||
((void (*)())*arm11)();
|
|
||||||
}
|
|
||||||
|
|
||||||
if(PDN_GPU_CNT == 0x1){
|
|
||||||
*arm11 = (u32)ARM11;
|
|
||||||
while(*arm11);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
clearScreens();
|
clearScreens();
|
||||||
|
|||||||
@@ -2,6 +2,11 @@
|
|||||||
.align 4
|
.align 4
|
||||||
.global _start
|
.global _start
|
||||||
_start:
|
_start:
|
||||||
|
b start
|
||||||
|
|
||||||
|
.word 0
|
||||||
|
|
||||||
|
start:
|
||||||
@ Change the stack pointer
|
@ Change the stack pointer
|
||||||
mov sp, #0x27000000
|
mov sp, #0x27000000
|
||||||
|
|
||||||
@@ -28,9 +33,9 @@ _start:
|
|||||||
mcr p15, 0, r6, c6, c6, 0
|
mcr p15, 0, r6, c6, c6, 0
|
||||||
mcr p15, 0, r7, c6, c7, 0
|
mcr p15, 0, r7, c6, c7, 0
|
||||||
mov r0, #0x25
|
mov r0, #0x25
|
||||||
mcr p15, 0, r0, c2, c0, 0 @ data cacheable
|
mcr p15, 0, r0, c3, c0, 0 @ Write bufferable 0, 2, 5
|
||||||
mcr p15, 0, r0, c2, c0, 1 @ instruction cacheable
|
mcr p15, 0, r0, c2, c0, 0 @ Data cacheable 0, 2, 5
|
||||||
mcr p15, 0, r0, c3, c0, 0 @ data bufferable
|
mcr p15, 0, r0, c2, c0, 1 @ Inst cacheable 0, 2, 5
|
||||||
|
|
||||||
@ Enable caches
|
@ Enable caches
|
||||||
mrc p15, 0, r0, c1, c0, 0 @ read control register
|
mrc p15, 0, r0, c1, c0, 0 @ read control register
|
||||||
@@ -50,7 +55,4 @@ _start:
|
|||||||
mov r1, #0x340
|
mov r1, #0x340
|
||||||
str r1, [r0]
|
str r1, [r0]
|
||||||
|
|
||||||
bl main
|
b main
|
||||||
|
|
||||||
.die:
|
|
||||||
b .die
|
|
||||||
|
|||||||
122
source/utils.c
122
source/utils.c
@@ -7,128 +7,50 @@
|
|||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "screeninit.h"
|
#include "screeninit.h"
|
||||||
#include "draw.h"
|
#include "draw.h"
|
||||||
#include "fs.h"
|
|
||||||
#include "i2c.h"
|
#include "i2c.h"
|
||||||
#include "buttons.h"
|
#include "buttons.h"
|
||||||
|
|
||||||
#define COLOR_TITLE 0xFF9900
|
u32 waitInput(void)
|
||||||
#define COLOR_WHITE 0xFFFFFF
|
{
|
||||||
#define COLOR_RED 0x0000FF
|
u32 pressedKey = 0,
|
||||||
#define COLOR_BLACK 0x000000
|
key;
|
||||||
|
|
||||||
struct option {
|
|
||||||
int posY;
|
|
||||||
u32 enabled;
|
|
||||||
};
|
|
||||||
|
|
||||||
static u16 waitInput(void){
|
|
||||||
u32 pressedKey = 0;
|
|
||||||
u16 key;
|
|
||||||
|
|
||||||
//Wait for no keys to be pressed
|
//Wait for no keys to be pressed
|
||||||
while(HID_PAD);
|
while(HID_PAD);
|
||||||
|
|
||||||
do {
|
do
|
||||||
|
{
|
||||||
//Wait for a key to be pressed
|
//Wait for a key to be pressed
|
||||||
while(!HID_PAD);
|
while(!HID_PAD);
|
||||||
|
|
||||||
key = HID_PAD;
|
key = HID_PAD;
|
||||||
|
|
||||||
//Make sure it's pressed
|
//Make sure it's pressed
|
||||||
for(u32 i = 0x13000; i; i--){
|
for(u32 i = 0x13000; i; i--)
|
||||||
|
{
|
||||||
if(key != HID_PAD) break;
|
if(key != HID_PAD) break;
|
||||||
if(i == 1) pressedKey = 1;
|
if(i == 1) pressedKey = 1;
|
||||||
}
|
}
|
||||||
} while(!pressedKey);
|
}
|
||||||
|
while(!pressedKey);
|
||||||
|
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
void configureCFW(const char *configPath, const char *firm90Path){
|
void mcuShutDown(void)
|
||||||
initScreens();
|
{
|
||||||
|
i2cWriteRegister(I2C_DEV_MCU, 0x20, 1);
|
||||||
|
while(1);
|
||||||
|
}
|
||||||
|
|
||||||
drawString(CONFIG_TITLE, 10, 10, COLOR_TITLE);
|
void mcuReboot(void)
|
||||||
drawString("Press A to select, START to save and reboot", 10, 30, COLOR_WHITE);
|
{
|
||||||
|
|
||||||
const char *optionsText[] = { "( ) Updated SysNAND mode (A9LH-only)",
|
|
||||||
"( ) Use pre-patched FIRMs",
|
|
||||||
"( ) Force A9LH detection",
|
|
||||||
"( ) Use 9.0 FIRM as default",
|
|
||||||
"( ) Use second EmuNAND as default",
|
|
||||||
"( ) Show current NAND in System Settings" };
|
|
||||||
|
|
||||||
u32 optionsAmount = sizeof(optionsText) / sizeof(char *);
|
|
||||||
struct option options[optionsAmount];
|
|
||||||
|
|
||||||
//Read and parse the existing configuration
|
|
||||||
u32 tempConfig = 0;
|
|
||||||
fileRead(&tempConfig, configPath, 3);
|
|
||||||
for(u32 i = 0; i < optionsAmount; i++)
|
|
||||||
options[i].enabled = (tempConfig >> i) & 0x1;
|
|
||||||
|
|
||||||
//Pre-select the first configuration option
|
|
||||||
u32 selectedOption = 0;
|
|
||||||
|
|
||||||
//Boring configuration menu
|
|
||||||
while(1){
|
|
||||||
u16 pressed = 0;
|
|
||||||
|
|
||||||
do{
|
|
||||||
for(u32 i = 0; i < optionsAmount; i++){
|
|
||||||
options[i].posY = drawString(optionsText[i], 10, !i ? 60 : options[i - 1].posY + SPACING_Y, selectedOption == i ? COLOR_RED : COLOR_WHITE);
|
|
||||||
drawCharacter('x', 10 + SPACING_X, options[i].posY, options[i].enabled ? (selectedOption == i ? COLOR_RED : COLOR_WHITE) : COLOR_BLACK);
|
|
||||||
}
|
|
||||||
pressed = waitInput();
|
|
||||||
} while(!(pressed & MENU_BUTTONS));
|
|
||||||
|
|
||||||
switch(pressed){
|
|
||||||
case BUTTON_UP:
|
|
||||||
selectedOption = !selectedOption ? optionsAmount - 1 : selectedOption - 1;
|
|
||||||
break;
|
|
||||||
case BUTTON_DOWN:
|
|
||||||
selectedOption = selectedOption == optionsAmount - 1 ? 0 : selectedOption + 1;
|
|
||||||
break;
|
|
||||||
case BUTTON_LEFT:
|
|
||||||
selectedOption = 0;
|
|
||||||
break;
|
|
||||||
case BUTTON_RIGHT:
|
|
||||||
selectedOption = optionsAmount - 1;
|
|
||||||
break;
|
|
||||||
case BUTTON_A:
|
|
||||||
options[selectedOption].enabled = !options[selectedOption].enabled;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(pressed == BUTTON_START) break;
|
|
||||||
}
|
|
||||||
|
|
||||||
//If the user has been using A9LH and the "Updated SysNAND" setting changed, delete the patched 9.0 FIRM
|
|
||||||
if(((tempConfig >> 16) & 0x1) && ((tempConfig & 0x1) != options[0].enabled))
|
|
||||||
fileDelete(firm90Path);
|
|
||||||
|
|
||||||
//Preserve the last-used boot options (last 12 bits)
|
|
||||||
tempConfig &= 0xFFF000;
|
|
||||||
|
|
||||||
//Parse and write the selected options
|
|
||||||
for(u32 i = 0; i < optionsAmount; i++)
|
|
||||||
tempConfig |= options[i].enabled << i;
|
|
||||||
fileWrite(&tempConfig, configPath, 3);
|
|
||||||
|
|
||||||
//Zero the last booted FIRM flag
|
|
||||||
CFG_BOOTENV = 0;
|
|
||||||
|
|
||||||
//Reboot
|
|
||||||
i2cWriteRegister(I2C_DEV_MCU, 0x20, 1 << 2);
|
i2cWriteRegister(I2C_DEV_MCU, 0x20, 1 << 2);
|
||||||
while(1);
|
while(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void deleteFirms(const char *firmPaths[], u32 firms){
|
void error(const char *message)
|
||||||
while(firms){
|
{
|
||||||
fileDelete(firmPaths[firms - 1]);
|
|
||||||
firms--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void error(const char *message){
|
|
||||||
initScreens();
|
initScreens();
|
||||||
|
|
||||||
drawString("An error has occurred:", 10, 10, COLOR_RED);
|
drawString("An error has occurred:", 10, 10, COLOR_RED);
|
||||||
@@ -137,7 +59,5 @@ void error(const char *message){
|
|||||||
|
|
||||||
waitInput();
|
waitInput();
|
||||||
|
|
||||||
//Shutdown
|
mcuShutDown();
|
||||||
i2cWriteRegister(I2C_DEV_MCU, 0x20, 1);
|
|
||||||
while(1);
|
|
||||||
}
|
}
|
||||||
@@ -8,8 +8,7 @@
|
|||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
#define CFG_BOOTENV (*(vu8 *)0x10010000)
|
u32 waitInput(void);
|
||||||
|
void mcuShutDown(void);
|
||||||
void configureCFW(const char *configPath, const char *firm90Path);
|
void mcuReboot(void);
|
||||||
void deleteFirms(const char *firmPaths[], u32 firms);
|
|
||||||
void error(const char *message);
|
void error(const char *message);
|
||||||
Reference in New Issue
Block a user