Compare commits

..

47 Commits
v4.2 ... v5.1.1

Author SHA1 Message Date
Aurora
a11124a3d6 Remove LFN support from the loader FatFs as it is not used. Slims down the binary by ~4 KBs 2016-04-18 04:47:53 +02:00
Aurora
d2d6e786c7 Fixed L+SELECT payload being broken (annoying LFN to 8.3 conversion rules). Now the payload is sel_NAME.bin 2016-04-18 02:55:54 +02:00
Aurora
a76c943c01 Reinstated the L+SELECT payload 2016-04-17 19:35:29 +02:00
Aurora
3c64a3a234 Updated ReadME 2016-04-17 19:11:38 +02:00
Aurora
06060c67b5 Changed the chainloader to load payloads named "BUTTON_NAME.bin", to remember which payload is which. Original idea and code by @habbbe (many thanks!) 2016-04-17 18:57:25 +02:00
Aurora
0f64fd73ec Fix bug when quitting AGB_FIRM
The wrong config.bin section was used to remember the last-used FIRM
2016-04-16 20:27:52 +02:00
Aurora
2323528975 Merge pull request #29 from habbbe/master
Made define for payload paths (removes repeated parts of file paths t…
2016-04-16 18:39:22 +02:00
habbbe
22b38a0f88 Made define for payload paths (removes repeated parts of file paths to payloads) 2016-04-16 18:21:42 +02:00
Aurora
034c0f8d7c Updated ReadME 2016-04-15 19:46:25 +02:00
Aurora
b4cd67cb8c Merge pull request #24 from ericchu94/master
Fix buffer overflow due to null character
2016-04-15 19:32:10 +02:00
Eric Chu
be83d77187 Fix buffer overflow due to null character 2016-04-15 12:54:30 -04:00
Aurora
615cf81a9f Further compatibility fix for language/region emulation, now works with games like Kirby Triple Deluxe 2016-04-15 17:54:45 +02:00
Aurora
c60ef7fe82 Better to reboot here 2016-04-15 16:10:32 +02:00
Aurora
fea5a111a9 Misc fixes, renamed "Updated SysNAND" to reflect what the option actually does now 2016-04-15 16:01:44 +02:00
Aurora
7eebfd4f6a Added improved language emulation from @TuxSH (improves compatibility), fixed language emulation only working for the first launched game/app and not being applied on demos 2016-04-15 03:34:08 +02:00
Aurora
939965b5a0 Cleanup 2016-04-14 17:10:55 +02:00
Aurora
a0334120a6 Added region/language emulation feature, thanks to the hard work of @TuxSH
Create a "locales" folder inside aurei, and one .txt for each game, with the title id of the game. The txt must be exactly 6 bytes long: 3 characters for the region ("JPN", "USA", "EUR", "AUS", "CHN", "KOR", "TWN"), a space, and two for the language ("JP", "EN", "FR", "DE", "IT", "ES", "ZH", "KO", "NL", "PT", "RU", "TW"). You can enable the feature globally in the config menu. This should also make DLCs for foreign games work.
2016-04-14 00:59:14 +02:00
Aurora
308417a48e Added region/language emulation feature, thanks to the hard work of @TuxSH
Create a "locales" folder inside aurei, and one .txt for each game, with the title id of the game. The txt must be exactly 6 bytes long: 3 characters for the region ("JPN", "USA", "EUR", "AUS", "CHN", "KOR", "TWN"), a space, and two for the language ("JP", "EN", "FR", "DE", "IT", "ES", "ZH", "KO", "NL", "PT", "RU", "TW"). You can enable the feature globally in the config menu. This should also make DLCs for foreign games work.
2016-04-14 00:56:34 +02:00
Aurora
85533411c9 Config menu cleanup 2016-04-13 15:29:44 +02:00
Aurora
6d4a84a325 Remove unneeded stuff from the loader injection 2016-04-13 14:37:40 +02:00
Aurora
89350b1edd Fixed config.bin getting recreated on each boot 2016-04-13 04:18:59 +02:00
Aurora
9e58e4ed7a Screwed up the order of the CPU settings 2016-04-13 00:36:35 +02:00
Aurora
f8f4ecea27 Add better code to the FIRM finding function to convert from integer to its hex representation array 2016-04-13 00:20:28 +02:00
Aurora
e9449f86bf Rewrote config menu to allow for multiple choice settings, made the N3DS CPU patch configurable in the NTR way, changed the config.bin format to be more future-proof (settings are on the leftmost part), added more macros to read settings 2016-04-12 23:28:35 +02:00
Aurora
4fabe1f704 Added new and working N3DS CPU patch from @TuxSH 2016-04-12 15:25:36 +02:00
Aurora
ef3ba896d5 Cleanup, removed the non-working clock speed patch 2016-04-12 14:32:38 +02:00
Aurora
649b160292 Use better makefiles for loader and the screen init stub 2016-04-12 04:55:36 +02:00
Aurora
697bc74535 Added tentative N3DS clock speed/L2 cache patch by @TuxSH. 2016-04-12 01:22:42 +02:00
Aurora
0e9ff44746 Made N3DS >9.6 key generation version independent 2016-04-11 22:26:39 +02:00
Aurora
49d49e637a Merge pull request #20 from Steveice10/master
Add developer UNITINFO patch.
2016-04-11 21:17:22 +02:00
Steven Smith
b3f0d13aa4 Add developer UNITINFO patch. 2016-04-11 12:14:51 -07:00
Aurora
bd1547710e Derp 2016-04-11 18:43:51 +02:00
Aurora
7479bf8092 Fixed possible issue with the injector 2016-04-11 18:08:22 +02:00
Aurora
d4d281bb9c Removed debug info patch 2016-04-11 17:14:00 +02:00
Aurora
68bf134017 Merge pull request #19 from TuxSH/master
"Friends" and "ErrDisp" patches (and Makefile fix)
2016-04-11 16:46:12 +02:00
Aurora
c7b90f739f Use fLTO to reduce the binary size 2016-04-11 15:58:58 +02:00
Aurora
160bc36ae8 Update FatFs for the loader 2016-04-11 15:13:05 +02:00
Aurora
464bf1680c Small changes 2016-04-11 14:42:34 +02:00
TuxSH
c51eaba18c Revert "Update FatFs"
This reverts commit 6d06ea6975.
2016-04-11 11:46:49 +02:00
Aurora
7dbded99a2 First commit of the AuReiNand rewrite!
- Gotten rid of the patched FIRMs, AuReiNand now finds and loads all the FIRMs from CTRNAND by default. If you are booting an emuNAND, the FIRMs will be loaded from its CTRNAND. This also applies to AGB and TWL FIRM, and allows for a very fast boot with no firmware files on the SD card.
- If for some reason (like using NTR) you do not want to use the CTRNAND FIRM, you can place a firmware.bin in the aurei folder and it will be loaded just for the default NAND.
- The way AuReiNand works has changed. Now you can specify to autoboot SysNAND or not, and a NAND is no more tied to a FIRM (since 9.0 FIRM is autodetected). If you press nothing the default NAND is booted with its own FIRM, L boots the non-default NAND with its own FIRM, R boots EmuNAND with the SysNAND FIRM if you picked "Updated SysNAND", and vice-versa.
- In order for AuReiNand to handle FIRM reboots, the .bin path needs to be hardcoded in the program. The default is /arm9loaderhax.bin (the AuReiNand.dat is also supported for 9.0 people). A PC tool was written to make changing the path easier.
- Bug fixes and stuff I forgot.
- Gelex is a saint.
2016-04-11 05:58:46 +02:00
TuxSH
6351e5b8c3 Implement "friends" and "ErrDisp" patches 2016-04-08 23:28:40 +02:00
TuxSH
5a0f2e4dfc Fix Makefile (by including 3ds_rules) 2016-04-08 19:52:37 +02:00
Aurora
6d06ea6975 Update FatFs 2016-04-07 17:16:57 +02:00
Aurora
4180261f1f Small changes, added a macro for reading options 2016-04-06 14:54:58 +02:00
Aurora
e882dd7aaf Rewrote the config menu (no longer prints the whole menu on each button press), cleaned up the reboot patch, boot options will keep being forced if a GBA game was lanched from SysNAND, added option to have a splash screen with the built-in screen-init 2016-04-05 23:20:21 +02:00
Aurora
9e851d2dfd Small code reorganization 2016-04-05 05:34:57 +02:00
Aurora
21a3edb150 Get rid of double options reading 2016-04-05 03:08:38 +02:00
54 changed files with 12687 additions and 11886 deletions

1
.gitignore vendored
View File

@@ -1,6 +1,7 @@
out out
build build
loader/build loader/build
screeninit/build
injector/build injector/build
*.bin *.bin
*.3dsx *.3dsx

View File

@@ -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
@@ -19,13 +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
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,18 +50,24 @@ 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_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
@@ -62,43 +76,41 @@ $(dir_out)/arm9loaderhax.bin: $(dir_build)/main.bin $(dir_out)
@cp -a $(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)/screeninit.h: $(dir_screeninit)/Makefile
@$(MAKE) -C $(dir_screeninit)
@mv $(dir_screeninit)/screeninit.bin $(dir_build)
@bin2c -o $@ -n screeninit $(dir_build)/screeninit.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)/memory.o : CFLAGS+=-O3 $(dir_build)/patches.h: $(dir_patches)/emunand.s $(dir_patches)/reboot.s $(dir_injector)/Makefile
$(dir_build)/utils.o : CFLAGS += -DCONFIG_TITLE="\"$(name) $(version) configuration\"" @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)/%.o: $(dir_source)/%.c $(dir_build)/patches.h $(dir_build)/loader.h $(dir_build)/screeninit.h $(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) $<
@@ -108,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)

View File

@@ -3,34 +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.
You also need to have a recent build of makerom in your path for the injector to be built. **Setup / Usage / Features:**
Lastly, just run Make and everything should work! See https://github.com/AuroraWright/AuReiNand/wiki
Copy everything in 'out' folder to SD root and run!
**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://www77.zippyshare.com/v/oXDn2Hes/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, and the heavy revision to the reboot patch to allow for AGB/TWL loading are from CakesFW.
ARM11 userland patching is only possible thanks to @yifanlu's 3ds_injector, which is bundled in the CFW.

View File

@@ -5,10 +5,13 @@
#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)
@@ -44,16 +47,15 @@ static u32 patchMemory(u8 *start, u32 size, const void *pattern, u32 patSize, in
{ {
u8 *found = memsearch(start, pattern, size, patSize); u8 *found = memsearch(start, pattern, size, patSize);
if(found == NULL) if(found == NULL) break;
break;
memcpy(found + offset, replace, repSize); 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);
size -= at + patSize;
start = found + patSize; start = found + patSize;
} }
@@ -72,51 +74,215 @@ static int fileOpen(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 loadSecureinfo() static int loadSecureInfo(void)
{ {
IFile file; if(secureInfo[0] == 0xFF)
Result ret;
u64 total;
if(secureinfo[0] == 0xFF)
return 0; return 0;
ret = fileOpen(&file, ARCHIVE_NAND_RW, "/sys/SecureInfo_C", FS_OPEN_READ); IFile file;
Result ret = fileOpen(&file, ARCHIVE_NAND_RW, "/sys/SecureInfo_C", FS_OPEN_READ);
if(R_SUCCEEDED(ret)) if(R_SUCCEEDED(ret))
{ {
ret = IFile_Read(&file, &total, secureinfo, sizeof(secureinfo)); 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)
secureinfo[0] = 0xFF; secureInfo[0] = 0xFF;
} }
return ret; return ret;
} }
static int loadConfig() static int loadConfig(void)
{ {
IFile file;
Result ret;
u64 total;
if(config) if(config)
return 0; return 0;
ret = fileOpen(&file, ARCHIVE_SDMC, "/aurei/config.bin", FS_OPEN_READ); IFile file;
Result ret = fileOpen(&file, ARCHIVE_SDMC, "/aurei/config.bin", FS_OPEN_READ);
if(R_SUCCEEDED(ret)) if(R_SUCCEEDED(ret))
{ {
ret = IFile_Read(&file, &total, &config, 3); 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;
} }
static int loadTitleLocaleConfig(u64 progId, u8 *regionId, u8 *languageId)
{
/* Here we look for "/aurei/locales/[u64 titleID in hex, uppercase].txt"
If it exists it should contain, for example, "EUR IT" */
char path[] = "/aurei/locales/0000000000000000.txt";
u32 i = 30;
while(progId > 0)
{
static const char hexDigits[] = "0123456789ABCDEF";
path[i--] = hexDigits[(u32)(progId & 0xF)];
progId >>= 4;
}
IFile file;
Result ret = fileOpen(&file, ARCHIVE_SDMC, path, FS_OPEN_READ);
if(R_SUCCEEDED(ret))
{
char buf[6];
u64 total;
ret = IFile_Read(&file, &total, buf, 6);
IFile_Close(&file);
if(!R_SUCCEEDED(ret) || total < 6) return -1;
for(u32 i = 0; i < 7; ++i)
{
static const char *regions[] = {"JPN", "USA", "EUR", "AUS", "CHN", "KOR", "TWN"};
if(memcmp(buf, regions[i], 3) == 0)
{
*regionId = (u8)i;
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) void patchCode(u64 progId, u8 *code, u32 size)
{ {
switch(progId) switch(progId)
@@ -180,6 +346,25 @@ void patchCode(u64 progId, u8 *code, u32 size)
break; 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;
}
break;
}
case 0x0004001000021000LL: // USA MSET case 0x0004001000021000LL: // USA MSET
case 0x0004001000020000LL: // JPN MSET case 0x0004001000020000LL: // JPN MSET
case 0x0004001000022000LL: // EUR MSET case 0x0004001000022000LL: // EUR MSET
@@ -187,18 +372,18 @@ void patchCode(u64 progId, u8 *code, u32 size)
case 0x0004001000027000LL: // KOR MSET case 0x0004001000027000LL: // KOR MSET
case 0x0004001000028000LL: // TWN MSET case 0x0004001000028000LL: // TWN MSET
{ {
if(R_SUCCEEDED(loadConfig()) && ((config >> 5) & 1)) if(R_SUCCEEDED(loadConfig()) && CONFIG(6))
{ {
static const u16 verPattern[] = u"Ver."; static const u16 verPattern[] = u"Ver.";
const u32 currentFirm = ((config >> 12) & 1); const u32 currentNand = BOOTCONFIG(0, 3);
const u32 currentNand = ((config >> 13) & 3); const u32 matchingFirm = BOOTCONFIG(2, 1) == (currentNand != 0);
//Patch Ver. string //Patch Ver. string
patchMemory(code, size, patchMemory(code, size,
verPattern, verPattern,
sizeof(verPattern) - sizeof(u16), 0, sizeof(verPattern) - sizeof(u16), 0,
currentNand ? ((currentNand == 1) ? ((currentFirm == 1) ? u" Emu" : u"Emu9") : u"Emu2") : !currentNand ? ((matchingFirm) ? u" Sys" : u"SysE") :
((currentFirm == 1) ? u" Sys" : u"Sys9"), ((currentNand == 1) ? (matchingFirm ? u" Emu" : u"EmuS") : ((matchingFirm) ? u"Emu2" : u"Em2S")),
sizeof(verPattern) - sizeof(u16), 1 sizeof(verPattern) - sizeof(u16), 1
); );
} }
@@ -223,6 +408,22 @@ void patchCode(u64 progId, u8 *code, u32 size)
sizeof(stopCartUpdatesPatch), 2 sizeof(stopCartUpdatesPatch), 2
); );
if(R_SUCCEEDED(loadConfig()) && MULTICONFIG(1))
{
static const u8 cfgN3dsCpuPattern[] = {
0x40, 0xA0, 0xE1, 0x07, 0x00
};
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; break;
} }
@@ -243,7 +444,7 @@ void patchCode(u64 progId, u8 *code, u32 size)
sizeof(secureinfoSigCheckPatch), 1 sizeof(secureinfoSigCheckPatch), 1
); );
if(R_SUCCEEDED(loadSecureinfo())) if(R_SUCCEEDED(loadSecureInfo()))
{ {
static const u16 secureinfoFilenamePattern[] = u"SecureInfo_"; static const u16 secureinfoFilenamePattern[] = u"SecureInfo_";
static const u16 secureinfoFilenamePatch[] = u"C"; static const u16 secureinfoFilenamePatch[] = u"C";
@@ -260,5 +461,35 @@ void patchCode(u64 progId, u8 *code, u32 size)
break; 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, &regionId, &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;
}
} }
} }

View File

@@ -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,108 +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
#--------------------------------------------------------------------------------- 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
#---------------------------------------------------------------------------------
# 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))
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)))
#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C
#---------------------------------------------------------------------------------
ifeq ($(strip $(CPPFILES)),)
#---------------------------------------------------------------------------------
export LD := $(CC)
#---------------------------------------------------------------------------------
else
#---------------------------------------------------------------------------------
export LD := $(CXX)
#---------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------
export OFILES := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
.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
#---------------------------------------------------------------------------------------

View File

@@ -9,4 +9,3 @@ SECTIONS
.rodata : { *(.rodata) } .rodata : { *(.rodata) }
. = ALIGN(4); . = ALIGN(4);
} }

View File

@@ -3,11 +3,11 @@
#include "types.h" #include "types.h"
#define HID_PAD (*(vu32 *)0x10146000 ^ 0xFFF) #define HID_PAD (*(vu32 *)0x10146000 ^ 0xFFF)
#define BUTTON_X (1 << 10)
#define BUTTON_Y (1 << 11)
#define BUTTON_R1 (1 << 8)
#define BUTTON_SELECT (1 << 2)
#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)

View 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).

View File

@@ -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

File diff suppressed because it is too large Load Diff

6
loader/source/fatfs/ff.h Normal file → Executable file
View 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
View 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
View 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;

View File

@@ -3,21 +3,36 @@
#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 *path) 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';
FIL payload; FIL payload;
unsigned int br; unsigned int br;
if(f_open(&payload, path, FA_READ) == FR_OK) f_open(&payload, path, FA_READ);
{ f_read(&payload, (void *)PAYLOAD_ADDRESS, f_size(&payload), &br);
f_read(&payload, (void *)PAYLOAD_ADDRESS, f_size(&payload), &br); f_close(&payload);
f_close(&payload);
return 1; return 1;
}
return 0;
} }
void main(void) void main(void)
@@ -29,14 +44,14 @@ void main(void)
//Get pressed buttons //Get pressed buttons
u32 pressed = HID_PAD; u32 pressed = HID_PAD;
if(((pressed & BUTTON_RIGHT) && loadPayload("/aurei/payloads/right.bin")) || if(((pressed & BUTTON_RIGHT) && LOAD_PAYLOAD("right")) ||
((pressed & BUTTON_LEFT) && loadPayload("/aurei/payloads/left.bin")) || ((pressed & BUTTON_LEFT) && LOAD_PAYLOAD("left")) ||
((pressed & BUTTON_UP) && loadPayload("/aurei/payloads/up.bin")) || ((pressed & BUTTON_UP) && LOAD_PAYLOAD("up")) ||
((pressed & BUTTON_DOWN) && loadPayload("/aurei/payloads/down.bin")) || ((pressed & BUTTON_DOWN) && LOAD_PAYLOAD("down")) ||
((pressed & BUTTON_X) && loadPayload("/aurei/payloads/x.bin")) || ((pressed & BUTTON_X) && LOAD_PAYLOAD("x")) ||
((pressed & BUTTON_Y) && loadPayload("/aurei/payloads/y.bin")) || ((pressed & BUTTON_Y) && LOAD_PAYLOAD("y")) ||
((pressed & BUTTON_SELECT) && loadPayload("/aurei/payloads/select.bin")) || ((pressed & BUTTON_R1) && LOAD_PAYLOAD("r")) ||
((pressed & BUTTON_R1) && loadPayload("/aurei/payloads/r.bin")) || ((pressed & BUTTON_SELECT) && LOAD_PAYLOAD("sel")) ||
loadPayload("/aurei/payloads/default.bin")) LOAD_PAYLOAD("def"))
((void (*)())PAYLOAD_ADDRESS)(); ((void (*)())PAYLOAD_ADDRESS)();
} }

View File

@@ -1,5 +0,0 @@
%rename link old_link
*link:
%(old_link) -T ../stub.ld%s

View File

@@ -1,8 +1,7 @@
.arm.little .arm.little
firm_addr equ 0x24000000 ; Temporary location where we'll load the FIRM to payload_addr equ 0x23F00000 ; Brahma payload address.
firm_maxsize equ 0x200000 ; Random value that's bigger than any of the currently known firm's sizes. payload_maxsize equ 0x20000 ; Maximum size for the payload (200 KB will do).
kernel_code equ 0x080F0000 ; Offset to copy the Kernel9 code to
.create "reboot.bin", 0 .create "reboot.bin", 0
.arm .arm
@@ -22,80 +21,43 @@ kernel_code equ 0x080F0000 ; Offset to copy the Kernel9 code to
cmp r0, r2 cmp r0, r2
bne pxi_wait_recv bne pxi_wait_recv
; Convert 2 bytes of the path string mov r4, #0
; This will be the method of getting the lower 2 bytes of the title ID adr r1, bin_fname
; until someone bothers figuring out where the value is derived from. b open_payload
mov r0, #0 ; Result
add r1, sp, #0x3A8 - 0x70
add r1, #0x22 ; The significant bytes
mov r2, #4 ; Maximum loops (amount of bytes * 2)
hex_string_to_int_loop:
ldr r3, [r1], #2 ; 2 because it's a utf-16 string.
and r3, #0xFF
; Check if it"s a number
cmp r3, #'0'
blo hex_string_to_int_end
sub r3, #'0'
cmp r3, #9
bls hex_string_to_int_calc
; Check if it"s a capital letter
cmp r3, #'A' - '0'
blo hex_string_to_int_end
sub r3, #'A' - '0' - 0xA ; Make the correct value: 0xF >= al >= 0xA
cmp r3, #0xF
bls hex_string_to_int_calc
; Incorrect value: x > "A"
bhi hex_string_to_int_end
hex_string_to_int_calc:
orr r0, r3, r0, lsl #4
subs r2, #1
bne hex_string_to_int_loop
hex_string_to_int_end:
; Get the FIRM path
cmp r0, #0x0002 ; NATIVE_FIRM
adreq r1, firm_fname
beq load_firm
ldr r5, =0x0102 ; TWL_FIRM
cmp r0, r5
adreq r1, twlfirm_fname
beq load_firm
ldr r5, =0x0202 ; AGB_FIRM
cmp r0, r5
adreq r1, agbfirm_fname
beq load_firm
bne fallback ; TODO: Stubbed
fallback: fallback:
; Fallback: Load specified FIRM from exefs mov r4, #1
add r1, sp, #0x3A8-0x70 ; Location of exefs string. adr r1, dat_fname
b load_firm
load_firm: open_payload:
; Open file ; Open file
add r0, r7, #8 add r0, r7, #8
mov r2, #1 mov r2, #1
ldr r6, [fopen] ldr r6, [fopen]
orr r6, 1 orr r6, 1
blx r6 blx r6
cmp r0, #0
bne fallback ; If the .bin is not found, try the .dat.
cmp r0, #0 ; Check if we were able to load the FIRM read_payload:
bne fallback ; Otherwise, try again with the FIRM from exefs.
; This will loop indefinitely if the exefs FIRM fails to load, but whatever.
; Read file ; Read file
mov r0, r7 mov r0, r7
adr r1, bytes_read adr r1, bytes_read
mov r2, firm_addr ldr r2, =payload_addr
mov r3, firm_maxsize cmp r4, #0
ldr r6, [sp, #0x3A8-0x198] movne r3, #0x12000 ; Skip the first 0x12000 bytes.
ldr r6, [r6, #0x28] moveq r3, payload_maxsize
blx r6 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.
add r0, sp, #0x3A8 - 0x70
ldr r0, [r0, #0x27]
ldr r1, =payload_addr + 4
str r0, [r1] ; Copy the last digits of the wanted firm to the 5th byte of the payload.
; Set kernel state ; Set kernel state
mov r0, #0 mov r0, #0
@@ -108,35 +70,18 @@ kernel_code equ 0x080F0000 ; Offset to copy the Kernel9 code to
; Jump to reboot code ; Jump to reboot code
ldr r0, =(kernelcode_start - goto_reboot - 12) ldr r0, =(kernelcode_start - goto_reboot - 12)
add r0, pc add r0, pc
ldr r1, =kernel_code
ldr r2, =0x300
bl memcpy32
ldr r0, =kernel_code
swi 0x7B swi 0x7B
die: die:
b die b die
memcpy32: ; memcpy32(void *src, void *dst, unsigned int size)
add r2, r0
memcpy32_loop:
ldmia r0!, {r3}
stmia r1!, {r3}
cmp r0, r2
blo memcpy32_loop
bx lr
bytes_read: .word 0 bytes_read: .word 0
fopen: .ascii "OPEN" fopen: .ascii "OPEN"
.pool .pool
firm_fname: .dcw "sdmc:/aurei/patched_firmware_sys.bin" bin_fname: .dcw "sdmc:/arm9loaderhax.bin"
.word 0x0 .word 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
.pool dat_fname: .dcw "sdmc:/AuReiNand.dat"
twlfirm_fname: .dcw "sdmc:/aurei/patched_firmware_twl.bin" .word 0
.word 0x0
.pool
agbfirm_fname: .dcw "sdmc:/aurei/patched_firmware_agb.bin"
.word 0x0
.align 4 .align 4
kernelcode_start: kernelcode_start:
@@ -171,23 +116,6 @@ agbfirm_fname: .dcw "sdmc:/aurei/patched_firmware_agb.bin"
mcr p15, 0, r1, c2, c0, 1 ; icacheable mcr p15, 0, r1, c2, c0, 1 ; icacheable
mcr p15, 0, r2, c3, c0, 0 ; write bufferable mcr p15, 0, r2, c3, c0, 0 ; write bufferable
; Copy the firmware
mov r4, firm_addr
add r5, r4, #0x40 ; Start of loop
add r6, r5, #0x30 * 3 ; End of loop (scan 4 entries)
copy_firm_loop:
ldr r0, [r5]
cmp r0, #0
addne r0, r4 ; src
ldrne r1, [r5, #4] ; dest
ldrne r2, [r5, #8] ; size
blne kernelmemcpy32
cmp r5, r6
addlo r5, #0x30
blo copy_firm_loop
; Flush cache ; Flush cache
mov r2, #0 mov r2, #0
mov r1, r2 mov r1, r2
@@ -211,22 +139,10 @@ agbfirm_fname: .dcw "sdmc:/aurei/patched_firmware_agb.bin"
mcr p15, 0, r1, c7, c5, 0 ; flush dcache mcr p15, 0, r1, c7, c5, 0 ; flush dcache
mcr p15, 0, r1, c7, c6, 0 ; flush icache mcr p15, 0, r1, c7, c6, 0 ; flush icache
mcr p15, 0, r1, c7, c10, 4 ; drain write buffer mcr p15, 0, r1, c7, c10, 4 ; drain write buffer
mov r0, firm_addr
; Boot FIRM ; Jump to payload
mov r1, #0x1FFFFFFC ldr r0, =payload_addr
ldr r2, [r0, #8] ; arm11 entry
str r2, [r1]
ldr r0, [r0, #0xC] ; arm9 entry
bx r0 bx r0
.pool
kernelmemcpy32: ; memcpy32(void *src, void *dst, unsigned int size) .pool
add r2, r0
kmemcpy32_loop:
ldmia r0!, {r3}
stmia r1!, {r3}
cmp r0, r2
blo kmemcpy32_loop
bx lr
.close .close

98
pathchanger/pathchanger.c Normal file
View 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);
}

View File

@@ -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,108 +6,42 @@ 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
#--------------------------------------------------------------------------------- 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=mpcore
-mcpu=mpcore -mlittle-endian\ 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 := -nostdlib
$(ARCH)
CFLAGS += $(INCLUDE) -DARM11 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
#---------------------------------------------------------------------------------
# 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))
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)))
#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C
#---------------------------------------------------------------------------------
ifeq ($(strip $(CPPFILES)),)
#---------------------------------------------------------------------------------
export LD := $(CC)
#---------------------------------------------------------------------------------
else
#---------------------------------------------------------------------------------
export LD := $(CXX)
#---------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------
export OFILES := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
.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 include $(call rwildcard, $(dir_build), *.d)
$(OUTPUT).elf : $(OFILES)
#---------------------------------------------------------------------------------
%.bin: %.elf
@$(OBJCOPY) -O binary $< $@
@echo built ... $(notdir $@)
-include $(DEPENDS)
#---------------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------------

View File

@@ -3,7 +3,7 @@
void main(void) void main(void)
{ {
const u32 brightness[4] = {0x5F, 0x4C, 0x39, 0x26}; const u32 brightness[4] = {0x5F, 0x4C, 0x39, 0x26};
u32 brightnessLevel = *(vu32 *)0x24F04000; u32 brightnessLevel = *(vu32 *)0x24F03008;
vu32 *const arm11 = (u32 *)0x1FFFFFF8; vu32 *const arm11 = (u32 *)0x1FFFFFF8;
*(vu32 *)0x10141200 = 0x1007F; *(vu32 *)0x10141200 = 0x1007F;

View File

@@ -6,3 +6,5 @@ _start:
CPSID aif CPSID aif
b main b main
.word 0

View File

@@ -1,5 +0,0 @@
%rename link old_link
*link:
%(old_link) -T ../stub.ld%s

184
source/config.c Normal file
View 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
View 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);

View File

@@ -229,86 +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)
//Initialize the CTRNAND crypto
void ctrNandInit(void)
{ {
u8 *addr = (console ? (u8 *)0x080D8BBC : (u8 *)0x080D797C) + 0x0F; u8 cid[0x10];
for(u8 keyLen = 0x10; keyLen; keyLen--) u8 shaSum[0x20];
*(buf++) = *(addr--);
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]; u8 tmpCTR[0x10];
getNandCTR(CTR, console); 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);
//Calculate the size of the ARM9 binary //Calculate the size of the ARM9 binary
u32 size = 0; 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 = arm9Section + 0x89814;
u8 *decKey = keyData + 0x10;
//Set keys 0x19..0x1F keyXs
aes_setkey(0x11, key2, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL);
aes_use_keyslot(0x11);
for(u8 slot = 0x19; slot < 0x20; slot++)
{ {
aes(decKey, keyData, 1, NULL, AES_ECB_DECRYPT_MODE, 0); u8 keyData[] = {0xDD, 0xDA, 0xA4, 0xC6, 0x2C, 0xC4, 0x50, 0xE9, 0xDA, 0xB6, 0x9B, 0x0D, 0x9D, 0x2A, 0x21, 0x98};
aes_setkey(slot, decKey, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL); u8 decKey[0x10];
*(keyData + 0xF) += 1;
//Set keys 0x19..0x1F keyXs
aes_use_keyslot(0x11);
for(u8 slot = 0x19; slot < 0x20; slot++)
{
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;
}
} }
} }

View File

@@ -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);

View File

@@ -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"
@@ -24,6 +25,7 @@ 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;
} }
@@ -36,13 +38,13 @@ void clearScreens(void)
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; u64 i = 0x1400000;
while(--i) __asm("mov r0, r0"); //Less Ghetto sleep func while(--i) __asm("mov r0, r0"); //Less Ghetto sleep func
} }
} }
@@ -56,24 +58,20 @@ void drawCharacter(char character, int posX, int posY, u32 color)
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) if ((charPos >> x) & 1)
{ {
int screenPos = (posX * SCREEN_TOP_HEIGHT * 3 + (SCREEN_TOP_HEIGHT - y - posY - 1) * 3) + (7 - x) * 3 * SCREEN_TOP_HEIGHT;
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')
{ {
@@ -85,8 +83,8 @@ int drawString(const char *string, int posX, int posY, u32 color)
{ {
// 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);

View File

@@ -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);

View File

@@ -8,9 +8,9 @@
#include "memory.h" #include "memory.h"
#include "fatfs/sdmmc/sdmmc.h" #include "fatfs/sdmmc/sdmmc.h"
u32 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;
const u32 nandSize = getMMCDevice(0)->total_size; const u32 nandSize = getMMCDevice(0)->total_size;
u32 nandOffset = *emuNAND == 1 ? 0 : u32 nandOffset = *emuNAND == 1 ? 0 :
@@ -40,13 +40,9 @@ u32 getEmunandSect(u32 *off, u32 *head, u32 *emuNAND)
{ {
(*emuNAND)--; (*emuNAND)--;
if(*emuNAND) getEmunandSect(off, head, emuNAND); if(*emuNAND) getEmunandSect(off, head, emuNAND);
return 0;
} }
} }
} }
return 1;
} }
u32 getSDMMC(u8 *pos, u32 size) u32 getSDMMC(u8 *pos, u32 size)

View File

@@ -10,7 +10,7 @@
#define NCSD_MAGIC (0x4453434E) #define NCSD_MAGIC (0x4453434E)
u32 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);

View File

@@ -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

File diff suppressed because it is too large Load Diff

6
source/fatfs/ff.h Normal file → Executable file
View 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
View 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
View 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
View 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;
}

View File

@@ -2,3 +2,4 @@
#include <stdbool.h> #include <stdbool.h>
#include "../../types.h" #include "../../types.h"
#include "../../crypto.h"

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -5,306 +5,286 @@
*/ */
#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 4
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",
"/aurei/patched_firmware_twl.bin",
"/aurei/patched_firmware_agb.bin" };
static u32 firmSize, u32 config,
console, console,
mode, firmSource,
emuNAND, emuOffset;
a9lhSetup,
selectedFirm,
usePatchedFirm,
emuOffset,
emuHeader;
u32 config;
void setupCFW(void) void main(void)
{ {
//Determine if booting with A9LH u32 bootType,
u32 a9lhBoot = !PDN_SPI_CNT ? 1 : 0; firmType,
nandType,
//Retrieve the last booted FIRM a9lhInstalled,
u32 previousFirm = CFG_BOOTENV; updatedSys,
needConfig,
newConfig,
emuHeader;
//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 //Mount filesystems. CTRNAND will be mounted only if/when needed
u32 pressed = HID_PAD; 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 needConfig; if(fileRead(&config, configPath, 4)) needConfig = 1;
if(fileRead(&config, configPath, 3)) needConfig = 1;
else else
{ {
config = 0; config = 0;
needConfig = 2; needConfig = 2;
} }
//Determine if A9LH is installed and the user has an updated sysNAND //Determine if this is a firmlaunch boot
u32 updatedSys; if(*(vu8 *)0x23F00005)
if(a9lhBoot || (config >> 2) & 1)
{ {
if(pressed == SAFE_MODE) if(needConfig == 2) mcuReboot();
error("Using Safe Mode would brick you, or remove A9LH!");
a9lhSetup = 1; bootType = 1;
//Check setting for > 9.2 sysNAND //'0' = NATIVE_FIRM, '1' = TWL_FIRM, '2' = AGB_FIRM
updatedSys = config & 1; firmType = *(vu8 *)0x23F00005 - '0';
nandType = BOOTCONFIG(0, 3);
firmSource = BOOTCONFIG(2, 1);
a9lhInstalled = BOOTCONFIG(3, 1);
updatedSys = (a9lhInstalled && CONFIG(1)) ? 1 : 0;
} }
else else
{ {
a9lhSetup = 0; bootType = 0;
updatedSys = 0; firmType = 0;
}
u32 tempConfig = (PATCH_VER << 17) | (a9lhSetup << 16); //Determine if booting with A9LH
u32 a9lhBoot = !PDN_SPI_CNT ? 1 : 0;
/* If booting with A9LH, it's a MCU reboot and a previous configuration exists, //Retrieve the last booted FIRM
try to force boot options */ u32 previousFirm = CFG_BOOTENV;
if(a9lhBoot && previousFirm && needConfig == 1)
{ //Get pressed buttons
//Always force a sysNAND boot when quitting AGB_FIRM u32 pressed = HID_PAD;
if(previousFirm == 7)
//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))
{ {
mode = updatedSys ? 1 : (config >> 12) & 1; if(pressed == SAFE_MODE)
emuNAND = 0; error("Using Safe Mode would brick you, or remove A9LH!");
needConfig = 0;
//Flag to prevent multiple boot options-forcing a9lhInstalled = 1;
tempConfig |= 1 << 15;
//Check setting for > 9.2 sysNAND
updatedSys = CONFIG(1);
} }
/* Else, force the last used boot options unless a payload button or A/L/R are pressed else
or the no-forcing flag is set */
else if(!(pressed & OVERRIDE_BUTTONS) && !((config >> 15) & 1))
{ {
mode = (config >> 12) & 1; a9lhInstalled = 0;
emuNAND = (config >> 13) & 3; updatedSys = 0;
needConfig = 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);
} }
} }
//Boot options aren't being forced //If we need to boot emuNAND, make sure it exists
if(needConfig) if(nandType)
{ {
/* If L and R/Select or one of the single payload buttons are pressed and, if not using A9LH, getEmunandSect(&emuOffset, &emuHeader, &nandType);
the Safe Mode combo is not pressed, chainload an external payload */ if(!nandType) firmSource = 0;
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 //Same if we're using emuNAND as the FIRM source
if(needConfig == 2 || (pressed & BUTTON_SELECT)) else if(firmSource)
configureCFW(configPath, patchedFirms); getEmunandSect(&emuOffset, &emuHeader, &firmSource);
//If screens are inited, load splash screen if(!bootType)
if(PDN_GPU_CNT != 1) loadSplash(); {
newConfig |= nandType | (firmSource << 2);
/* If L is pressed, or L or R are not pressed when it is the default FIRM, /* If the boot configuration is different from previously, overwrite it.
boot 9.0 FIRM */ Just the no-forcing flag being set is not enough */
mode = ((config >> 3) & 1) ? ((!(pressed & BUTTON_L1R1)) ? 0 : 1) : if((newConfig & 0x2F) != (config & 0x3F))
((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 the second emuNAND is set as default and B isn't pressed, or vice-versa, //Preserve user settings (last 26 bits)
attempt to boot it */ newConfig |= config & 0xFFFFFFC0;
emuNAND = (mode && ((!(pressed & BUTTON_B)) == ((config >> 4) & 1))) ? 2 : 1;
fileWrite(&newConfig, configPath, 4);
} }
else emuNAND = 0;
/* 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 *));
} }
u32 usePatchedFirmSet = ((config >> 1) & 1); loadFirm(firmType, !firmType && (nandType == 2 || updatedSys == !firmSource));
while(1) if(!firmType) patchNativeFirm(nandType, emuHeader, a9lhInstalled);
{ else patchTwlAgbFirm(firmType);
/* Determine which patched FIRM we need to write or attempt to use (if any).
Patched 9.0 FIRM is only needed if "Use pre-patched FIRMs" is set */
selectedFirm = mode ? (emuNAND ? (emuNAND == 1 ? 2 : 3) : 1) :
(usePatchedFirmSet ? 4 : 0);
//If "Use pre-patched FIRMs" is set and the appropriate FIRM exists, use it launchFirm(bootType);
if(usePatchedFirmSet && fileExists(patchedFirms[selectedFirm - 1]))
usePatchedFirm = 1;
/* If the user is booting EmuNAND but the chosen one is not found,
force 9.6/10.x FIRM and re-detect the patched FIRMs */
else if(emuNAND && !getEmunandSect(&emuOffset, &emuHeader, &emuNAND))
{
mode = 1;
continue;
}
break;
}
tempConfig |= (emuNAND << 13) | (mode << 12);
//If the boot configuration is different from previously, overwrite it
if(tempConfig != (config & 0xFFF000))
{
//Preserve user settings (first 12 bits)
tempConfig |= config & 0xFFF;
fileWrite(&tempConfig, configPath, 3);
}
} }
//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(mode ? "aurei/firmware.bin doesn't exist" :
"aurei/firmware90.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(mode ? "aurei/firmware.bin doesn't match this console,\nor it's encrypted" :
"aurei/firmware90.bin doesn't match this console,\nor it's encrypted");
arm9Section = (u8 *)firm + section[2].offset; if(externalFirm)
//On N3DS, decrypt ARM9Bin and patch ARM9 entrypoint to skip arm9loader
if(console && !usePatchedFirm)
{ {
decryptArm9Bin(arm9Section, mode); const char path[] = "/aurei/firmware.bin";
firm->arm9Entry = (u8 *)0x801B01C; firmSize = fileSize(path);
}
}
static inline void patchTwlAgb(u32 whichFirm) if(firmSize)
{
static firmHeader *const twlAgbFirm = (firmHeader *)0x25000000;
const char *path = whichFirm ? "/aurei/firmware_agb.bin" : "/aurei/firmware_twl.bin";
u32 size = fileSize(path);
//Skip patching if the file doesn't exist
if(!size) return;
fileRead(twlAgbFirm, path, size);
static const firmSectionHeader *twlAgbSection = twlAgbFirm->section;
//Check that the loaded FIRM matches the console
if((((u32)twlAgbSection[3].address >> 8) & 0xFF) != (console ? 0x60 : 0x68))
error(whichFirm ? "aurei/firmware_agb.bin doesn't match this\nconsole, or it's encrypted" :
"aurei/firmware_twl.bin doesn't match this\nconsole, or it's encrypted");
//On N3DS, decrypt ARM9Bin and patch ARM9 entrypoint to skip arm9loader
if(console)
{
decryptArm9Bin((u8 *)twlAgbFirm + twlAgbSection[3].offset, 0);
twlAgbFirm->arm9Entry = (u8 *)0x801301C;
}
struct patchData {
u32 offset[2];
union {
u8 type0[8];
u16 type1;
} patch;
u32 type;
};
static const struct 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}
};
static const struct patchData 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 = whichFirm ? (sizeof(agbPatches) / sizeof(struct patchData)) - !((config >> 6) & 1) :
(sizeof(twlPatches) / sizeof(struct patchData));
const struct patchData *patches = whichFirm ? agbPatches : twlPatches;
//Patch
for(u32 i = 0; i < numPatches; i++)
{
switch(patches[i].type)
{ {
case 0: fileRead(firm, path, firmSize);
memcpy((u8 *)twlAgbFirm + patches[i].offset[console], patches[i].patch.type0 + 1, patches[i].patch.type0[0]);
break; //Check that the loaded FIRM matches the console
case 2: if((((u32)section[2].address >> 8) & 0xFF) != (console ? 0x60 : 0x68)) firmSize = 0;
*(u16 *)((u8 *)twlAgbFirm + patches[i].offset[console] + 2) = 0;
case 1:
*(u16 *)((u8 *)twlAgbFirm + patches[i].offset[console]) = patches[i].patch.type1;
break;
} }
} }
else firmSize = 0;
fileWrite(twlAgbFirm, whichFirm ? patchedFirms[5] : patchedFirms[4], size); 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 inline void patchEmuNAND(u8 *proc9Offset) {
u8 *arm9Section = (u8 *)firm + section[2].offset;
u32 nativeFirmType;
if(console)
{
//Determine if we're booting the 9.0 FIRM
nativeFirmType = (arm9Section[0x51] == 0xFF) ? 0 : 1;
//Decrypt ARM9Bin and patch ARM9 entrypoint to skip arm9loader
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);
@@ -324,7 +304,7 @@ static inline void patchEmuNAND(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, u32 emuRead,
emuWrite; emuWrite;
@@ -343,7 +323,7 @@ static inline void patchEmuNAND(u8 *proc9Offset)
*(mpuOffset + 9) = mpuPatch[2]; *(mpuOffset + 9) = mpuPatch[2];
} }
static inline void patchReboots(u8 *proc9Offset) static inline void patchReboots(u8 *arm9Section, u8 *proc9Offset)
{ {
//Calculate offset for the firmlaunch code //Calculate offset for the firmlaunch code
void *rebootOffset = getReboot(arm9Section, section[2].size); void *rebootOffset = getReboot(arm9Section, section[2].size);
@@ -357,27 +337,18 @@ static inline void patchReboots(u8 *proc9Offset)
//Put the fOpen offset in the right location //Put the fOpen offset in the right location
u32 *pos_fopen = (u32 *)memsearch(rebootOffset, "OPEN", reboot_size, 4); u32 *pos_fopen = (u32 *)memsearch(rebootOffset, "OPEN", reboot_size, 4);
*pos_fopen = fOpenOffset; *pos_fopen = fOpenOffset;
//Patch path for emuNAND-patched FIRM
if(emuNAND)
{
void *pos_path = memsearch(rebootOffset, L"sy", reboot_size, 4);
memcpy(pos_path, emuNAND == 1 ? L"emu" : L"em2", 5);
}
} }
static inline void injectLoader(void) static inline void injectLoader(void)
{ {
u32 loaderOffset, u32 loaderSize;
loaderSize;
getLoader((u8 *)firm + section[0].offset, section[0].size, &loaderOffset, &loaderSize); void *loaderOffset = getLoader((u8 *)firm + section[0].offset, section[0].size, &loaderSize);
//Check that the injector CXI isn't larger than the original //Check that the injector CXI isn't larger than the original
if(injector_size <= (int)loaderSize) if((u32)injector_size <= loaderSize)
{ {
memset((void *)loaderOffset, 0, loaderSize); memcpy(loaderOffset, injector, injector_size);
memcpy((void *)loaderOffset, injector, injector_size);
//Patch content size and ExeFS size to match the repaced loader's ones //Patch content size and ExeFS size to match the repaced loader's ones
*((u32 *)loaderOffset + 0x41) = loaderSize / 0x200; *((u32 *)loaderOffset + 0x41) = loaderSize / 0x200;
@@ -385,71 +356,70 @@ static inline void injectLoader(void)
} }
} }
//Patches static inline void patchTwlAgbFirm(u32 firmType)
void patchFirm(void)
{ {
if(mode) //On N3DS, decrypt ARM9Bin and patch ARM9 entrypoint to skip arm9loader
if(console)
{ {
//Only patch AGB_FIRM/TWL_FIRM if the patched ones don't already exist arm9Loader((u8 *)firm + section[3].offset, 0);
if(!fileExists(patchedFirms[4])) patchTwlAgb(0); firm->arm9Entry = (u8 *)0x801301C;
if(!fileExists(patchedFirms[5])) patchTwlAgb(1);
} }
//Skip patching const patchData twlPatches[] = {
if(usePatchedFirm) return; {{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}
};
if(mode || emuNAND) /* 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++)
{ {
//Find the Process9 NCCH location switch(patches[i].type)
u8 *proc9Offset = getProc9(arm9Section, section[2].size); {
case 0:
//Apply emuNAND patches memcpy((u8 *)firm + patches[i].offset[console], patches[i].patch.type0 + 1, patches[i].patch.type0[0]);
if(emuNAND) patchEmuNAND(proc9Offset); break;
case 2:
//Apply FIRM reboot patches, not on 9.0 FIRM as it breaks firmlaunchhax *(u16 *)((u8 *)firm + patches[i].offset[console] + 2) = 0;
if(mode) patchReboots(proc9Offset); case 1:
*(u16 *)((u8 *)firm + patches[i].offset[console]) = patches[i].patch.type1;
break;
}
} }
//Apply FIRM0/1 writes patches on sysNAND to protect A9LH
if(a9lhSetup && !emuNAND)
{
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];
//Replace the FIRM loader with the injector
injectLoader();
//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 launchFirm(u32 bootType)
{ {
if(console && mode) setKeyXs(arm9Section);
//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)();

View File

@@ -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);

View File

@@ -5,13 +5,17 @@
*/ */
#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 mountSD(void) u32 mountFs(void)
{ {
if(f_mount(&fs, "0:", 1) != FR_OK) return 0; if(f_mount(&sdFs, "0:", 1) != FR_OK) return 0;
f_mount(&nandFs, "1:", 0);
return 1; return 1;
} }
@@ -29,6 +33,7 @@ u32 fileRead(void *dest, const char *path, u32 size)
} }
f_close(&fp); f_close(&fp);
return fr ? 0 : 1; return fr ? 0 : 1;
} }
@@ -42,6 +47,7 @@ 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;
} }
@@ -54,21 +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; DIR dir;
u32 exists = 0; 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);
} }

View File

@@ -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);

View File

@@ -14,7 +14,7 @@
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);

View File

@@ -1,19 +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();
}

View File

@@ -17,14 +17,6 @@ void memcpy(void *dest, const void *src, u32 size)
destc[i] = srcc[i]; destc[i] = srcc[i];
} }
void memset(void *dest, int 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) void memset32(void *dest, u32 filler, u32 size)
{ {
u32 *dest32 = (u32 *)dest; u32 *dest32 = (u32 *)dest;

View File

@@ -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);

View File

@@ -19,6 +19,8 @@ const u16 sigPatch[2] = {0x2000, 0x4770};
const u16 writeBlock[2] = {0x2000, 0x46C0}; const u16 writeBlock[2] = {0x2000, 0x46C0};
const u8 unitInfoPatch = 0xE3;
/************************************************** /**************************************************
* Functions * Functions
**************************************************/ **************************************************/
@@ -67,10 +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;
} }

View File

@@ -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);

View File

@@ -8,6 +8,7 @@
*/ */
#include "screeninit.h" #include "screeninit.h"
#include "config.h"
#include "memory.h" #include "memory.h"
#include "draw.h" #include "draw.h"
#include "i2c.h" #include "i2c.h"
@@ -15,7 +16,7 @@
#define SCREENINIT_ADDRESS 0x24F03000 #define SCREENINIT_ADDRESS 0x24F03000
static vu32 *const arm11 = (u32 *)0x1FFFFFF8; vu32 *arm11Entry = (u32 *)0x1FFFFFF8;
void deinitScreens(void) void deinitScreens(void)
{ {
@@ -25,7 +26,7 @@ void deinitScreens(void)
__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;
@@ -33,16 +34,16 @@ 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 != 1) if(PDN_GPU_CNT != 1)
{ {
*arm11 = (u32)ARM11; *arm11Entry = (u32)ARM11;
while(*arm11); while(*arm11Entry);
} }
} }
@@ -50,13 +51,13 @@ void initScreens(void)
{ {
if(PDN_GPU_CNT == 1) if(PDN_GPU_CNT == 1)
{ {
//Write brightness level for the stub to pick up
*(vu32 *)0x24F04000 = (config >> 10) & 3;
memcpy((void *)SCREENINIT_ADDRESS, screeninit, screeninit_size); memcpy((void *)SCREENINIT_ADDRESS, screeninit, screeninit_size);
*arm11 = SCREENINIT_ADDRESS; //Write brightness level for the stub to pick up
while(*arm11); *(vu32 *)(SCREENINIT_ADDRESS + 8) = MULTICONFIG(0);
*arm11Entry = SCREENINIT_ADDRESS;
while(*arm11Entry);
//Turn on backlight //Turn on backlight
i2cWriteRegister(I2C_DEV_MCU, 0x22, 0x2A); i2cWriteRegister(I2C_DEV_MCU, 0x22, 0x2A);

View File

@@ -13,7 +13,5 @@
#define PDN_GPU_CNT (*(vu8 *)0x10141200) #define PDN_GPU_CNT (*(vu8 *)0x10141200)
u32 config;
void deinitScreens(void); void deinitScreens(void);
void initScreens(void); void initScreens(void);

View File

@@ -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

View File

@@ -7,29 +7,19 @@
#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
#define COLOR_BLACK 0x000000
struct option {
int posY;
u32 enabled;
};
static u32 waitInput(void)
{ {
u32 pressedKey = 0; u32 pressedKey = 0,
u32 key; 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);
@@ -47,112 +37,16 @@ static u32 waitInput(void)
return key; return key;
} }
void configureCFW(const char *configPath, const char *patchedFirms[]) void mcuShutDown(void)
{ {
initScreens(); i2cWriteRegister(I2C_DEV_MCU, 0x20, 1);
drawString(CONFIG_TITLE, 10, 10, COLOR_TITLE);
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",
"( ) Show GBA boot screen in patched AGB_FIRM" };
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) & 1;
options[optionsAmount].enabled = (tempConfig >> 10) & 3;
//Pre-select the first configuration option
u32 selectedOption = 0;
//Boring configuration menu
while(1)
{
u16 pressed = 0;
do {
options[optionsAmount].posY = drawString("Screen-init brightness: 4( ) 3( ) 2( ) 1( )", 10, 53, selectedOption == optionsAmount ? COLOR_RED : COLOR_WHITE);
for(u32 i = 0; i < optionsAmount; i++)
{
options[i].posY = drawString(optionsText[i], 10, !i ? options[optionsAmount].posY + 2 * SPACING_Y : 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);
}
for(u32 i = 0; i < 4; i++)
drawCharacter('x', 10 + (26 + 5 * i) * SPACING_X, options[optionsAmount].posY, options[optionsAmount].enabled == i ? (selectedOption == optionsAmount ? COLOR_RED : COLOR_WHITE) : COLOR_BLACK);
pressed = waitInput();
}
while(!(pressed & MENU_BUTTONS));
switch(pressed)
{
case BUTTON_UP:
selectedOption = !selectedOption ? optionsAmount : 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:
if(selectedOption != optionsAmount) options[selectedOption].enabled = !options[selectedOption].enabled;
else options[optionsAmount].enabled = options[optionsAmount].enabled == 3 ? 0 : options[optionsAmount].enabled + 1;
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) & 1) && ((tempConfig & 1) != options[0].enabled)) fileDelete(patchedFirms[3]);
//If the "Show GBA boot screen in patched AGB_FIRM" setting changed, delete the patched AGB_FIRM
if(((tempConfig >> 6) & 1) != options[6].enabled) fileDelete(patchedFirms[5]);
//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;
tempConfig |= options[optionsAmount].enabled << 10;
fileWrite(&tempConfig, configPath, 3);
//Zero the last booted FIRM flag
CFG_BOOTENV = 0;
//Reboot
i2cWriteRegister(I2C_DEV_MCU, 0x20, 1 << 2);
while(1); while(1);
} }
void deleteFirms(const char *firmPaths[], u32 firms) void mcuReboot(void)
{ {
while(firms) i2cWriteRegister(I2C_DEV_MCU, 0x20, 1 << 2);
{ while(1);
fileDelete(firmPaths[firms - 1]);
firms--;
}
} }
void error(const char *message) void error(const char *message)
@@ -165,7 +59,5 @@ void error(const char *message)
waitInput(); waitInput();
//Shutdown mcuShutDown();
i2cWriteRegister(I2C_DEV_MCU, 0x20, 1);
while(1);
} }

View File

@@ -8,8 +8,7 @@
#include "types.h" #include "types.h"
#define CFG_BOOTENV (*(vu32 *)0x10010000) u32 waitInput(void);
void mcuShutDown(void);
void configureCFW(const char *configPath, const char *patchedFirms[]); void mcuReboot(void);
void deleteFirms(const char *firmPaths[], u32 firms);
void error(const char *message); void error(const char *message);