Compare commits

...

95 Commits
v4.0 ... v5.3.1

Author SHA1 Message Date
Aurora
5a9d0e2569 Fail 2016-04-27 16:16:25 +02:00
Aurora
041ca8451e Use the older cxi, should fix NANDs with incomplete background updates 2016-04-27 15:37:13 +02:00
Aurora
2382e6d82c Fixed oversight in the injector 2016-04-27 04:52:23 +02:00
Aurora
f9a1f1a79b Move the UNITINFO patch to the developer version 2016-04-26 21:51:57 +02:00
Aurora
a736e4602a Cleanup 2016-04-26 20:10:20 +02:00
Aurora
5202ba8826 Update ReadME 2016-04-26 14:33:01 +02:00
Aurora
0f1bc98bb7 Rename "Use SysNAND FIRM as default" to "SysNAND is updated" 2016-04-26 14:11:34 +02:00
Aurora
d40722af53 Apply the eShop update skipping patch only if the updated NAND was not booted (depends on the "Use SysNAND FIRM as default" option) 2016-04-26 14:05:48 +02:00
Aurora
c9781ab626 Added python implementation of the path changer from @TuxSH 2016-04-26 03:39:36 +02:00
Aurora
4cbf4e93e7 Minor stuff 2016-04-26 01:30:03 +02:00
Aurora
1f68c2da42 Update ReadME 2016-04-24 20:19:35 +02:00
Aurora
d786c292f3 Update submodules 2016-04-24 19:49:09 +02:00
Aurora
ada3e09784 Added L+A payload 2016-04-24 19:46:33 +02:00
Aurora
c928b3b68b New icon 2016-04-23 15:39:40 +02:00
Aurora
ae9c29629c Wrong name in the Makefile 2016-04-23 03:50:04 +02:00
Aurora
3fd4603553 Welcome Luma3DS 2016-04-23 01:43:36 +02:00
Aurora
c14526068a Minor stuff 2016-04-21 23:39:05 +02:00
Aurora
180b2a6f4d Bye bye fileSize! 2016-04-21 05:08:42 +02:00
Aurora
b926ab7dd2 Give 3ds_injector a sane makefile 2016-04-20 03:31:40 +02:00
Aurora
19d8861d27 Give 3ds_injector a sane makefile 2016-04-19 20:51:00 +02:00
Aurora
70e82e627b More cleanup 2016-04-19 17:28:18 +02:00
Aurora
67e229e5a9 Cleanup of the injector 2016-04-18 23:14:35 +02:00
Aurora
d0d6baaa85 We do not need this anymore (D9/E9/GM9 were updated) 2016-04-18 18:52:58 +02:00
Aurora
fd4352a1d6 Remove useless sdmmc code (we do not need NAND init/read from loader, or write at all 2016-04-18 18:29:37 +02:00
Aurora
08808da741 Update FatFs to 0.12 2016-04-18 18:04:04 +02:00
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
Aurora
3aacbd17ce Upped patch version 2016-04-05 02:29:36 +02:00
Aurora
6f8a9421ef Added basic support for configuring the brightness level for the built-in screen init 2016-04-05 02:24:21 +02:00
Aurora
bb437f6f7b Better commenting 2016-04-04 19:14:49 +02:00
Aurora
0001f301f8 Cleanup, fixed the second emuNAND patched FIRM still getting created, removed injector SOAP patch as it changes nothing without going to great lengths to change the region of a NNID, made L not needed to load payloads except for R and Select (Start is now default) 2016-04-04 18:07:13 +02:00
Aurora
f7bbc4bfec Made the AGB_FIRM splash screen optional
Apparently it causes compatibility issues
2016-04-04 01:08:42 +02:00
Aurora
a127a38438 Updated ReadME 2016-04-03 19:53:03 +02:00
Aurora
16225b97d7 Small changes 2016-04-03 18:18:44 +02:00
Aurora
0587c14162 Forgot stuff 2016-04-03 18:10:48 +02:00
Aurora
a181bba9f2 Added TWL/AGB FIRM patching/SD loading for New and Old 3DS (thanks to mid-kid of CakesFW for making it possible!) 2016-04-03 17:56:09 +02:00
Aurora
993e564fbb u32-ify 2016-04-02 22:02:16 +02:00
Aurora
956829864c This looks unused (my AUS N3DS has 2) 2016-04-02 18:57:52 +02:00
Aurora
24186a7148 Some more tidying up 2016-04-02 18:48:31 +02:00
Aurora
3475cfe1e6 Changed indentation style across the code to make it more readable, added newlines before comments, moved patches to separate functions, made memory operations slightly faster by compiling them with O3 (thanks TuxSH!) 2016-04-02 18:22:47 +02:00
Aurora
6b64a10362 Fixed ARM11 access to chainloaded payloads 2016-04-01 14:27:31 +02:00
Aurora
5e99fb3aa0 Fixed dumb mistakes 2016-03-31 18:25:50 +02:00
Aurora
060d8e9945 Comment things better 2016-03-31 16:04:12 +02:00
Aurora
1026471842 Leftover from testing 2016-03-31 15:59:40 +02:00
Aurora
645208ec82 EmuNAND is detected almost instantly when the CFW configures itself, if the user is attempting to load an EmuNAND and none is found, SysNAND and 9.6/10.x FIRM are forced. Also prevents the second EmuNAND patched FIRM from being created if no second EmuNAND exists. 2016-03-31 15:57:02 +02:00
Aurora
f4c48a64ca Fixed loading the alternate EmuNAND if 9.0 FIRM was set as default, improved comments and further cleanup of the injector 2016-03-31 01:38:28 +02:00
Aurora
c80ac985fe Further clean-up of the patcher code 2016-03-29 22:43:15 +02:00
Aurora
ac9bdc7665 Fixed exiting GBA games with updated SysNAND 2016-03-29 18:56:51 +02:00
Aurora
217d75024d These should be u32s 2016-03-29 18:47:30 +02:00
Aurora
12e5b4adb9 Updated readME 2016-03-29 18:17:22 +02:00
75 changed files with 16035 additions and 12761 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

Submodule CakeHax updated: 6b8fca0b37...5245c7b9dc

View File

@@ -1,31 +1,39 @@
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
OC := arm-none-eabi-objcopy OC := arm-none-eabi-objcopy
name := AuReiNand name := Luma3DS
version := $(shell git describe --abbrev=0 --tags) version := $(shell git describe --abbrev=0 --tags)
dir_source := source dir_source := source
dir_patches := patches dir_patches := patches
dir_loader := loader dir_loader := loader
dir_screeninit := screeninit
dir_injector := injector dir_injector := injector
dir_mset := CakeHax dir_mset := CakeHax
dir_ninjhax := CakeBrah dir_ninjhax := CakeBrah
dir_build := build dir_build := build
dir_out := out dir_out := out
ASFLAGS := -mlittle-endian -mcpu=arm946e-s -march=armv5te ASFLAGS := -mcpu=arm946e-s
CFLAGS := -Wall -Wextra -MMD -MP -marm $(ASFLAGS) -fno-builtin -fshort-wchar -std=c11 -Wno-main -O2 -ffast-math CFLAGS := -Wall -Wextra -MMD -MP -marm $(ASFLAGS) -fno-builtin -fshort-wchar -std=c11 -Wno-main -O2 -flto -ffast-math
CFLAGS += -DCONFIG_TITLE="\"$(name) $(version) configuration\"" LDFLAGS := -nostartfiles
FLAGS := name=$(name).dat dir_out=$(abspath $(dir_out)) ICON=$(abspath icon.png) APP_DESCRIPTION="Noob-friendly 3DS CFW." APP_AUTHOR="Reisyukaku/Aurora Wright" --no-print-directory FLAGS := name=$(name).dat dir_out=$(abspath $(dir_out)) ICON=$(abspath icon.png) APP_DESCRIPTION="Noob-friendly 3DS CFW." APP_AUTHOR="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
@@ -40,56 +48,63 @@ a9lh: $(dir_out)/arm9loaderhax.bin
ninjhax: $(dir_out)/3ds/$(name) ninjhax: $(dir_out)/3ds/$(name)
.PHONY: release .PHONY: release
release: $(dir_out)/$(name).zip release: $(dir_out)/$(name)$(version).7z
.PHONY: clean .PHONY: clean
clean: clean:
@$(MAKE) $(FLAGS) -C $(dir_mset) clean @$(MAKE) $(FLAGS) -C $(dir_mset) clean
@$(MAKE) $(FLAGS) -C $(dir_ninjhax) clean @$(MAKE) $(FLAGS) -C $(dir_ninjhax) clean
@rm -rf $(dir_out) $(dir_build)
@$(MAKE) -C $(dir_loader) clean @$(MAKE) -C $(dir_loader) clean
@$(MAKE) -C $(dir_screeninit) clean
@$(MAKE) -C $(dir_injector) clean @$(MAKE) -C $(dir_injector) clean
@rm -rf $(dir_out) $(dir_build)
$(dir_out): $(dir_out):
@mkdir -p "$(dir_out)/aurei/payloads" @mkdir -p "$(dir_out)/luma/payloads"
$(dir_out)/$(name).dat: $(dir_build)/main.bin $(dir_out) $(dir_out)/$(name).dat: $(dir_build)/main.bin $(dir_out)
@$(MAKE) $(FLAGS) -C $(dir_mset) launcher @$(MAKE) $(FLAGS) -C $(dir_mset) launcher
@dd if=$(dir_build)/main.bin of=$@ bs=512 seek=144 @dd if=$(dir_build)/main.bin of=$@ bs=512 seek=144
$(dir_out)/arm9loaderhax.bin: $(dir_build)/main.bin $(dir_out) $(dir_out)/arm9loaderhax.bin: $(dir_build)/main.bin $(dir_out)
@cp -av $(dir_build)/main.bin $@ @cp -a $(dir_build)/main.bin $@
$(dir_out)/3ds/$(name): $(dir_out) $(dir_out)/3ds/$(name): $(dir_out)
@mkdir -p "$(dir_out)/3ds/$(name)" @mkdir -p "$@"
@$(MAKE) $(FLAGS) -C $(dir_ninjhax) @$(MAKE) $(FLAGS) -C $(dir_ninjhax)
@mv $(dir_out)/$(name).3dsx $@ @mv $(dir_out)/$(name).3dsx $(dir_out)/$(name).smdh $@
@mv $(dir_out)/$(name).smdh $@
$(dir_out)/$(name).zip: launcher a9lh ninjhax $(dir_out)/$(name)$(version).7z: launcher a9lh ninjhax
@cd $(dir_out) && zip -9 -r $(name) * @7z a -mx $@ ./$(@D)/*
$(dir_build)/patches.h: $(dir_patches)/emunand.s $(dir_patches)/reboot.s $(dir_injector)/Makefile
@mkdir -p "$(dir_build)"
@armips $<
@armips $(word 2,$^)
@$(MAKE) -C $(dir_injector)
@mv emunand.bin reboot.bin $(dir_injector)/injector.cxi $(dir_build)
@bin2c -o $@ -n emunand $(dir_build)/emunand.bin -n reboot $(dir_build)/reboot.bin -n injector $(dir_build)/injector.cxi
$(dir_build)/loader.h: $(dir_loader)/Makefile
@$(MAKE) -C $(dir_loader)
@mv $(dir_loader)/loader.bin $(dir_build)
@bin2c -o $@ -n loader $(dir_build)/loader.bin
$(dir_build)/main.bin: $(dir_build)/main.elf $(dir_build)/main.bin: $(dir_build)/main.elf
$(OC) -S -O binary $< $@ $(OC) -S -O binary $< $@
$(dir_build)/main.elf: $(objects_cfw) $(dir_build)/main.elf: $(objects)
# FatFs requires libgcc for __aeabi_uidiv $(LINK.o) -T linker.ld $(OUTPUT_OPTION) $^
$(CC) -nostartfiles $(LDFLAGS) -T linker.ld $(OUTPUT_OPTION) $^
$(dir_build)/%.o: $(dir_source)/%.c $(dir_build)/patches.h $(dir_build)/loader.h $(dir_build)/patches.h: $(dir_patches)/emunand.s $(dir_patches)/reboot.s $(dir_injector)/Makefile
@mkdir -p "$(@D)"
@armips $<
@armips $(word 2,$^)
@$(MAKE) -C $(dir_injector)
@mv emunand.bin reboot.bin $(dir_injector)/injector.cxi $(@D)
@bin2c -o $@ -n emunand $(@D)/emunand.bin -n reboot $(@D)/reboot.bin -n injector $(@D)/injector.cxi
$(dir_build)/loader.h: $(dir_loader)/Makefile
@$(MAKE) -C $(dir_loader)
@mv $(dir_loader)/loader.bin $(@D)
@bin2c -o $@ -n loader $(@D)/loader.bin
$(dir_build)/screeninit.h: $(dir_screeninit)/Makefile
@$(MAKE) -C $(dir_screeninit)
@mv $(dir_screeninit)/screeninit.bin $(@D)
@bin2c -o $@ -n screeninit $(@D)/screeninit.bin
$(dir_build)/memory.o : CFLAGS += -O3
$(dir_build)/config.o : CFLAGS += -DCONFIG_TITLE="\"$(name) $(version) configuration\""
$(dir_build)/%.o: $(dir_source)/%.c $(bundled)
@mkdir -p "$(@D)" @mkdir -p "$(@D)"
$(COMPILE.c) $(OUTPUT_OPTION) $< $(COMPILE.c) $(OUTPUT_OPTION) $<
@@ -99,9 +114,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

@@ -1,32 +1,23 @@
# AuReiNand # Luma3DS
*A modification of the ReiNand custom firmware* *Noob-proof (N)3DS "Custom Firmware"*
**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. First you need to clone the repository recursively with: 'git clone --recursive https://github.com/AuroraWright/Luma3DS.git'
To compile, you'll need [armips](https://github.com/Kingcom/armips), [bin2c](https://sourceforge.net/projects/bin2c/), and a recent build of [makerom](https://github.com/profi200/Project_CTR) added to your PATH.
For your convenience, here are [Windows](http://www91.zippyshare.com/v/ePGpjk9r/file.html) and [Linux](https://mega.nz/#!uQ1T1IAD!Q91O0e12LXKiaXh_YjXD3D5m8_W3FuMI-hEa6KVMRDQ) builds of armips (thanks to who compiled them!).
Finally just run 'make' and everything should work!
You can find the compiled files in the 'out' folder.
Lastly, just run Make and everything should work! **Setup / Usage / Features:**
Copy everything in 'out' folder to SD root and run! See https://github.com/AuroraWright/Luma3DS/wiki
**Usage / Features:**
See https://github.com/Reisyukaku/ReiNand and http://gbatemp.net/threads/reinand-mod-o3ds-n3ds-sysnand.411110
The FIRMs you need are [HERE](http://www99.zippyshare.com/v/kEIiQl0x/file.html).
**Credits:** **Credits:**
Rei as this is mostly his code. See https://github.com/AuroraWright/Luma3DS/wiki/Credits
The offset to detect the console, and to calculate the O3DS NAND CTR are from Decrypt9. **Licensing:**
tiniVi suggested me a way to detect a A9LH environment, and figured out screen deinit. This software is licensed under the terms of the GPLv3.
You can find a copy of the license in the LICENSE.txt file.
Delebile provided me with the FIRM writes blocking patch.
A skilled reverser gave me the new reboot patch.
The screen init code is from dark_samus, bil1s, Normmatt, delebile and everyone who contributed.
The code for printing to the screen is from CakesFW.

BIN
icon.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

170
injector/Makefile Normal file → Executable file
View File

@@ -1,161 +1,51 @@
#--------------------------------------------------------------------------------- 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")
endif endif
TOPDIR ?= $(CURDIR)
MAKEROM ?= makerom
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
#---------------------------------------------------------------------------------
TARGET := $(notdir $(CURDIR))
BUILD := build
SOURCES := source
DATA := data
INCLUDES := include
#--------------------------------------------------------------------------------- name := $(shell basename $(CURDIR))
# options for code generation
#---------------------------------------------------------------------------------
ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard -mtp=soft
CFLAGS := -flto -Wall -O2 -mword-relocations \ dir_source := source
-ffast-math -ffunction-sections -fdata-sections \ dir_build := build
$(ARCH)
CFLAGS += $(INCLUDE) -DARM11 -D_3DS LIBS := -lctru
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu99
ASFLAGS := $(ARCH)
LDFLAGS = -flto -Xlinker --defsym="__start__=0x14000000" -specs=3dsx.specs $(ARCH) -Wl,-Map,$(notdir $*.map)
LIBS := -lctru
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS := $(CTRULIB) LIBDIRS := $(CTRULIB)
LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
INCLUDE := $(foreach dir,$(LIBDIRS),-I$(dir)/include)
#--------------------------------------------------------------------------------- ARCH := -mcpu=mpcore -mfloat-abi=hard -mtp=soft
# no real need to edit anything past this point unless you need to add additional CFLAGS := -Wall -Wextra -MMD -MP -marm $(ARCH) -fno-builtin -std=c11 -O2 -flto -ffast-math -mword-relocations \
# rules for different file extensions -ffunction-sections -fdata-sections $(INCLUDE) -DARM11 -D_3DS
#--------------------------------------------------------------------------------- LDFLAGS := -Xlinker --defsym="__start__=0x14000000" -specs=3dsx.specs $(ARCH)
ifneq ($(BUILD),$(notdir $(CURDIR)))
#---------------------------------------------------------------------------------
export OUTPUT := $(CURDIR)/$(TARGET) objects = $(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \
export TOPDIR := $(CURDIR) $(call rwildcard, $(dir_source), *.c))
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ .PHONY: all
$(foreach dir,$(DATA),$(CURDIR)/$(dir)) all: $(name).cxi
export DEPSDIR := $(CURDIR)/$(BUILD) .PHONY: clean
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
PICAFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.v.pica)))
SHLISTFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.shlist)))
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C
#---------------------------------------------------------------------------------
ifeq ($(strip $(CPPFILES)),)
#---------------------------------------------------------------------------------
export LD := $(CC)
#---------------------------------------------------------------------------------
else
#---------------------------------------------------------------------------------
export LD := $(CXX)
#---------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------
export OFILES := $(addsuffix .o,$(BINFILES)) \
$(PICAFILES:.v.pica=.shbin.o) $(SHLISTFILES:.shlist=.shbin.o) \
$(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
-I$(CURDIR)/$(BUILD)
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
.PHONY: $(BUILD) clean all
#---------------------------------------------------------------------------------
all: $(BUILD)
$(BUILD):
@[ -d $@ ] || mkdir -p $@
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
#---------------------------------------------------------------------------------
clean: clean:
@echo clean ... @rm -rf $(dir_build)
@rm -fr $(BUILD) $(OUTPUT).cxi $(TARGET).elf
$(name).cxi: $(dir_build)/$(name).elf
@makerom -f ncch -rsf loader.rsf -nocodepadding -o $@ -elf $<
#--------------------------------------------------------------------------------- $(dir_build)/$(name).elf: $(objects)
else $(LINK.o) $(OUTPUT_OPTION) $^ $(LIBPATHS) $(LIBS)
DEPENDS := $(OFILES:.o=.d) $(dir_build)/memory.o : CFLAGS += -O3
#--------------------------------------------------------------------------------- $(dir_build)/%.o: $(dir_source)/%.c
# main targets @mkdir -p "$(@D)"
#--------------------------------------------------------------------------------- $(COMPILE.c) $(OUTPUT_OPTION) $<
$(OUTPUT).cxi : $(OUTPUT).elf include $(call rwildcard, $(dir_build), *.d)
$(MAKEROM) -f ncch -rsf ../loader.rsf -nocodepadding -o $@ -elf $<
$(OUTPUT).elf : $(OFILES)
#---------------------------------------------------------------------------------
# you need a rule like this for each extension you use as binary data
#---------------------------------------------------------------------------------
%.bin.o : %.bin
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@$(bin2o)
#---------------------------------------------------------------------------------
# rules for assembling GPU shaders
#---------------------------------------------------------------------------------
define shader-as
$(eval CURBIN := $(patsubst %.shbin.o,%.shbin,$(notdir $@)))
picasso -o $(CURBIN) $1
bin2s $(CURBIN) | $(AS) -o $@
echo "extern const u8" `(echo $(CURBIN) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"_end[];" > `(echo $(CURBIN) | tr . _)`.h
echo "extern const u8" `(echo $(CURBIN) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"[];" >> `(echo $(CURBIN) | tr . _)`.h
echo "extern const u32" `(echo $(CURBIN) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`_size";" >> `(echo $(CURBIN) | tr . _)`.h
endef
%.shbin.o : %.v.pica %.g.pica
@echo $(notdir $^)
@$(call shader-as,$^)
%.shbin.o : %.v.pica
@echo $(notdir $<)
@$(call shader-as,$<)
%.shbin.o : %.shlist
@echo $(notdir $<)
@$(call shader-as,$(foreach file,$(shell cat $<),$(dir $<)/$(file)))
-include $(DEPENDS)
#---------------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------------

View File

@@ -63,43 +63,4 @@ Result IFile_Read(IFile *file, u64 *total, void *buffer, u32 len)
*total = cur; *total = cur;
return res; return res;
} }
Result IFile_Write(IFile *file, u64 *total, void *buffer, u32 len, u32 flags)
{
u32 written;
u32 left;
char *buf;
u64 cur;
Result res;
if (len == 0)
{
*total = 0;
return 0;
}
buf = (char *)buffer;
cur = 0;
left = len;
while (1)
{
res = FSFILE_Write(file->handle, &written, file->pos, buf, left, flags);
if (R_FAILED(res))
{
break;
}
cur += written;
file->pos += written;
if (written == left)
{
break;
}
buf += written;
left -= written;
}
*total = cur;
return res;
}

View File

@@ -12,5 +12,4 @@ typedef struct
Result IFile_Open(IFile *file, FS_Archive archive, FS_Path path, u32 flags); Result IFile_Open(IFile *file, FS_Archive archive, FS_Path path, u32 flags);
Result IFile_Close(IFile *file); Result IFile_Close(IFile *file);
Result IFile_GetSize(IFile *file, u64 *size); Result IFile_GetSize(IFile *file, u64 *size);
Result IFile_Read(IFile *file, u64 *total, void *buffer, u32 len); Result IFile_Read(IFile *file, u64 *total, void *buffer, u32 len);
Result IFile_Write(IFile *file, u64 *total, void *buffer, u32 len, u32 flags);

View File

@@ -1,6 +1,5 @@
#include <3ds.h> #include <3ds.h>
#include <string.h> #include "memory.h"
#include <sys/iosupport.h>
#include "patcher.h" #include "patcher.h"
#include "exheader.h" #include "exheader.h"
#include "ifile.h" #include "ifile.h"
@@ -158,7 +157,7 @@ static Result load_code(u64 progid, prog_addrs_t *shared, u64 prog_handle, int i
} }
// patch // patch
patch_code(progid, (u8 *)shared->text_addr, shared->total_size << 12); patchCode(progid, (u8 *)shared->text_addr, shared->total_size << 12);
return 0; return 0;
} }
@@ -462,14 +461,14 @@ void __sync_init();
void __sync_fini(); void __sync_fini();
void __system_initSyscalls(); void __system_initSyscalls();
void __ctru_exit(int rc) void __ctru_exit()
{ {
__appExit(); __appExit();
__sync_fini(); __sync_fini();
svcExitProcess(); svcExitProcess();
} }
void initSystem(void (*retAddr)(void)) void initSystem()
{ {
__sync_init(); __sync_init();
__system_initSyscalls(); __system_initSyscalls();
@@ -521,7 +520,7 @@ int main()
if (R_FAILED(ret)) if (R_FAILED(ret))
{ {
// check if any handle has been closed // check if any handle has been closed
if (ret == 0xC920181A) if (ret == (int)0xC920181A)
{ {
if (index == -1) if (index == -1)
{ {

10
injector/source/memory.c Normal file
View File

@@ -0,0 +1,10 @@
#include "memory.h"
void memcpy(void *dest, const void *src, u32 size)
{
u8 *destc = (u8 *)dest;
const u8 *srcc = (const u8 *)src;
for(u32 i = 0; i < size; i++)
destc[i] = srcc[i];
}

5
injector/source/memory.h Normal file
View File

@@ -0,0 +1,5 @@
#pragma once
#include <3ds/types.h>
void memcpy(void *dest, const void *src, u32 size);

View File

@@ -1,21 +1,36 @@
#include <3ds.h> #include <3ds.h>
#include <string.h> #include "memory.h"
#include "patcher.h" #include "patcher.h"
#include "ifile.h" #include "ifile.h"
#ifndef PATH_MAX #ifndef PATH_MAX
#define PATH_MAX 255 #define PATH_MAX 255
#define CONFIG(a) ((loadConfig() >> (a + 16)) & 1)
#define MULTICONFIG(a) ((loadConfig() >> (a * 2 + 6)) & 3)
#define BOOTCONFIG(a, b) ((loadConfig() >> a) & b)
#endif #endif
static u32 config = 0; static int memcmp(const void *buf1, const void *buf2, u32 size)
static u8 secureinfo[0x111] = {0}; {
const u8 *buf1c = (const u8 *)buf1;
const u8 *buf2c = (const u8 *)buf2;
for(u32 i = 0; i < size; i++)
{
int cmp = buf1c[i] - buf2c[i];
if(cmp) return cmp;
}
return 0;
}
//Quick Search algorithm, adapted from http://igm.univ-mlv.fr/~lecroq/string/node19.html#SECTION00190 //Quick Search algorithm, adapted from http://igm.univ-mlv.fr/~lecroq/string/node19.html#SECTION00190
static u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSize){ static u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSize)
{
const u8 *patternc = (const u8 *)pattern; const u8 *patternc = (const u8 *)pattern;
//Preprocessing //Preprocessing
int table[256]; u32 table[256];
for(u32 i = 0; i < 256; ++i) for(u32 i = 0; i < 256; ++i)
table[i] = patternSize + 1; table[i] = patternSize + 1;
@@ -25,7 +40,8 @@ static u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSiz
//Searching //Searching
u32 j = 0; u32 j = 0;
while(j <= size - patternSize){ while(j <= size - patternSize)
{
if(memcmp(patternc, startPos + j, patternSize) == 0) if(memcmp(patternc, startPos + j, patternSize) == 0)
return startPos + j; return startPos + j;
j += table[startPos[j + patternSize]]; j += table[startPos[j + patternSize]];
@@ -34,28 +50,40 @@ static u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSiz
return NULL; return NULL;
} }
static u32 patch_memory(u8 *start, u32 size, const void *pattern, u32 patsize, int offset, const void *replace, u32 repsize, u32 count){ static u32 patchMemory(u8 *start, u32 size, const void *pattern, u32 patSize, int offset, const void *replace, u32 repSize, u32 count)
{
u32 i; u32 i;
for(i = 0; i < count; i++){ for(i = 0; i < count; i++)
u8 *found = memsearch(start, pattern, size, patsize); {
if(found == NULL) u8 *found = memsearch(start, pattern, size, patSize);
break;
memcpy(found + offset, replace, repsize); if(found == NULL) break;
memcpy(found + offset, replace, repSize);
u32 at = (u32)(found - start); u32 at = (u32)(found - start);
if(at + patsize > size) size = 0; if(at + patSize > size) break;
else size = size - (at + patsize);
start = found + patsize; size -= at + patSize;
start = found + patSize;
} }
return i; return i;
} }
static int file_open(IFile *file, FS_ArchiveID id, const char *path, int flags){ static inline size_t strnlen(const char *string, size_t maxlen)
{
size_t size;
for(size = 0; *string && size < maxlen; string++, size++);
return size;
}
static int fileOpen(IFile *file, FS_ArchiveID id, const char *path, int flags)
{
FS_Archive archive; FS_Archive archive;
FS_Path ppath; FS_Path ppath;
@@ -66,209 +94,423 @@ static int file_open(IFile *file, FS_ArchiveID id, const char *path, int flags){
archive.lowPath.data = (u8 *)""; archive.lowPath.data = (u8 *)"";
ppath.type = PATH_ASCII; ppath.type = PATH_ASCII;
ppath.data = path; ppath.data = path;
ppath.size = len+1; ppath.size = len + 1;
return IFile_Open(file, archive, ppath, flags); return IFile_Open(file, archive, ppath, flags);
} }
static int patch_secureinfo(){ static u32 secureInfoExists(void)
IFile file; {
Result ret; static u32 secureInfoExists = 0;
u64 total;
if(secureinfo[0] == 0xFF) if(!secureInfoExists)
return 0; {
IFile file;
ret = file_open(&file, ARCHIVE_SDMC, "/SecureInfo_A", FS_OPEN_READ); if(R_SUCCEEDED(fileOpen(&file, ARCHIVE_NAND_RW, "/sys/SecureInfo_C", FS_OPEN_READ)))
if(R_SUCCEEDED(ret)){ {
ret = IFile_Read(&file, &total, secureinfo, sizeof(secureinfo)); secureInfoExists = 1;
IFile_Close(&file);
if(R_SUCCEEDED(ret) && total == sizeof(secureinfo)){
ret = file_open(&file, ARCHIVE_NAND_RW, "/sys/SecureInfo_C", FS_OPEN_WRITE | FS_OPEN_CREATE);
if(R_SUCCEEDED(ret)){
ret = IFile_Write(&file, &total, secureinfo, sizeof(secureinfo), FS_WRITE_FLUSH);
IFile_Close(&file);
}
secureinfo[0] = 0xFF; // we repurpose this byte as status
}
}
else { // get file from NAND
ret = file_open(&file, ARCHIVE_NAND_RW, "/sys/SecureInfo_C", FS_OPEN_READ);
if(R_SUCCEEDED(ret)){
ret = IFile_Read(&file, &total, secureinfo, sizeof(secureinfo));
IFile_Close(&file); IFile_Close(&file);
if(R_SUCCEEDED(ret) && total == sizeof(secureinfo)) }
secureinfo[0] = 0xFF; }
return secureInfoExists;
}
static u32 loadConfig(void)
{
static u32 config = 0;
if(!config)
{
IFile file;
if(R_SUCCEEDED(fileOpen(&file, ARCHIVE_SDMC, "/luma/config.bin", FS_OPEN_READ)))
{
u64 total;
if(R_SUCCEEDED(IFile_Read(&file, &total, &config, 4))) config |= 1 << 4;
IFile_Close(&file);
}
}
return config;
}
static int loadTitleLocaleConfig(u64 progId, u8 *regionId, u8 *languageId)
{
/* Here we look for "/luma/locales/[u64 titleID in hex, uppercase].txt"
If it exists it should contain, for example, "EUR IT" */
char path[] = "/luma/locales/0000000000000000.txt";
u32 i = 29;
while(progId)
{
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; return ret;
} }
static int open_config(){ static u8 *getCfgOffsets(u8 *code, u32 size, u32 *CFGUHandleOffset)
IFile file; {
Result ret; /* HANS:
u64 total; 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) */
if(config) u32 n = 0,
return 0; possible[24];
ret = file_open(&file, ARCHIVE_SDMC, "/aurei/config.bin", FS_OPEN_READ); for(u8 *pos = code + 4; n < 24 && pos < code + size - 4; pos += 4)
if(R_SUCCEEDED(ret)){ {
ret = IFile_Read(&file, &total, (void *)&config, 3); if(*(u32 *)pos == 0xD8A103F9)
IFile_Close(&file); {
for(u32 *l = (u32 *)pos - 4; n < 24 && l < (u32 *)pos + 4; l++)
if(*l <= 0x10000000) possible[n++] = *l;
}
} }
return ret; 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;
} }
u32 patch_code(u64 progid, u8 *code, u32 size){ static void patchCfgGetLanguage(u8 *code, u32 size, u8 languageId, u8 *CFGU_GetConfigInfoBlk2_endPos)
if( progid == 0x0004003000008F02LL || // USA Menu {
progid == 0x0004003000008202LL || // JPN Menu u8 *CFGU_GetConfigInfoBlk2_startPos; //Let's find STMFD SP (there might be a NOP before, but nevermind)
progid == 0x0004003000009802LL || // EUR Menu
progid == 0x000400300000A102LL || // CHN Menu
progid == 0x000400300000A902LL || // KOR Menu
progid == 0x000400300000B102LL // TWN Menu
){
static const u8 regionFreePattern[] = {
0x00, 0x00, 0x55, 0xE3, 0x01, 0x10, 0xA0, 0xE3
};
static const u8 regionFreePatch[] = {
0x01, 0x00, 0xA0, 0xE3, 0x1E, 0xFF, 0x2F, 0xE1
};
patch_memory(code, size, for(CFGU_GetConfigInfoBlk2_startPos = CFGU_GetConfigInfoBlk2_endPos - 4;
regionFreePattern, CFGU_GetConfigInfoBlk2_startPos >= code && *((u16 *)CFGU_GetConfigInfoBlk2_startPos + 1) != 0xE92D;
sizeof(regionFreePattern), -16, CFGU_GetConfigInfoBlk2_startPos -= 2);
regionFreePatch,
sizeof(regionFreePatch), 1 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;
}
}
}
}
} }
else if(progid == 0x0004013000002C02LL){ // NIM }
static const u8 blockAutoUpdatesPattern[] = {
0x25, 0x79, 0x0B, 0x99
};
static const u8 blockAutoUpdatesPatch[] = {
0xE3, 0xA0
};
static const u8 blockEShopUpdateCheckPattern[] = {
0x30, 0xB5, 0xF1, 0xB0
};
static const u8 blockEShopUpdateCheckPatch[] = {
0x00, 0x20, 0x08, 0x60, 0x70, 0x47
};
static const u8 countryRespPattern[] = {
0x01, 0x20, 0x01, 0x90, 0x22, 0x46, 0x06, 0x9B
};
static const char countryRespPatchModel[] = {
0x06, 0x9A, 0x03, 0x20, 0x90, 0x47, 0x55, 0x21, 0x01, 0x70, 0x53, 0x21, 0x41, 0x70, 0x00, 0x21,
0x81, 0x70, 0x60, 0x61, 0x00, 0x20
};
const char *country;
char countryRespPatch[sizeof(countryRespPatchModel)];
patch_memory(code, size, static void patchCfgGetRegion(u8 *code, u32 size, u8 regionId, u32 CFGUHandleOffset)
blockAutoUpdatesPattern, {
sizeof(blockAutoUpdatesPattern), 0, for(u8 *cmdPos = code; cmdPos < code + size - 28; cmdPos += 4)
blockAutoUpdatesPatch, {
sizeof(blockAutoUpdatesPatch), 1 static const u32 cfgSecureInfoGetRegionCmdPattern[] = {0xEE1D4F70, 0xE3A00802, 0xE5A40080};
);
patch_memory(code, size, u32 *cmp = (u32 *)cmdPos;
blockEShopUpdateCheckPattern,
sizeof(blockEShopUpdateCheckPattern), 0, if(cmp[0] == cfgSecureInfoGetRegionCmdPattern[0] && cmp[1] == cfgSecureInfoGetRegionCmdPattern[1] &&
blockEShopUpdateCheckPatch, cmp[2] == cfgSecureInfoGetRegionCmdPattern[2] && *((u16 *)cmdPos + 7) == 0xE59F &&
sizeof(blockEShopUpdateCheckPatch), 1 *(u32 *)(cmdPos + 20 + *((u16 *)cmdPos + 6)) == CFGUHandleOffset)
); {
if(R_SUCCEEDED(patch_secureinfo())){ *((u32 *)cmdPos + 4) = 0xE3A00000 | regionId; // mov r0, =regionId
switch(secureinfo[0x100]){ *((u32 *)cmdPos + 5) = 0xE5C40008; // strb r0, [r4, 8]
case 1: country = "US"; break; *((u32 *)cmdPos + 6) = 0xE3B00000; // movs r0, 0 (result code) ('s' not needed but nvm)
case 2: country = "GB"; break; // sorry rest-of-Europe, you have to change this *((u32 *)cmdPos + 7) = 0xE5840004; // str r0, [r4, 4]
case 3: country = "AU"; break;
case 4: country = "CN"; break; //The remaining, not patched, function code will do the rest for us
case 5: country = "KR"; break; break;
case 6: country = "TW"; break; }
default: case 0: country = "JP"; break; }
}
void patchCode(u64 progId, u8 *code, u32 size)
{
switch(progId)
{
case 0x0004003000008F02LL: // USA Menu
case 0x0004003000008202LL: // EUR Menu
case 0x0004003000009802LL: // JPN Menu
case 0x000400300000A102LL: // CHN Menu
case 0x000400300000A902LL: // KOR Menu
case 0x000400300000B102LL: // TWN Menu
{
static const u8 regionFreePattern[] = {
0x00, 0x00, 0x55, 0xE3, 0x01, 0x10, 0xA0, 0xE3
};
static const u8 regionFreePatch[] = {
0x01, 0x00, 0xA0, 0xE3, 0x1E, 0xFF, 0x2F, 0xE1
};
//Patch SMDH region checks
patchMemory(code, size,
regionFreePattern,
sizeof(regionFreePattern), -16,
regionFreePatch,
sizeof(regionFreePatch), 1
);
break;
}
case 0x0004013000002C02LL: // NIM
{
static const u8 blockAutoUpdatesPattern[] = {
0x25, 0x79, 0x0B, 0x99
};
static const u8 blockAutoUpdatesPatch[] = {
0xE3, 0xA0
};
//Block silent auto-updates
patchMemory(code, size,
blockAutoUpdatesPattern,
sizeof(blockAutoUpdatesPattern), 0,
blockAutoUpdatesPatch,
sizeof(blockAutoUpdatesPatch), 1
);
//Apply only if the updated NAND hasn't been booted
if((BOOTCONFIG(0, 3) != 0) == (BOOTCONFIG(3, 1) && CONFIG(1)))
{
static const u8 skipEshopUpdateCheckPattern[] = {
0x30, 0xB5, 0xF1, 0xB0
};
static const u8 skipEshopUpdateCheckPatch[] = {
0x00, 0x20, 0x08, 0x60, 0x70, 0x47
};
//Skip update checks to access the EShop
patchMemory(code, size,
skipEshopUpdateCheckPattern,
sizeof(skipEshopUpdateCheckPattern), 0,
skipEshopUpdateCheckPatch,
sizeof(skipEshopUpdateCheckPatch), 1
);
} }
// patch XML response Country break;
memcpy(countryRespPatch,
countryRespPatchModel,
sizeof(countryRespPatchModel)
);
countryRespPatch[6] = country[0];
countryRespPatch[10] = country[1];
patch_memory(code, size,
countryRespPattern,
sizeof(countryRespPattern), 0,
countryRespPatch,
sizeof(countryRespPatch), 1
);
} }
}
else if(
progid == 0x0004001000021000LL || // USA MSET
progid == 0x0004001000020000LL || // JPN MSET
progid == 0x0004001000022000LL || // EUR MSET
progid == 0x0004001000026000LL || // CHN MSET
progid == 0x0004001000027000LL || // KOR MSET
progid == 0x0004001000028000LL // TWN MSET
){
if(R_SUCCEEDED(open_config()) && ((config >> 5) & 0x1)){
static const u16 VerPattern[] = u"Ver.";
const u32 currentFirm = ((config >> 12) & 0x1);
const u32 currentNand = ((config >> 13) & 0x3);
patch_memory(code, size, case 0x0004013000003202LL: // FRIENDS
VerPattern, {
sizeof(VerPattern) - sizeof(u16), 0, static const u8 fpdVerPattern[] = {
currentNand ? ((currentNand == 1) ? ((currentFirm == 1) ? u" Emu" : u"Emu9") : u"Emu2") : 0xE0, 0x1E, 0xFF, 0x2F, 0xE1, 0x01, 0x01, 0x01
((currentFirm == 1) ? u" Sys" : u"Sys9"), };
sizeof(VerPattern) - sizeof(u16), 1
static const u8 fpdVerPatch = 0x05;
//Allow online access to work with old friends modules
patchMemory(code, size,
fpdVerPattern,
sizeof(fpdVerPattern), 9,
&fpdVerPatch,
sizeof(fpdVerPatch), 1
); );
break;
} }
}
else if (progid == 0x0004013000008002LL){ // NS case 0x0004001000021000LL: // USA MSET
static const u8 stopCartUpdatesPattern[] = { case 0x0004001000020000LL: // JPN MSET
0x0C, 0x18, 0xE1, 0xD8 case 0x0004001000022000LL: // EUR MSET
}; case 0x0004001000026000LL: // CHN MSET
static const u8 stopCartUpdatesPatch[] = { case 0x0004001000027000LL: // KOR MSET
0x0B, 0x18, 0x21, 0xC8 case 0x0004001000028000LL: // TWN MSET
}; {
if(CONFIG(5))
{
static const u16 verPattern[] = u"Ver.";
const u32 currentNand = BOOTCONFIG(0, 3);
const u32 matchingFirm = BOOTCONFIG(2, 1) == (currentNand != 0);
patch_memory(code, size, //Patch Ver. string
stopCartUpdatesPattern, patchMemory(code, size,
sizeof(stopCartUpdatesPattern), 0, verPattern,
stopCartUpdatesPatch, sizeof(verPattern) - sizeof(u16), 0,
sizeof(stopCartUpdatesPatch), 2 !currentNand ? ((matchingFirm) ? u" Sys" : u"SysE") :
); ((currentNand == 1) ? (matchingFirm ? u" Emu" : u"EmuS") : ((matchingFirm) ? u"Emu2" : u"Em2S")),
} sizeof(verPattern) - sizeof(u16), 1
else if(progid == 0x0004013000001702LL){ // CFG );
static const u8 secureinfoSigCheckPattern[] = { }
0x06, 0x46, 0x10, 0x48, 0xFC
};
static const u8 secureinfoSigCheckPatch[] = {
0x00, 0x26
};
static const u16 secureinfoFilenamePattern[] = u"SecureInfo_";
static const u16 secureinfoFilenamePatch[] = u"C";
// disable SecureInfo signature check break;
patch_memory(code, size, }
secureinfoSigCheckPattern,
sizeof(secureinfoSigCheckPattern), 0, case 0x0004013000008002LL: // NS
secureinfoSigCheckPatch, {
sizeof(secureinfoSigCheckPatch), 1 static const u8 stopCartUpdatesPattern[] = {
); 0x0C, 0x18, 0xE1, 0xD8
if(R_SUCCEEDED(patch_secureinfo())){ };
// use SecureInfo_C static const u8 stopCartUpdatesPatch[] = {
patch_memory(code, size, 0x0B, 0x18, 0x21, 0xC8
secureinfoFilenamePattern, };
sizeof(secureinfoFilenamePattern) - sizeof(u16),
sizeof(secureinfoFilenamePattern) - sizeof(u16), //Disable updates from foreign carts (makes carts region-free)
secureinfoFilenamePatch, patchMemory(code, size,
sizeof(secureinfoFilenamePatch) - sizeof(u16), 2 stopCartUpdatesPattern,
sizeof(stopCartUpdatesPattern), 0,
stopCartUpdatesPatch,
sizeof(stopCartUpdatesPatch), 2
); );
}
}
return 0; u32 cpuSetting = MULTICONFIG(1);
}
if(cpuSetting)
{
static const u8 cfgN3dsCpuPattern[] = {
0x00, 0x40, 0xA0, 0xE1, 0x07, 0x00
};
u32 *cfgN3dsCpuLoc = (u32 *)memsearch(code, cfgN3dsCpuPattern, size, sizeof(cfgN3dsCpuPattern));
//Patch N3DS CPU Clock and L2 cache setting
if(cfgN3dsCpuLoc != NULL)
{
*(cfgN3dsCpuLoc + 1) = 0xE1A00000;
*(cfgN3dsCpuLoc + 8) = 0xE3A00000 | cpuSetting;
}
}
break;
}
case 0x0004013000001702LL: // CFG
{
static const u8 secureinfoSigCheckPattern[] = {
0x06, 0x46, 0x10, 0x48, 0xFC
};
static const u8 secureinfoSigCheckPatch[] = {
0x00, 0x26
};
//Disable SecureInfo signature check
patchMemory(code, size,
secureinfoSigCheckPattern,
sizeof(secureinfoSigCheckPattern), 0,
secureinfoSigCheckPatch,
sizeof(secureinfoSigCheckPatch), 1
);
if(secureInfoExists())
{
static const u16 secureinfoFilenamePattern[] = u"SecureInfo_";
static const u16 secureinfoFilenamePatch[] = u"C";
//Use SecureInfo_C
patchMemory(code, size,
secureinfoFilenamePattern,
sizeof(secureinfoFilenamePattern) - sizeof(u16),
sizeof(secureinfoFilenamePattern) - sizeof(u16),
secureinfoFilenamePatch,
sizeof(secureinfoFilenamePatch) - sizeof(u16), 2
);
}
break;
}
default:
if(CONFIG(4))
{
u32 tidHigh = (progId & 0xFFFFFFF000000000LL) >> 0x24;
if(tidHigh == 0x0004000)
{
//Language emulation
u8 regionId = 0xFF,
languageId = 0xFF;
if(R_SUCCEEDED(loadTitleLocaleConfig(progId, &regionId, &languageId)))
{
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

@@ -2,4 +2,4 @@
#include <3ds/types.h> #include <3ds/types.h>
u32 patch_code(u64 progid, u8 *code, u32 size); void patchCode(u64 progId, u8 *code, u32 size);

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,127 +6,50 @@ endif
include $(DEVKITARM)/3ds_rules include $(DEVKITARM)/3ds_rules
#--------------------------------------------------------------------------------- CC := arm-none-eabi-gcc
# TARGET is the name of the output AS := arm-none-eabi-as
# BUILD is the directory where object files & intermediate files will be placed LD := arm-none-eabi-ld
# SOURCES is a list of directories containing source code OC := arm-none-eabi-objcopy
# DATA is a list of directories containing data files
# INCLUDES is a list of directories containing header files
# SPECS is the directory containing the important build and link files
#---------------------------------------------------------------------------------
export TARGET := $(shell basename $(CURDIR))
BUILD := build
SOURCES := source source/fatfs source/fatfs/sdmmc
DATA := data
INCLUDES := include source/fatfs source/fatfs/sdmmc
#--------------------------------------------------------------------------------- name := $(shell basename $(CURDIR))
# Setup some defines
#---------------------------------------------------------------------------------
#--------------------------------------------------------------------------------- dir_source := source
# options for code generation dir_build := build
#---------------------------------------------------------------------------------
ARCH := -mthumb -mthumb-interwork
CFLAGS := -g -Wall -O2\ ASFLAGS := -mcpu=arm946e-s
-march=armv5te -mtune=arm946e-s\ CFLAGS := -Wall -Wextra -MMD -MP -mthumb -mthumb-interwork $(ASFLAGS) -fno-builtin -std=c11 -Wno-main -O2 -flto -ffast-math
-ffast-math -Wno-main -std=c99\ LDFLAGS := -nostartfiles
$(ARCH)
CFLAGS += $(INCLUDE) -DARM9 objects = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \
$(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \
$(call rwildcard, $(dir_source), *.s *.c)))
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions .PHONY: all
all: $(name).bin
ASFLAGS := -g $(ARCH) .PHONY: clean
LDFLAGS = -nostartfiles -g --specs=../stub.specs $(ARCH) -Wl,-Map,$(TARGET).map
LIBS :=
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS :=
#---------------------------------------------------------------------------------
# no real need to edit anything past this point unless you need to add additional
# rules for different file extensions
#---------------------------------------------------------------------------------
ifneq ($(BUILD),$(notdir $(CURDIR)))
#---------------------------------------------------------------------------------
export OUTPUT := $(CURDIR)/$(TARGET)
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
export DEPSDIR := $(CURDIR)/$(BUILD)
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C
#---------------------------------------------------------------------------------
ifeq ($(strip $(CPPFILES)),)
#---------------------------------------------------------------------------------
export LD := $(CC)
#---------------------------------------------------------------------------------
else
#---------------------------------------------------------------------------------
export LD := $(CXX)
#---------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------
export OFILES := $(addsuffix .o,$(BINFILES)) \
$(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
-I$(CURDIR)/$(BUILD)
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
.PHONY: $(BUILD) clean all
#---------------------------------------------------------------------------------
all: $(BUILD)
$(BUILD):
@[ -d $@ ] || mkdir -p $@
@make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
#---------------------------------------------------------------------------------
clean: clean:
@echo clean ... @rm -rf $(dir_build)
@rm -fr $(BUILD) $(OUTPUT).elf
#---------------------------------------------------------------------------------
else
DEPENDS := $(OFILES:.o=.d)
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
$(OUTPUT).bin : $(OUTPUT).elf
$(OUTPUT).elf : $(OFILES)
$(name).bin: $(dir_build)/$(name).elf
$(OC) -S -O binary $< $@
#--------------------------------------------------------------------------------- $(dir_build)/$(name).elf: $(objects)
%.bin: %.elf $(LINK.o) -T linker.ld $(OUTPUT_OPTION) $^
@$(OBJCOPY) -O binary $< $@
@echo built ... $(notdir $@)
-include $(DEPENDS) $(dir_build)/%.o: $(dir_source)/%.c
@mkdir -p "$(@D)"
$(COMPILE.c) $(OUTPUT_OPTION) $<
$(dir_build)/%.o: $(dir_source)/%.s
#--------------------------------------------------------------------------------------- @mkdir -p "$(@D)"
endif $(COMPILE.s) $(OUTPUT_OPTION) $<
#---------------------------------------------------------------------------------------
$(dir_build)/fatfs/%.o: $(dir_source)/fatfs/%.c
@mkdir -p "$(@D)"
$(COMPILE.c) $(OUTPUT_OPTION) $<
$(dir_build)/fatfs/%.o: $(dir_source)/fatfs/%.s
@mkdir -p "$(@D)"
$(COMPILE.s) $(OUTPUT_OPTION) $<
include $(call rwildcard, $(dir_build), *.d)

View File

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

View File

@@ -2,13 +2,13 @@
#include "types.h" #include "types.h"
#define HID_PAD (*(vu16 *)0x10146000 ^ 0xFFF) #define HID_PAD (*(vu32 *)0x10146000 ^ 0xFFF)
#define BUTTON_B (1 << 1)
#define BUTTON_X (1 << 10)
#define BUTTON_Y (1 << 11)
#define BUTTON_SELECT (1 << 2)
#define BUTTON_START (1 << 3)
#define BUTTON_RIGHT (1 << 4) #define BUTTON_RIGHT (1 << 4)
#define BUTTON_LEFT (1 << 5) #define BUTTON_LEFT (1 << 5)
#define BUTTON_UP (1 << 6) #define BUTTON_UP (1 << 6)
#define BUTTON_DOWN (1 << 7) #define BUTTON_DOWN (1 << 7)
#define BUTTON_A 1
#define BUTTON_X (1 << 10)
#define BUTTON_Y (1 << 11)
#define BUTTON_R1 (1 << 8)
#define BUTTON_SELECT (1 << 2)

View File

@@ -1,180 +1,254 @@
---------------------------------------------------------------------------- ----------------------------------------------------------------------------
Revision history of FatFs module Revision history of FatFs module
---------------------------------------------------------------------------- ----------------------------------------------------------------------------
R0.00 (February 26, 2006) R0.00 (February 26, 2006)
Prototype.
Prototype.
R0.01 (April 29, 2006)
First stable version.
R0.01 (April 29, 2006)
R0.02 (June 01, 2006) First stable version.
Added FAT12 support.
Removed unbuffered mode.
Fixed a problem on small (<32M) partition.
R0.02 (June 01, 2006)
R0.02a (June 10, 2006) Added FAT12 support.
Added a configuration option (_FS_MINIMUM). Removed unbuffered mode.
Fixed a problem on small (<32M) partition.
R0.03 (September 22, 2006)
Added f_rename().
Changed option _FS_MINIMUM to _FS_MINIMIZE. R0.02a (June 10, 2006)
Added a configuration option (_FS_MINIMUM).
R0.03a (December 11, 2006)
Improved cluster scan algorithm to write files fast.
Fixed f_mkdir() creates incorrect directory on FAT32.
R0.03 (September 22, 2006)
R0.04 (February 04, 2007) Added f_rename().
Added f_mkfs(). Changed option _FS_MINIMUM to _FS_MINIMIZE.
Supported multiple drive system.
Changed some interfaces for multiple drive system.
Changed f_mountdrv() to f_mount().
R0.03a (December 11, 2006)
R0.04a (April 01, 2007) Improved cluster scan algorithm to write files fast.
Supported multiple partitions on a physical drive. Fixed f_mkdir() creates incorrect directory on FAT32.
Added a capability of extending file size to f_lseek().
Added minimization level 3.
Fixed an endian sensitive code in f_mkfs().
R0.04 (February 04, 2007)
R0.04b (May 05, 2007) Added f_mkfs().
Added a configuration option _USE_NTFLAG. Supported multiple drive system.
Added FSINFO support. Changed some interfaces for multiple drive system.
Fixed DBCS name can result FR_INVALID_NAME. Changed f_mountdrv() to f_mount().
Fixed short seek (<= csize) collapses the file object.
R0.05 (August 25, 2007) R0.04a (April 01, 2007)
Changed arguments of f_read(), f_write() and f_mkfs().
Fixed f_mkfs() on FAT32 creates incorrect FSINFO. Supported multiple partitions on a physical drive.
Fixed f_mkdir() on FAT32 creates incorrect directory. Added a capability of extending file size to f_lseek().
Added minimization level 3.
Fixed an endian sensitive code in f_mkfs().
R0.05a (February 03, 2008)
Added f_truncate() and f_utime().
Fixed off by one error at FAT sub-type determination.
Fixed btr in f_read() can be mistruncated. R0.04b (May 05, 2007)
Fixed cached sector is not flushed when create and close without write.
Added a configuration option _USE_NTFLAG.
Added FSINFO support.
R0.06 (April 01, 2008) Fixed DBCS name can result FR_INVALID_NAME.
Added fputc(), fputs(), fprintf() and fgets(). Fixed short seek (<= csize) collapses the file object.
Improved performance of f_lseek() on moving to the same or following cluster.
R0.07 (April 01, 2009) R0.05 (August 25, 2007)
Merged Tiny-FatFs as a configuration option. (_FS_TINY)
Added long file name feature. (_USE_LFN) Changed arguments of f_read(), f_write() and f_mkfs().
Added multiple code page feature. (_CODE_PAGE) Fixed f_mkfs() on FAT32 creates incorrect FSINFO.
Added re-entrancy for multitask operation. (_FS_REENTRANT) Fixed f_mkdir() on FAT32 creates incorrect directory.
Added auto cluster size selection to f_mkfs().
Added rewind option to f_readdir().
Changed result code of critical errors.
Renamed string functions to avoid name collision. R0.05a (February 03, 2008)
Added f_truncate() and f_utime().
R0.07a (April 14, 2009) Fixed off by one error at FAT sub-type determination.
Septemberarated out OS dependent code on reentrant cfg. Fixed btr in f_read() can be mistruncated.
Added multiple sector size feature. Fixed cached sector is not flushed when create and close without write.
R0.07c (June 21, 2009)
Fixed f_unlink() can return FR_OK on error. R0.06 (April 01, 2008)
Fixed wrong cache control in f_lseek().
Added relative path feature. Added fputc(), fputs(), fprintf() and fgets().
Added f_chdir() and f_chdrive(). Improved performance of f_lseek() on moving to the same or following cluster.
Added proper case conversion to extended character.
R0.07e (November 03, 2009) R0.07 (April 01, 2009)
Septemberarated out configuration options from ff.h to ffconf.h.
Fixed f_unlink() fails to remove a sub-directory on _FS_RPATH. Merged Tiny-FatFs as a configuration option. (_FS_TINY)
Fixed name matching error on the 13 character boundary. Added long file name feature. (_USE_LFN)
Added a configuration option, _LFN_UNICODE. Added multiple code page feature. (_CODE_PAGE)
Changed f_readdir() to return the SFN with always upper case on non-LFN cfg. Added re-entrancy for multitask operation. (_FS_REENTRANT)
Added auto cluster size selection to f_mkfs().
Added rewind option to f_readdir().
R0.08 (May 15, 2010) Changed result code of critical errors.
Added a memory configuration option. (_USE_LFN = 3) Renamed string functions to avoid name collision.
Added file lock feature. (_FS_SHARE)
Added fast seek feature. (_USE_FASTSEEK)
Changed some types on the API, XCHAR->TCHAR.
Changed .fname in the FILINFO structure on Unicode cfg. R0.07a (April 14, 2009)
String functions support UTF-8 encoding files on Unicode cfg.
Septemberarated out OS dependent code on reentrant cfg.
Added multiple sector size feature.
R0.08a (August 16, 2010)
Added f_getcwd(). (_FS_RPATH = 2)
Added sector erase feature. (_USE_ERASE)
Moved file lock semaphore table from fs object to the bss. R0.07c (June 21, 2009)
Fixed f_mkfs() creates wrong FAT32 volume.
Fixed f_unlink() can return FR_OK on error.
Fixed wrong cache control in f_lseek().
R0.08b (January 15, 2011) Added relative path feature.
Fast seek feature is also applied to f_read() and f_write(). Added f_chdir() and f_chdrive().
f_lseek() reports required table size on creating CLMP. Added proper case conversion to extended character.
Extended format syntax of f_printf().
Ignores duplicated directory separators in given path name.
R0.07e (November 03, 2009)
R0.09 (September 06, 2011)
f_mkfs() supports multiple partition to complete the multiple partition feature. Septemberarated out configuration options from ff.h to ffconf.h.
Added f_fdisk(). Fixed f_unlink() fails to remove a sub-directory on _FS_RPATH.
Fixed name matching error on the 13 character boundary.
Added a configuration option, _LFN_UNICODE.
R0.09a (August 27, 2012) Changed f_readdir() to return the SFN with always upper case on non-LFN cfg.
Changed f_open() and f_opendir() reject null object pointer to avoid crash.
Changed option name _FS_SHARE to _FS_LOCK.
Fixed assertion failure due to OS/2 EA on FAT12/16 volume.
R0.08 (May 15, 2010)
R0.09b (January 24, 2013) Added a memory configuration option. (_USE_LFN = 3)
Added f_setlabel() and f_getlabel(). Added file lock feature. (_FS_SHARE)
Added fast seek feature. (_USE_FASTSEEK)
Changed some types on the API, XCHAR->TCHAR.
R0.10 (October 02, 2013) Changed .fname in the FILINFO structure on Unicode cfg.
Added selection of character encoding on the file. (_STRF_ENCODE) String functions support UTF-8 encoding files on Unicode cfg.
Added f_closedir().
Added forced full FAT scan for f_getfree(). (_FS_NOFSINFO)
Added forced mount feature with changes of f_mount().
Improved behavior of volume auto detection. R0.08a (August 16, 2010)
Improved write throughput of f_puts() and f_printf().
Changed argument of f_chdrive(), f_mkfs(), disk_read() and disk_write(). Added f_getcwd(). (_FS_RPATH = 2)
Fixed f_write() can be truncated when the file size is close to 4GB. Added sector erase feature. (_USE_ERASE)
Fixed f_open(), f_mkdir() and f_setlabel() can return incorrect error code. Moved file lock semaphore table from fs object to the bss.
Fixed f_mkfs() creates wrong FAT32 volume.
R0.10a (January 15, 2014)
Added arbitrary strings as drive number in the path name. (_STR_VOLUME_ID)
Added a configuration option of minimum sector size. (_MIN_SS) R0.08b (January 15, 2011)
2nd argument of f_rename() can have a drive number and it will be ignored.
Fixed f_mount() with forced mount fails when drive number is >= 1. (appeared at R0.10) Fast seek feature is also applied to f_read() and f_write().
Fixed f_close() invalidates the file object without volume lock. f_lseek() reports required table size on creating CLMP.
Fixed f_closedir() returns but the volume lock is left acquired. (appeared at R0.10) Extended format syntax of f_printf().
Fixed creation of an entry with LFN fails on too many SFN collisions. (appeared at R0.07) Ignores duplicated directory separators in given path name.
R0.10b (May 19, 2014)
Fixed a hard error in the disk I/O layer can collapse the directory entry. R0.09 (September 06, 2011)
Fixed LFN entry is not deleted on delete/rename an object with lossy converted SFN. (appeared at R0.07)
f_mkfs() supports multiple partition to complete the multiple partition feature.
Added f_fdisk().
R0.10c (November 09, 2014)
Added a configuration option for the platforms without RTC. (_FS_NORTC)
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) R0.09a (August 27, 2012)
Fixed a potential problem of FAT access that can appear on disk error.
Fixed null pointer dereference on attempting to delete the root direcotry. (appeared at R0.08) Changed f_open() and f_opendir() reject null object pointer to avoid crash.
Changed option name _FS_SHARE to _FS_LOCK.
Fixed assertion failure due to OS/2 EA on FAT12/16 volume.
R0.11 (February 09, 2015)
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 _FS_NORTC option does not work properly. (appeared at R0.10c) R0.09b (January 24, 2013)
Added f_setlabel() and f_getlabel().
R0.10 (October 02, 2013)
Added selection of character encoding on the file. (_STRF_ENCODE)
Added f_closedir().
Added forced full FAT scan for f_getfree(). (_FS_NOFSINFO)
Added forced mount feature with changes of f_mount().
Improved behavior of volume auto detection.
Improved write throughput of f_puts() and f_printf().
Changed argument of f_chdrive(), f_mkfs(), disk_read() and disk_write().
Fixed f_write() can be truncated when the file size is close to 4GB.
Fixed f_open(), f_mkdir() and f_setlabel() can return incorrect value on error.
R0.10a (January 15, 2014)
Added arbitrary strings as drive number in the path name. (_STR_VOLUME_ID)
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.
Fixed f_mount() with forced mount fails when drive number is >= 1. (appeared at R0.10)
Fixed f_close() invalidates the file object without volume lock.
Fixed f_closedir() returns but the volume lock is left acquired. (appeared at R0.10)
Fixed creation of an entry with LFN fails on too many SFN collisions. (appeared at R0.07)
R0.10b (May 19, 2014)
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)
R0.10c (November 09, 2014)
Added a configuration option for the platforms without RTC. (_FS_NORTC)
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 a potential problem of FAT access that can appear on disk error.
Fixed null pointer dereference on attempting to delete the root direcotry. (appeared at R0.08)
R0.11 (February 09, 2015)
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 _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).
R0.12 (April 12, 2016)
Added support of exFAT file system. (_FS_EXFAT)
Added f_expand(). (_USE_EXPAND)
Changed some members in FINFO structure and behavior of f_readdir().
Added an option _USE_CHMOD and removed an option _WORD_ACCESS.
Fixed errors in the case conversion teble of Unicode (cc*.c).

View File

@@ -1,21 +1,21 @@
FatFs Module Source Files R0.11 FatFs Module Source Files R0.12
FILES FILES
00readme.txt This file. 00readme.txt This file.
history.txt Revision history. history.txt Revision history.
ffconf.h Configuration file for FatFs module. ffconf.h Configuration file for FatFs module.
ff.h Common include file for FatFs and application module. ff.h Common include file for FatFs and application module.
ff.c FatFs module. ff.c FatFs module.
diskio.h Common include file for FatFs and disk I/O module. diskio.h Common include file for FatFs and disk I/O module.
diskio.c An example of glue function to attach existing disk I/O module to FatFs. diskio.c An example of glue function to attach existing disk I/O module to FatFs.
integer.h Integer type definitions for FatFs. integer.h Integer type definitions for FatFs.
option Optional external functions. option Optional external functions.
Low level disk I/O module is not included in this archive because the FatFs Low level disk I/O module is not included in this archive because the FatFs
module is only a generic file system layer and not depend on any specific module is only a generic file system layer and not depend on any specific
storage device. You have to provide a low level disk I/O module that written storage device. You have to provide a low level disk I/O module that written
to control the target storage device. to control the target storage device.

View File

@@ -10,7 +10,6 @@
#include "diskio.h" /* FatFs lower layer API */ #include "diskio.h" /* FatFs lower layer API */
#include "sdmmc/sdmmc.h" #include "sdmmc/sdmmc.h"
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* Get Drive Status */ /* Get Drive Status */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
@@ -35,6 +34,7 @@ DSTATUS disk_initialize (
) )
{ {
sdmmc_sdcard_init(); sdmmc_sdcard_init();
return RES_OK; return RES_OK;
} }
@@ -52,9 +52,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;
} }
@@ -69,15 +68,14 @@ DRESULT disk_read (
DRESULT disk_write ( DRESULT disk_write (
__attribute__((unused)) __attribute__((unused))
BYTE pdrv, /* Physical drive nmuber to identify the drive */ BYTE pdrv, /* Physical drive nmuber to identify the drive */
__attribute__((unused))
const BYTE *buff, /* Data to be written */ const BYTE *buff, /* Data to be written */
__attribute__((unused))
DWORD sector, /* Sector address in LBA */ DWORD sector, /* Sector address in LBA */
__attribute__((unused))
UINT count /* Number of sectors to write */ UINT count /* Number of sectors to write */
) )
{ {
if (sdmmc_sdcard_writesectors(sector, count, (BYTE *)buff)) {
return RES_PARERR;
}
return RES_OK; return RES_OK;
} }
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,350 +1,366 @@
/*---------------------------------------------------------------------------/ /*---------------------------------------------------------------------------/
/ FatFs - FAT file system module include R0.11 (C)ChaN, 2015 / FatFs - FAT file system module include R0.12 (C)ChaN, 2016
/----------------------------------------------------------------------------/ /----------------------------------------------------------------------------/
/ 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.
/ /
/ Copyright (C) 2015, ChaN, all right reserved. / Copyright (C) 2016, ChaN, all right reserved.
/ /
/ 1. Redistributions of source code must retain the above copyright notice, / 1. Redistributions of source code must retain the above copyright notice,
/ this condition and the following disclaimer. / this condition and the following disclaimer.
/ /
/ This software is provided by the copyright holder and contributors "AS IS" / This software is provided by the copyright holder and contributors "AS IS"
/ and any warranties related to this software are DISCLAIMED. / and any warranties related to this software are DISCLAIMED.
/ The copyright owner or contributors be NOT LIABLE for any damages caused / The copyright owner or contributors be NOT LIABLE for any damages caused
/ by use of this software. / by use of this software.
/---------------------------------------------------------------------------*/ /---------------------------------------------------------------------------*/
#ifndef _FATFS #ifndef _FATFS
#define _FATFS 32020 /* Revision ID */ #define _FATFS 88100 /* Revision ID */
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
#include "integer.h" /* Basic integer types */ #include "integer.h" /* Basic integer types */
#include "ffconf.h" /* FatFs configuration options */ #include "ffconf.h" /* FatFs configuration options */
#if _FATFS != _FFCONF #if _FATFS != _FFCONF
#error Wrong configuration file (ffconf.h). #error Wrong configuration file (ffconf.h).
#endif #endif
/* Definitions of volume management */ /* Definitions of volume management */
#if _MULTI_PARTITION /* Multiple partition configuration */ #if _MULTI_PARTITION /* Multiple partition configuration */
typedef struct { typedef struct {
BYTE pd; /* Physical drive number */ BYTE pd; /* Physical drive number */
BYTE pt; /* Partition: 0:Auto detect, 1-4:Forced partition) */ BYTE pt; /* Partition: 0:Auto detect, 1-4:Forced partition) */
} PARTITION; } PARTITION;
extern PARTITION VolToPart[]; /* Volume - Partition resolution table */ extern PARTITION VolToPart[]; /* Volume - Partition resolution table */
#define LD2PD(vol) (VolToPart[vol].pd) /* Get physical drive number */ #define LD2PD(vol) (VolToPart[vol].pd) /* Get physical drive number */
#define LD2PT(vol) (VolToPart[vol].pt) /* Get partition index */ #define LD2PT(vol) (VolToPart[vol].pt) /* Get partition index */
#else /* Single partition configuration */ #else /* Single partition configuration */
#define LD2PD(vol) (BYTE)(vol) /* Each logical drive is bound to the same physical drive number */ #define LD2PD(vol) (BYTE)(vol) /* Each logical drive is bound to the same physical drive number */
#define LD2PT(vol) 0 /* Find first valid partition or in SFD */ #define LD2PT(vol) 0 /* Find first valid partition or in SFD */
#endif #endif
/* Type of path name strings on FatFs API */ /* Type of path name strings on FatFs API */
#if _LFN_UNICODE /* Unicode string */ #if _LFN_UNICODE /* Unicode string */
#if !_USE_LFN #if _USE_LFN == 0
#error _LFN_UNICODE must be 0 at non-LFN cfg. #error _LFN_UNICODE must be 0 at non-LFN cfg.
#endif #endif
#ifndef _INC_TCHAR #ifndef _INC_TCHAR
typedef WCHAR TCHAR; typedef WCHAR TCHAR;
#define _T(x) L ## x #define _T(x) L ## x
#define _TEXT(x) L ## x #define _TEXT(x) L ## x
#endif #endif
#else /* ANSI/OEM string */ #else /* ANSI/OEM string */
#ifndef _INC_TCHAR #ifndef _INC_TCHAR
typedef char TCHAR; typedef char TCHAR;
#define _T(x) x #define _T(x) x
#define _TEXT(x) x #define _TEXT(x) x
#endif #endif
#endif #endif
/* File system object structure (FATFS) */ /* File system object structure (FATFS) */
typedef struct { typedef struct {
BYTE fs_type; /* FAT sub-type (0:Not mounted) */ BYTE fs_type; /* File system type (0:N/A) */
BYTE drv; /* Physical drive number */ BYTE drv; /* Physical drive number */
BYTE csize; /* Sectors per cluster (1,2,4...128) */ BYTE n_fats; /* Number of FATs (1 or 2) */
BYTE n_fats; /* Number of FAT copies (1 or 2) */ BYTE wflag; /* win[] flag (b0:dirty) */
BYTE wflag; /* win[] flag (b0:dirty) */ BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */
BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */ WORD id; /* File system mount ID */
WORD id; /* File system mount ID */ WORD n_rootdir; /* Number of root directory entries (FAT12/16) */
WORD n_rootdir; /* Number of root directory entries (FAT12/16) */ WORD csize; /* Cluster size [sectors] */
#if _MAX_SS != _MIN_SS #if _MAX_SS != _MIN_SS
WORD ssize; /* Bytes per sector (512, 1024, 2048 or 4096) */ WORD ssize; /* Sector size (512, 1024, 2048 or 4096) */
#endif #endif
#if _FS_REENTRANT #if _FS_EXFAT
_SYNC_t sobj; /* Identifier of sync object */ BYTE* dirbuf; /* Directory entry block scratchpad buffer */
#endif #endif
#if !_FS_READONLY #if _FS_REENTRANT
DWORD last_clust; /* Last allocated cluster */ _SYNC_t sobj; /* Identifier of sync object */
DWORD free_clust; /* Number of free clusters */ #endif
#endif #if !_FS_READONLY
#if _FS_RPATH DWORD last_clst; /* Last allocated cluster */
DWORD cdir; /* Current directory start cluster (0:root) */ DWORD free_clst; /* Number of free clusters */
#endif #endif
DWORD n_fatent; /* Number of FAT entries, = number of clusters + 2 */ #if _FS_RPATH != 0
DWORD fsize; /* Sectors per FAT */ DWORD cdir; /* Current directory start cluster (0:root) */
DWORD volbase; /* Volume start sector */ #if _FS_EXFAT
DWORD fatbase; /* FAT start sector */ DWORD cdc_scl; /* Containing directory start cluster (invalid when cdir is 0) */
DWORD dirbase; /* Root directory start sector (FAT32:Cluster#) */ DWORD cdc_size; /* b31-b8:Size of containing directory, b7-b0: Chain status */
DWORD database; /* Data start sector */ DWORD cdc_ofs; /* Offset in the containing directory (invalid when cdir is 0) */
DWORD winsect; /* Current sector appearing in the win[] */ #endif
BYTE win[_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */ #endif
} FATFS; DWORD n_fatent; /* Number of FAT entries (number of clusters + 2) */
DWORD fsize; /* Size of an FAT [sectors] */
DWORD volbase; /* Volume base sector */
DWORD fatbase; /* FAT base sector */
/* File object structure (FIL) */ DWORD dirbase; /* Root directory base sector/cluster */
DWORD database; /* Data base sector */
typedef struct { DWORD winsect; /* Current sector appearing in the win[] */
FATFS* fs; /* Pointer to the related file system object (**do not change order**) */ BYTE win[_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */
WORD id; /* Owner file system mount ID (**do not change order**) */ } FATFS;
BYTE flag; /* Status flags */
BYTE err; /* Abort flag (error code) */
DWORD fptr; /* File read/write pointer (Zeroed on file open) */
DWORD fsize; /* File size */ /* Type of file size variables and object identifier */
DWORD sclust; /* File start cluster (0:no cluster chain, always 0 when fsize is 0) */
DWORD clust; /* Current cluster of fpter (not valid when fprt is 0) */ #if _FS_EXFAT
DWORD dsect; /* Sector number appearing in buf[] (0:invalid) */ #if _USE_LFN == 0
#if !_FS_READONLY #error LFN must be enabled when enable exFAT
DWORD dir_sect; /* Sector number containing the directory entry */ #endif
BYTE* dir_ptr; /* Pointer to the directory entry in the win[] */ typedef QWORD FSIZE_t;
#endif #else
#if _USE_FASTSEEK typedef DWORD FSIZE_t;
DWORD* cltbl; /* Pointer to the cluster link map table (Nulled on file open) */ #endif
#endif
#if _FS_LOCK
UINT lockid; /* File lock ID origin from 1 (index of file semaphore table Files[]) */
#endif /* Object ID and allocation information (_FDID) */
#if !_FS_TINY
BYTE buf[_MAX_SS]; /* File private data read/write window */ typedef struct {
#endif FATFS* fs; /* Pointer to the owner file system object */
} FIL; WORD id; /* Owner file system mount ID */
BYTE attr; /* Object attribute */
BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous (no data on FAT), =3:got flagmented, b2:sub-directory stretched) */
DWORD sclust; /* Object start cluster (0:no cluster or root directory) */
/* Directory object structure (DIR) */ FSIZE_t objsize; /* Object size (valid when sclust != 0) */
#if _FS_EXFAT
typedef struct { DWORD n_cont; /* Size of coutiguous part, clusters - 1 (valid when stat == 3) */
FATFS* fs; /* Pointer to the owner file system object (**do not change order**) */ DWORD c_scl; /* Containing directory start cluster (valid when sclust != 0) */
WORD id; /* Owner file system mount ID (**do not change order**) */ DWORD c_size; /* b31-b8:Size of containing directory, b7-b0: Chain status (valid when c_scl != 0) */
WORD index; /* Current read/write index number */ DWORD c_ofs; /* Offset in the containing directory (valid when sclust != 0) */
DWORD sclust; /* Table start cluster (0:Root dir) */ #endif
DWORD clust; /* Current cluster */ #if _FS_LOCK != 0
DWORD sect; /* Current sector */ UINT lockid; /* File lock ID origin from 1 (index of file semaphore table Files[]) */
BYTE* dir; /* Pointer to the current SFN entry in the win[] */ #endif
BYTE* fn; /* Pointer to the SFN (in/out) {file[8],ext[3],status[1]} */ } _FDID;
#if _FS_LOCK
UINT lockid; /* File lock ID (index of file semaphore table Files[]) */
#endif
#if _USE_LFN /* File object structure (FIL) */
WCHAR* lfn; /* Pointer to the LFN working buffer */
WORD lfn_idx; /* Last matched LFN index number (0xFFFF:No LFN) */ typedef struct {
#endif _FDID obj; /* Object identifier */
#if _USE_FIND BYTE flag; /* File status flags */
const TCHAR* pat; /* Pointer to the name matching pattern */ BYTE err; /* Abort flag (error code) */
#endif FSIZE_t fptr; /* File read/write pointer (Zeroed on file open) */
} DIR; DWORD clust; /* Current cluster of fpter (not valid when fprt is 0) */
DWORD sect; /* Sector number appearing in buf[] (0:invalid) */
#if !_FS_READONLY
DWORD dir_sect; /* Sector number containing the directory entry */
/* File information structure (FILINFO) */ BYTE* dir_ptr; /* Pointer to the directory entry in the win[] */
#endif
typedef struct { #if _USE_FASTSEEK
DWORD fsize; /* File size */ DWORD* cltbl; /* Pointer to the cluster link map table (Nulled on file open) */
WORD fdate; /* Last modified date */ #endif
WORD ftime; /* Last modified time */ #if !_FS_TINY
BYTE fattrib; /* Attribute */ BYTE buf[_MAX_SS]; /* File private data read/write window */
TCHAR fname[13]; /* Short file name (8.3 format) */ #endif
#if _USE_LFN } FIL;
TCHAR* lfname; /* Pointer to the LFN buffer */
UINT lfsize; /* Size of LFN buffer in TCHAR */
#endif
} FILINFO; /* Directory object structure (DIR) */
typedef struct {
_FDID obj; /* Object identifier */
/* File function return code (FRESULT) */ DWORD dptr; /* Current read/write offset */
DWORD clust; /* Current cluster */
typedef enum { DWORD sect; /* Current sector */
FR_OK = 0, /* (0) Succeeded */ BYTE* dir; /* Pointer to the directory item in the win[] */
FR_DISK_ERR, /* (1) A hard error occurred in the low level disk I/O layer */ BYTE* fn; /* Pointer to the SFN (in/out) {body[8],ext[3],status[1]} */
FR_INT_ERR, /* (2) Assertion failed */ #if _USE_LFN != 0
FR_NOT_READY, /* (3) The physical drive cannot work */ DWORD blk_ofs; /* Offset of current entry block being processed (0xFFFFFFFF:Invalid) */
FR_NO_FILE, /* (4) Could not find the file */ WCHAR* lfn; /* Pointer to the LFN working buffer */
FR_NO_PATH, /* (5) Could not find the path */ #endif
FR_INVALID_NAME, /* (6) The path name format is invalid */ #if _USE_FIND
FR_DENIED, /* (7) Access denied due to prohibited access or directory full */ const TCHAR* pat; /* Pointer to the name matching pattern */
FR_EXIST, /* (8) Access denied due to prohibited access */ #endif
FR_INVALID_OBJECT, /* (9) The file/directory object is invalid */ } DIR;
FR_WRITE_PROTECTED, /* (10) The physical drive is write protected */
FR_INVALID_DRIVE, /* (11) The logical drive number is invalid */
FR_NOT_ENABLED, /* (12) The volume has no work area */
FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume */ /* File information structure (FILINFO) */
FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any parameter error */
FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */ typedef struct {
FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */ FSIZE_t fsize; /* File size */
FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */ WORD fdate; /* Modified date */
FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > _FS_SHARE */ WORD ftime; /* Modified time */
FR_INVALID_PARAMETER /* (19) Given parameter is invalid */ BYTE fattrib; /* File attribute */
} FRESULT; #if _USE_LFN != 0
TCHAR altname[13]; /* Altenative file name */
TCHAR fname[_MAX_LFN + 1]; /* Primary file name */
#else
/*--------------------------------------------------------------*/ TCHAR fname[13]; /* File name */
/* FatFs module application interface */ #endif
} FILINFO;
FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */
FRESULT f_close (FIL* fp); /* Close an open file object */
FRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br); /* Read data from a file */
FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to a file */ /* File function return code (FRESULT) */
FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */
FRESULT f_lseek (FIL* fp, DWORD ofs); /* Move file pointer of a file object */ typedef enum {
FRESULT f_truncate (FIL* fp); /* Truncate file */ FR_OK = 0, /* (0) Succeeded */
FRESULT f_sync (FIL* fp); /* Flush cached data of a writing file */ FR_DISK_ERR, /* (1) A hard error occurred in the low level disk I/O layer */
FRESULT f_opendir (DIR* dp, const TCHAR* path); /* Open a directory */ FR_INT_ERR, /* (2) Assertion failed */
FRESULT f_closedir (DIR* dp); /* Close an open directory */ FR_NOT_READY, /* (3) The physical drive cannot work */
FRESULT f_readdir (DIR* dp, FILINFO* fno); /* Read a directory item */ FR_NO_FILE, /* (4) Could not find the file */
FRESULT f_findfirst (DIR* dp, FILINFO* fno, const TCHAR* path, const TCHAR* pattern); /* Find first file */ FR_NO_PATH, /* (5) Could not find the path */
FRESULT f_findnext (DIR* dp, FILINFO* fno); /* Find next file */ FR_INVALID_NAME, /* (6) The path name format is invalid */
FRESULT f_mkdir (const TCHAR* path); /* Create a sub directory */ FR_DENIED, /* (7) Access denied due to prohibited access or directory full */
FRESULT f_unlink (const TCHAR* path); /* Delete an existing file or directory */ FR_EXIST, /* (8) Access denied due to prohibited access */
FRESULT f_rename (const TCHAR* path_old, const TCHAR* path_new); /* Rename/Move a file or directory */ FR_INVALID_OBJECT, /* (9) The file/directory object is invalid */
FRESULT f_stat (const TCHAR* path, FILINFO* fno); /* Get file status */ FR_WRITE_PROTECTED, /* (10) The physical drive is write protected */
FRESULT f_chmod (const TCHAR* path, BYTE attr, BYTE mask); /* Change attribute of the file/dir */ FR_INVALID_DRIVE, /* (11) The logical drive number is invalid */
FRESULT f_utime (const TCHAR* path, const FILINFO* fno); /* Change times-tamp of the file/dir */ FR_NOT_ENABLED, /* (12) The volume has no work area */
FRESULT f_chdir (const TCHAR* path); /* Change current directory */ FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume */
FRESULT f_chdrive (const TCHAR* path); /* Change current drive */ FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any parameter error */
FRESULT f_getcwd (TCHAR* buff, UINT len); /* Get current directory */ FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */
FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs); /* Get number of free clusters on the drive */ FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */
FRESULT f_getlabel (const TCHAR* path, TCHAR* label, DWORD* vsn); /* Get volume label */ FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */
FRESULT f_setlabel (const TCHAR* label); /* Set volume label */ FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > _FS_LOCK */
FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */ FR_INVALID_PARAMETER /* (19) Given parameter is invalid */
FRESULT f_mkfs (const TCHAR* path, BYTE sfd, UINT au); /* Create a file system on the volume */ } FRESULT;
FRESULT f_fdisk (BYTE pdrv, const DWORD szt[], void* work); /* Divide a physical drive into some partitions */
int f_putc (TCHAR c, FIL* fp); /* Put a character to the file */
int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */
int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */ /*--------------------------------------------------------------*/
TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the file */ /* FatFs module application interface */
#define f_eof(fp) ((int)((fp)->fptr == (fp)->fsize)) FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */
#define f_error(fp) ((fp)->err) FRESULT f_close (FIL* fp); /* Close an open file object */
#define f_tell(fp) ((fp)->fptr) FRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br); /* Read data from a file */
#define f_size(fp) ((fp)->fsize) FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to a file */
#define f_rewind(fp) f_lseek((fp), 0) FRESULT f_lseek (FIL* fp, FSIZE_t ofs); /* Move file pointer of a file object */
#define f_rewinddir(dp) f_readdir((dp), 0) FRESULT f_truncate (FIL* fp); /* Truncate file */
FRESULT f_sync (FIL* fp); /* Flush cached data of a writing file */
#ifndef EOF FRESULT f_opendir (DIR* dp, const TCHAR* path); /* Open a directory */
#define EOF (-1) FRESULT f_closedir (DIR* dp); /* Close an open directory */
#endif FRESULT f_readdir (DIR* dp, FILINFO* fno); /* Read a directory item */
FRESULT f_findfirst (DIR* dp, FILINFO* fno, const TCHAR* path, const TCHAR* pattern); /* Find first file */
FRESULT f_findnext (DIR* dp, FILINFO* fno); /* Find next file */
FRESULT f_mkdir (const TCHAR* path); /* Create a sub directory */
FRESULT f_unlink (const TCHAR* path); /* Delete an existing file or directory */
/*--------------------------------------------------------------*/ FRESULT f_rename (const TCHAR* path_old, const TCHAR* path_new); /* Rename/Move a file or directory */
/* Additional user defined functions */ FRESULT f_stat (const TCHAR* path, FILINFO* fno); /* Get file status */
FRESULT f_chmod (const TCHAR* path, BYTE attr, BYTE mask); /* Change attribute of the file/dir */
/* RTC function */ FRESULT f_utime (const TCHAR* path, const FILINFO* fno); /* Change timestamp of the file/dir */
#if !_FS_READONLY && !_FS_NORTC FRESULT f_chdir (const TCHAR* path); /* Change current directory */
DWORD get_fattime (void); FRESULT f_chdrive (const TCHAR* path); /* Change current drive */
#endif FRESULT f_getcwd (TCHAR* buff, UINT len); /* Get current directory */
FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs); /* Get number of free clusters on the drive */
/* Unicode support functions */ FRESULT f_getlabel (const TCHAR* path, TCHAR* label, DWORD* vsn); /* Get volume label */
#if _USE_LFN /* Unicode - OEM code conversion */ FRESULT f_setlabel (const TCHAR* label); /* Set volume label */
WCHAR ff_convert (WCHAR chr, UINT dir); /* OEM-Unicode bidirectional conversion */ FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */
WCHAR ff_wtoupper (WCHAR chr); /* Unicode upper-case conversion */ FRESULT f_expand (FIL* fp, FSIZE_t szf, BYTE opt); /* Allocate a contiguous block to the file */
#if _USE_LFN == 3 /* Memory functions */ FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */
void* ff_memalloc (UINT msize); /* Allocate memory block */ FRESULT f_mkfs (const TCHAR* path, BYTE sfd, UINT au); /* Create a file system on the volume */
void ff_memfree (void* mblock); /* Free memory block */ FRESULT f_fdisk (BYTE pdrv, const DWORD szt[], void* work); /* Divide a physical drive into some partitions */
#endif int f_putc (TCHAR c, FIL* fp); /* Put a character to the file */
#endif int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */
int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */
/* Sync functions */ TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the file */
#if _FS_REENTRANT
int ff_cre_syncobj (BYTE vol, _SYNC_t* sobj); /* Create a sync object */ #define f_eof(fp) ((int)((fp)->fptr == (fp)->obj.objsize))
int ff_req_grant (_SYNC_t sobj); /* Lock sync object */ #define f_error(fp) ((fp)->err)
void ff_rel_grant (_SYNC_t sobj); /* Unlock sync object */ #define f_tell(fp) ((fp)->fptr)
int ff_del_syncobj (_SYNC_t sobj); /* Delete a sync object */ #define f_size(fp) ((fp)->obj.objsize)
#endif #define f_rewind(fp) f_lseek((fp), 0)
#define f_rewinddir(dp) f_readdir((dp), 0)
#ifndef EOF
#define EOF (-1)
/*--------------------------------------------------------------*/ #endif
/* Flags and offset address */
/* File access control and file status flags (FIL.flag) */
/*--------------------------------------------------------------*/
#define FA_READ 0x01 /* Additional user defined functions */
#define FA_OPEN_EXISTING 0x00
/* RTC function */
#if !_FS_READONLY #if !_FS_READONLY && !_FS_NORTC
#define FA_WRITE 0x02 DWORD get_fattime (void);
#define FA_CREATE_NEW 0x04 #endif
#define FA_CREATE_ALWAYS 0x08
#define FA_OPEN_ALWAYS 0x10 /* Unicode support functions */
#define FA__WRITTEN 0x20 #if _USE_LFN != 0 /* Unicode - OEM code conversion */
#define FA__DIRTY 0x40 WCHAR ff_convert (WCHAR chr, UINT dir); /* OEM-Unicode bidirectional conversion */
#endif WCHAR ff_wtoupper (WCHAR chr); /* Unicode upper-case conversion */
#if _USE_LFN == 3 /* Memory functions */
void* ff_memalloc (UINT msize); /* Allocate memory block */
/* FAT sub type (FATFS.fs_type) */ void ff_memfree (void* mblock); /* Free memory block */
#endif
#define FS_FAT12 1 #endif
#define FS_FAT16 2
#define FS_FAT32 3 /* Sync functions */
#if _FS_REENTRANT
int ff_cre_syncobj (BYTE vol, _SYNC_t* sobj); /* Create a sync object */
/* File attribute bits for directory entry */ int ff_req_grant (_SYNC_t sobj); /* Lock sync object */
void ff_rel_grant (_SYNC_t sobj); /* Unlock sync object */
#define AM_RDO 0x01 /* Read only */ int ff_del_syncobj (_SYNC_t sobj); /* Delete a sync object */
#define AM_HID 0x02 /* Hidden */ #endif
#define AM_SYS 0x04 /* System */
#define AM_VOL 0x08 /* Volume label */
#define AM_LFN 0x0F /* LFN entry */
#define AM_DIR 0x10 /* Directory */
#define AM_ARC 0x20 /* Archive */ /*--------------------------------------------------------------*/
#define AM_MASK 0x3F /* Mask of defined bits */ /* Flags and offset address */
/* Fast seek feature */ /* File access control and file status flags (FIL.flag) */
#define CREATE_LINKMAP 0xFFFFFFFF
#define FA_READ 0x01
#define FA_WRITE 0x02
#define FA_OPEN_EXISTING 0x00
/*--------------------------------*/ #define FA_CREATE_NEW 0x04
/* Multi-byte word access macros */ #define FA_CREATE_ALWAYS 0x08
#define FA_OPEN_ALWAYS 0x10
#if _WORD_ACCESS == 1 /* Enable word access to the FAT structure */ #define _FA_MODIFIED 0x20
#define LD_WORD(ptr) (WORD)(*(WORD*)(BYTE*)(ptr)) #define _FA_DIRTY 0x40
#define LD_DWORD(ptr) (DWORD)(*(DWORD*)(BYTE*)(ptr))
#define ST_WORD(ptr,val) *(WORD*)(BYTE*)(ptr)=(WORD)(val)
#define ST_DWORD(ptr,val) *(DWORD*)(BYTE*)(ptr)=(DWORD)(val) /* FAT sub type (FATFS.fs_type) */
#else /* Use byte-by-byte access to the FAT structure */
#define LD_WORD(ptr) (WORD)(((WORD)*((BYTE*)(ptr)+1)<<8)|(WORD)*(BYTE*)(ptr)) #define FS_FAT12 1
#define LD_DWORD(ptr) (DWORD)(((DWORD)*((BYTE*)(ptr)+3)<<24)|((DWORD)*((BYTE*)(ptr)+2)<<16)|((WORD)*((BYTE*)(ptr)+1)<<8)|*(BYTE*)(ptr)) #define FS_FAT16 2
#define ST_WORD(ptr,val) *(BYTE*)(ptr)=(BYTE)(val); *((BYTE*)(ptr)+1)=(BYTE)((WORD)(val)>>8) #define FS_FAT32 3
#define ST_DWORD(ptr,val) *(BYTE*)(ptr)=(BYTE)(val); *((BYTE*)(ptr)+1)=(BYTE)((WORD)(val)>>8); *((BYTE*)(ptr)+2)=(BYTE)((DWORD)(val)>>16); *((BYTE*)(ptr)+3)=(BYTE)((DWORD)(val)>>24) #define FS_EXFAT 4
#endif
#ifdef __cplusplus /* File attribute bits for directory entry */
}
#endif #define AM_RDO 0x01 /* Read only */
#define AM_HID 0x02 /* Hidden */
#endif /* _FATFS */ #define AM_SYS 0x04 /* System */
#define AM_VOL 0x08 /* Volume label */
#define AM_LFN 0x0F /* LFN entry */
#define AM_DIR 0x10 /* Directory */
#define AM_ARC 0x20 /* Archive */
#define AM_MASK 0x3F /* Mask of defined bits */
/* Fast seek controls */
#define CREATE_LINKMAP ((FSIZE_t)0 - 1)
#ifdef __cplusplus
}
#endif
#endif /* _FATFS */

View File

@@ -1,271 +1,266 @@
/*---------------------------------------------------------------------------/ /*---------------------------------------------------------------------------/
/ FatFs - FAT file system module configuration file R0.11 (C)ChaN, 2015 / FatFs - FAT file system module configuration file R0.12 (C)ChaN, 2016
/---------------------------------------------------------------------------*/ /---------------------------------------------------------------------------*/
#define _FFCONF 32020 /* Revision ID */ #define _FFCONF 88100 /* Revision ID */
/*---------------------------------------------------------------------------/ /*---------------------------------------------------------------------------/
/ Functions and Buffer Configurations / Function Configurations
/---------------------------------------------------------------------------*/ /---------------------------------------------------------------------------*/
#define _FS_TINY 0 #define _FS_READONLY 1
/* This option switches tiny buffer configuration. (0:Normal or 1:Tiny) /* This option switches read-only configuration. (0:Read/Write or 1:Read-only)
/ At the tiny configuration, size of the file object (FIL) is reduced _MAX_SS / Read-only configuration removes writing API functions, f_write(), f_sync(),
/ bytes. Instead of private sector buffer eliminated from the file object, / f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree()
/ common sector buffer in the file system object (FATFS) is used for the file / and optional writing functions as well. */
/ data transfer. */
#define _FS_MINIMIZE 1
#define _FS_READONLY 1 /* This option defines minimization level to remove some basic API functions.
/* This option switches read-only configuration. (0:Read/Write or 1:Read-only) /
/ Read-only configuration removes writing API functions, f_write(), f_sync(), / 0: All basic functions are enabled.
/ f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree() / 1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_truncate() and f_rename()
/ and optional writing functions as well. */ / are removed.
/ 2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1.
/ 3: f_lseek() function is removed in addition to 2. */
#define _FS_MINIMIZE 3
/* This option defines minimization level to remove some basic API functions.
/ #define _USE_STRFUNC 0
/ 0: All basic functions are enabled. /* This option switches string functions, f_gets(), f_putc(), f_puts() and
/ 1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_chmod(), f_utime(), / f_printf().
/ f_truncate() and f_rename() function are removed. /
/ 2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1. / 0: Disable string functions.
/ 3: f_lseek() function is removed in addition to 2. */ / 1: Enable without LF-CRLF conversion.
/ 2: Enable with LF-CRLF conversion. */
#define _USE_STRFUNC 0
/* This option switches string functions, f_gets(), f_putc(), f_puts() and #define _USE_FIND 1
/ f_printf(). /* This option switches filtered directory read functions, f_findfirst() and
/ / f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */
/ 0: Disable string functions.
/ 1: Enable without LF-CRLF conversion.
/ 2: Enable with LF-CRLF conversion. */ #define _USE_MKFS 0
/* This option switches f_mkfs() function. (0:Disable or 1:Enable) */
#define _USE_FIND 0
/* This option switches filtered directory read feature and related functions, #define _USE_FASTSEEK 0
/ f_findfirst() and f_findnext(). (0:Disable or 1:Enable) */ /* This option switches fast seek function. (0:Disable or 1:Enable) */
#define _USE_MKFS 0 #define _USE_EXPAND 0
/* This option switches f_mkfs() function. (0:Disable or 1:Enable) */ /* This option switches f_expand function. (0:Disable or 1:Enable) */
#define _USE_FASTSEEK 0 #define _USE_CHMOD 0
/* This option switches fast seek feature. (0:Disable or 1:Enable) */ /* This option switches attribute manipulation functions, f_chmod() and f_utime().
/ (0:Disable or 1:Enable) Also _FS_READONLY needs to be 0 to enable this option. */
#define _USE_LABEL 0
/* This option switches volume label functions, f_getlabel() and f_setlabel(). #define _USE_LABEL 0
/ (0:Disable or 1:Enable) */ /* This option switches volume label functions, f_getlabel() and f_setlabel().
/ (0:Disable or 1:Enable) */
#define _USE_FORWARD 0
/* This option switches f_forward() function. (0:Disable or 1:Enable) #define _USE_FORWARD 0
/ To enable it, also _FS_TINY need to be set to 1. */ /* This option switches f_forward() function. (0:Disable or 1:Enable)
/ To enable it, also _FS_TINY need to be 1. */
/*---------------------------------------------------------------------------/
/ Locale and Namespace Configurations /*---------------------------------------------------------------------------/
/---------------------------------------------------------------------------*/ / Locale and Namespace Configurations
/---------------------------------------------------------------------------*/
#define _CODE_PAGE 437
/* This option specifies the OEM code page to be used on the target system. #define _CODE_PAGE 1
/ Incorrect setting of the code page can cause a file open failure. /* 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.
/ 1 - ASCII (No extended character. Non-LFN cfg. only) /
/ 437 - U.S. / 1 - ASCII (No extended character. Non-LFN cfg. only)
/ 720 - Arabic / 437 - U.S.
/ 737 - Greek / 720 - Arabic
/ 775 - Baltic / 737 - Greek
/ 850 - Multilingual Latin 1 / 771 - KBL
/ 852 - Latin 2 / 775 - Baltic
/ 855 - Cyrillic / 850 - Latin 1
/ 857 - Turkish / 852 - Latin 2
/ 858 - Multilingual Latin 1 + Euro / 855 - Cyrillic
/ 862 - Hebrew / 857 - Turkish
/ 866 - Russian / 860 - Portuguese
/ 874 - Thai / 861 - Icelandic
/ 932 - Japanese Shift_JIS (DBCS) / 862 - Hebrew
/ 936 - Simplified Chinese GBK (DBCS) / 863 - Canadian French
/ 949 - Korean (DBCS) / 864 - Arabic
/ 950 - Traditional Chinese Big5 (DBCS) / 865 - Nordic
*/ / 866 - Russian
/ 869 - Greek 2
/ 932 - Japanese (DBCS)
#define _USE_LFN 2 / 936 - Simplified Chinese (DBCS)
#define _MAX_LFN 255 / 949 - Korean (DBCS)
/* The _USE_LFN option switches the LFN feature. / 950 - Traditional Chinese (DBCS)
/ */
/ 0: Disable LFN feature. _MAX_LFN has no effect.
/ 1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe.
/ 2: Enable LFN with dynamic working buffer on the STACK. #define _USE_LFN 0
/ 3: Enable LFN with dynamic working buffer on the HEAP. #define _MAX_LFN 255
/ /* The _USE_LFN switches the support of long file name (LFN).
/ When enable the LFN feature, Unicode handling functions (option/unicode.c) must /
/ be added to the project. The LFN working buffer occupies (_MAX_LFN + 1) * 2 bytes. / 0: Disable support of LFN. _MAX_LFN has no effect.
/ When use stack for the working buffer, take care on stack overflow. When use heap / 1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe.
/ memory for the working buffer, memory management functions, ff_memalloc() and / 2: Enable LFN with dynamic working buffer on the STACK.
/ ff_memfree(), must be added to the project. */ / 3: Enable LFN with dynamic working buffer on the HEAP.
/
/ To enable the LFN, Unicode handling functions (option/unicode.c) must be added
#define _LFN_UNICODE 0 / to the project. The working buffer occupies (_MAX_LFN + 1) * 2 bytes and
/* This option switches character encoding on the API. (0:ANSI/OEM or 1:Unicode) / additional 608 bytes at exFAT enabled. _MAX_LFN can be in range from 12 to 255.
/ To use Unicode string for the path name, enable LFN feature and set _LFN_UNICODE / It should be set 255 to support full featured LFN operations.
/ to 1. This option also affects behavior of string I/O functions. */ / When use stack for the working buffer, take care on stack overflow. When use heap
/ memory for the working buffer, memory management functions, ff_memalloc() and
/ ff_memfree(), must be added to the project. */
#define _STRF_ENCODE 0
/* 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(). #define _LFN_UNICODE 0
/ /* This option switches character encoding on the API. (0:ANSI/OEM or 1:Unicode)
/ 0: ANSI/OEM / To use Unicode string for the path name, enable LFN and set _LFN_UNICODE = 1.
/ 1: UTF-16LE / This option also affects behavior of string I/O functions. */
/ 2: UTF-16BE
/ 3: UTF-8
/ #define _STRF_ENCODE 3
/ When _LFN_UNICODE is 0, this option has no effect. */ /* When _LFN_UNICODE == 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().
/
#define _FS_RPATH 0 / 0: ANSI/OEM
/* This option configures relative path feature. / 1: UTF-16LE
/ / 2: UTF-16BE
/ 0: Disable relative path feature and remove related functions. / 3: UTF-8
/ 1: Enable relative path feature. f_chdir() and f_chdrive() are available. /
/ 2: f_getcwd() function is available in addition to 1. / This option has no effect when _LFN_UNICODE == 0. */
/
/ Note that directory items read via f_readdir() are affected by this option. */
#define _FS_RPATH 0
/* This option configures support of relative path.
/*---------------------------------------------------------------------------/ /
/ Drive/Volume Configurations / 0: Disable relative path and remove related functions.
/---------------------------------------------------------------------------*/ / 1: Enable relative path. f_chdir() and f_chdrive() are available.
/ 2: f_getcwd() function is available in addition to 1.
#define _VOLUMES 1 */
/* Number of volumes (logical drives) to be used. */
/*---------------------------------------------------------------------------/
#define _STR_VOLUME_ID 0 / Drive/Volume Configurations
#define _VOLUME_STRS "RAM","NAND","CF","SD1","SD2","USB1","USB2","USB3" /---------------------------------------------------------------------------*/
/* _STR_VOLUME_ID option switches string volume ID feature.
/ When _STR_VOLUME_ID is set to 1, also pre-defined strings can be used as drive #define _VOLUMES 1
/ number in the path name. _VOLUME_STRS defines the drive ID strings for each /* Number of volumes (logical drives) to be used. */
/ logical drives. Number of items must be equal to _VOLUMES. Valid characters for
/ the drive ID strings are: A-Z and 0-9. */
#define _STR_VOLUME_ID 0
#define _VOLUME_STRS "RAM","NAND","CF","SD1","SD2","USB1","USB2","USB3"
#define _MULTI_PARTITION 0 /* _STR_VOLUME_ID switches string support of volume ID.
/* This option switches multi-partition feature. By default (0), each logical drive / When _STR_VOLUME_ID is set to 1, also pre-defined strings can be used as drive
/ number is bound to the same physical drive number and only an FAT volume found on / number in the path name. _VOLUME_STRS defines the drive ID strings for each
/ the physical drive will be mounted. When multi-partition feature is enabled (1), / logical drives. Number of items must be equal to _VOLUMES. Valid characters for
/ each logical drive number is bound to arbitrary physical drive and partition / the drive ID strings are: A-Z and 0-9. */
/ listed in the VolToPart[]. Also f_fdisk() funciton will be available. */
#define _MULTI_PARTITION 0
#define _MIN_SS 512 /* This option switches support of multi-partition on a physical drive.
#define _MAX_SS 512 / By default (0), each logical drive number is bound to the same physical drive
/* These options configure the range of sector size to be supported. (512, 1024, / number and only an FAT volume found on the physical drive will be mounted.
/ 2048 or 4096) Always set both 512 for most systems, all type of memory cards and / When multi-partition is enabled (1), each logical drive number can be bound to
/ harddisk. But a larger value may be required for on-board flash memory and some / arbitrary physical drive and partition listed in the VolToPart[]. Also f_fdisk()
/ type of optical media. When _MAX_SS is larger than _MIN_SS, FatFs is configured / funciton will be available. */
/ to variable sector size and GET_SECTOR_SIZE command must be implemented to the
/ disk_ioctl() function. */
#define _MIN_SS 512
#define _MAX_SS 512
#define _USE_TRIM 0 /* These options configure the range of sector size to be supported. (512, 1024,
/* This option switches ATA-TRIM feature. (0:Disable or 1:Enable) / 2048 or 4096) Always set both 512 for most systems, all type of memory cards and
/ To enable Trim feature, also CTRL_TRIM command should be implemented to the / harddisk. But a larger value may be required for on-board flash memory and some
/ disk_ioctl() function. */ / type of optical media. When _MAX_SS is larger than _MIN_SS, FatFs is configured
/ to variable sector size and GET_SECTOR_SIZE command must be implemented to the
/ disk_ioctl() function. */
#define _FS_NOFSINFO 0
/* If you need to know correct free space on the FAT32 volume, set bit 0 of this
/ option, and f_getfree() function at first time after volume mount will force #define _USE_TRIM 0
/ a full FAT scan. Bit 1 controls the use of last allocated cluster number. /* This option switches support of ATA-TRIM. (0:Disable or 1:Enable)
/ / To enable Trim function, also CTRL_TRIM command should be implemented to the
/ bit0=0: Use free cluster count in the FSINFO if available. / disk_ioctl() function. */
/ bit0=1: Do not trust free cluster count in the FSINFO.
/ bit1=0: Use last allocated cluster number in the FSINFO if available.
/ bit1=1: Do not trust last allocated cluster number in the FSINFO. #define _FS_NOFSINFO 0
*/ /* If you need to know correct free space on the FAT32 volume, set bit 0 of this
/ option, and f_getfree() function at first time after volume mount will force
/ a full FAT scan. Bit 1 controls the use of last allocated cluster number.
/
/*---------------------------------------------------------------------------/ / bit0=0: Use free cluster count in the FSINFO if available.
/ System Configurations / bit0=1: Do not trust free cluster count in the FSINFO.
/---------------------------------------------------------------------------*/ / bit1=0: Use last allocated cluster number in the FSINFO if available.
/ bit1=1: Do not trust last allocated cluster number in the FSINFO.
#define _FS_NORTC 1 */
#define _NORTC_MON 2
#define _NORTC_MDAY 1
#define _NORTC_YEAR 2015
/* 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 / System Configurations
/ the timestamp feature. All objects modified by FatFs will have a fixed timestamp /---------------------------------------------------------------------------*/
/ defined by _NORTC_MON, _NORTC_MDAY and _NORTC_YEAR.
/ When timestamp feature is enabled (_FS_NORTC == 0), get_fattime() function need #define _FS_TINY 0
/ to be added to the project to read current time form RTC. _NORTC_MON, /* This option switches tiny buffer configuration. (0:Normal or 1:Tiny)
/ _NORTC_MDAY and _NORTC_YEAR have no effect. / At the tiny configuration, size of the file object (FIL) is reduced _MAX_SS bytes.
/ These options have no effect at read-only configuration (_FS_READONLY == 1). */ / 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_LOCK 0
/* The _FS_LOCK option switches file lock feature to control duplicated file open #define _FS_EXFAT 0
/ and illegal operation to open objects. This option must be 0 when _FS_READONLY /* This option switches support of exFAT file system in addition to the traditional
/ is 1. / FAT file system. (0:Disable or 1:Enable) To enable exFAT, also LFN must be enabled.
/ / Note that enabling exFAT discards C89 compatibility. */
/ 0: Disable file lock feature. To avoid volume corruption, application program
/ should avoid illegal open, remove and rename to the open objects.
/ >0: Enable file lock feature. The value defines how many files/sub-directories #define _FS_NORTC 1
/ can be opened simultaneously under file lock control. Note that the file #define _NORTC_MON 3
/ lock feature is independent of re-entrancy. */ #define _NORTC_MDAY 1
#define _NORTC_YEAR 2016
/* The option _FS_NORTC switches timestamp functiton. If the system does not have
#define _FS_REENTRANT 0 / any RTC function or valid timestamp is not needed, set _FS_NORTC = 1 to disable
#define _FS_TIMEOUT 1000 / the timestamp function. All objects modified by FatFs will have a fixed timestamp
#define _SYNC_t HANDLE / defined by _NORTC_MON, _NORTC_MDAY and _NORTC_YEAR in local time.
/* The _FS_REENTRANT option switches the re-entrancy (thread safe) of the FatFs / To enable timestamp function (_FS_NORTC = 0), get_fattime() function need to be
/ module itself. Note that regardless of this option, file access to different / added to the project to get current time form real-time clock. _NORTC_MON,
/ volume is always re-entrant and volume control functions, f_mount(), f_mkfs() / _NORTC_MDAY and _NORTC_YEAR have no effect.
/ and f_fdisk() function, are always not re-entrant. Only file/directory access / These options have no effect at read-only configuration (_FS_READONLY = 1). */
/ to the same volume is under control of this feature.
/
/ 0: Disable re-entrancy. _FS_TIMEOUT and _SYNC_t have no effect. #define _FS_LOCK 0
/ 1: Enable re-entrancy. Also user provided synchronization handlers, /* The option _FS_LOCK switches file lock function to control duplicated file open
/ ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj() / and illegal operation to open objects. This option must be 0 when _FS_READONLY
/ function, must be added to the project. Samples are available in / is 1.
/ option/syscall.c. /
/ / 0: Disable file lock function. To avoid volume corruption, application program
/ The _FS_TIMEOUT defines timeout period in unit of time tick. / should avoid illegal open, remove and rename to the open objects.
/ The _SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*, / >0: Enable file lock function. The value defines how many files/sub-directories
/ SemaphoreHandle_t and etc.. A header file for O/S definitions needs to be / can be opened simultaneously under file lock control. Note that the file
/ included somewhere in the scope of ff.c. */ / lock control is independent of re-entrancy. */
#define _WORD_ACCESS 0 #define _FS_REENTRANT 0
/* The _WORD_ACCESS option is an only platform dependent option. It defines #define _FS_TIMEOUT 1000
/ which access method is used to the word data on the FAT volume. #define _SYNC_t HANDLE
/ /* The option _FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs
/ 0: Byte-by-byte access. Always compatible with all platforms. / module itself. Note that regardless of this option, file access to different
/ 1: Word access. Do not choose this unless under both the following conditions. / volume is always re-entrant and volume control functions, f_mount(), f_mkfs()
/ / and f_fdisk() function, are always not re-entrant. Only file/directory access
/ * Address misaligned memory access is always allowed to ALL instructions. / to the same volume is under control of this function.
/ * Byte order on the memory is little-endian. /
/ / 0: Disable re-entrancy. _FS_TIMEOUT and _SYNC_t have no effect.
/ If it is the case, _WORD_ACCESS can also be set to 1 to reduce code size. / 1: Enable re-entrancy. Also user provided synchronization handlers,
/ Following table shows allowable settings of some processor types. / ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj()
/ / function, must be added to the project. Samples are available in
/ ARM7TDMI 0 *2 ColdFire 0 *1 V850E 0 *2 / option/syscall.c.
/ Cortex-M3 0 *3 Z80 0/1 V850ES 0/1 /
/ Cortex-M0 0 *2 x86 0/1 TLCS-870 0/1 / The _FS_TIMEOUT defines timeout period in unit of time tick.
/ AVR 0/1 RX600(LE) 0/1 TLCS-900 0/1 / The _SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*,
/ AVR32 0 *1 RL78 0 *2 R32C 0 *2 / SemaphoreHandle_t and etc.. A header file for O/S definitions needs to be
/ PIC18 0/1 SH-2 0 *1 M16C 0/1 / included somewhere in the scope of ff.c. */
/ PIC24 0 *2 H8S 0 *1 MSP430 0 *2
/ PIC32 0 *1 H8/300H 0 *1 8051 0/1
/ /*--- End of configuration options ---*/
/ *1:Big-endian.
/ *2:Unaligned memory access is not supported.
/ *3:Some compilers generate LDM/STM for mem_cpy function.
*/

View File

@@ -1,33 +1,38 @@
/*-------------------------------------------*/ /*-------------------------------------------*/
/* Integer type definitions for FatFs module */ /* Integer type definitions for FatFs module */
/*-------------------------------------------*/ /*-------------------------------------------*/
#ifndef _FF_INTEGER #ifndef _FF_INTEGER
#define _FF_INTEGER #define _FF_INTEGER
#ifdef _WIN32 /* FatFs development platform */ #ifdef _WIN32 /* FatFs development platform */
#include <windows.h> #include <windows.h>
#include <tchar.h> #include <tchar.h>
typedef unsigned __int64 QWORD;
#else /* Embedded platform */
/* This type MUST be 8 bit */ #else /* Embedded platform */
typedef unsigned char BYTE;
/* These types MUST be 16-bit or 32-bit */
/* These types MUST be 16 bit */ typedef int INT;
typedef short SHORT; typedef unsigned int UINT;
typedef unsigned short WORD;
typedef unsigned short WCHAR; /* This type MUST be 8-bit */
typedef unsigned char BYTE;
/* These types MUST be 16 bit or 32 bit */
typedef int INT; /* These types MUST be 16-bit */
typedef unsigned int UINT; typedef short SHORT;
typedef unsigned short WORD;
/* These types MUST be 32 bit */ typedef unsigned short WCHAR;
typedef long LONG;
typedef unsigned long DWORD; /* These types MUST be 32-bit */
typedef long LONG;
#endif typedef unsigned long DWORD;
#endif /* This type MUST be 64-bit (Remove this for C89 compatibility) */
typedef unsigned long long QWORD;
#endif
#endif

View File

@@ -5,8 +5,7 @@
#include "sdmmc.h" #include "sdmmc.h"
#include "delay.h" #include "delay.h"
struct mmcdevice handleNAND; static struct mmcdevice handleSD;
struct mmcdevice handleSD;
static inline u16 sdmmc_read16(u16 reg) { static inline u16 sdmmc_read16(u16 reg) {
return *(vu16*)(SDMMC_BASE + reg); return *(vu16*)(SDMMC_BASE + reg);
@@ -38,13 +37,6 @@ static inline void setckl(u32 data)
sdmmc_mask16(REG_SDCLKCTL, 0x0, 0x100); sdmmc_mask16(REG_SDCLKCTL, 0x0, 0x100);
} }
mmcdevice *getMMCDevice(int drive)
{
if(drive==0) return &handleNAND;
return &handleSD;
}
static u32 __attribute__((noinline)) geterror(struct mmcdevice *ctx) static u32 __attribute__((noinline)) geterror(struct mmcdevice *ctx)
{ {
return (ctx->error << 29) >> 31; return (ctx->error << 29) >> 31;
@@ -150,20 +142,6 @@ static void __attribute__((noinline)) sdmmc_send_command(struct mmcdevice *ctx,
} }
} }
u32 __attribute__((noinline)) sdmmc_sdcard_writesectors(u32 sector_no, u32 numsectors, vu8 *in)
{
if (handleSD.isSDHC == 0)
sector_no <<= 9;
inittarget(&handleSD);
sdmmc_write16(REG_SDSTOP,0x100);
sdmmc_write16(REG_SDBLKCOUNT,numsectors);
handleSD.data = in;
handleSD.size = numsectors << 9;
sdmmc_send_command(&handleSD,0x52C19,sector_no);
return geterror(&handleSD);
}
u32 __attribute__((noinline)) sdmmc_sdcard_readsectors(u32 sector_no, u32 numsectors, vu8 *out) u32 __attribute__((noinline)) sdmmc_sdcard_readsectors(u32 sector_no, u32 numsectors, vu8 *out)
{ {
if (handleSD.isSDHC == 0) if (handleSD.isSDHC == 0)
@@ -178,38 +156,6 @@ u32 __attribute__((noinline)) sdmmc_sdcard_readsectors(u32 sector_no, u32 numsec
return geterror(&handleSD); return geterror(&handleSD);
} }
u32 __attribute__((noinline)) sdmmc_nand_readsectors(u32 sector_no, u32 numsectors, vu8 *out)
{
if (handleNAND.isSDHC == 0)
sector_no <<= 9;
inittarget(&handleNAND);
sdmmc_write16(REG_SDSTOP,0x100);
sdmmc_write16(REG_SDBLKCOUNT,numsectors);
handleNAND.data = out;
handleNAND.size = numsectors << 9;
sdmmc_send_command(&handleNAND,0x33C12,sector_no);
inittarget(&handleSD);
return geterror(&handleNAND);
}
u32 __attribute__((noinline)) sdmmc_nand_writesectors(u32 sector_no, u32 numsectors, vu8 *in) //experimental
{
if (handleNAND.isSDHC == 0)
sector_no <<= 9;
inittarget(&handleNAND);
sdmmc_write16(REG_SDSTOP,0x100);
sdmmc_write16(REG_SDBLKCOUNT,numsectors);
handleNAND.data = in;
handleNAND.size = numsectors << 9;
sdmmc_send_command(&handleNAND,0x52C19,sector_no);
inittarget(&handleSD);
return geterror(&handleNAND);
}
static u32 calcSDSize(u8* csd, int type) static u32 calcSDSize(u8* csd, int type)
{ {
u32 result = 0; u32 result = 0;
@@ -241,14 +187,6 @@ static u32 calcSDSize(u8* csd, int type)
static void InitSD() static void InitSD()
{ {
//NAND
handleNAND.isSDHC = 0;
handleNAND.SDOPT = 0;
handleNAND.res = 0;
handleNAND.initarg = 1;
handleNAND.clk = 0x80;
handleNAND.devicenumber = 1;
//SD //SD
handleSD.isSDHC = 0; handleSD.isSDHC = 0;
handleSD.SDOPT = 0; handleSD.SDOPT = 0;
@@ -281,56 +219,6 @@ static void InitSD()
inittarget(&handleSD); inittarget(&handleSD);
} }
static int Nand_Init()
{
inittarget(&handleNAND);
ioDelay(0xF000);
sdmmc_send_command(&handleNAND,0,0);
do {
do {
sdmmc_send_command(&handleNAND,0x10701,0x100000);
} while ( !(handleNAND.error & 1) );
} while((handleNAND.ret[0] & 0x80000000) == 0);
sdmmc_send_command(&handleNAND,0x10602,0x0);
if (handleNAND.error & 0x4) return -1;
sdmmc_send_command(&handleNAND,0x10403,handleNAND.initarg << 0x10);
if (handleNAND.error & 0x4) return -1;
sdmmc_send_command(&handleNAND,0x10609,handleNAND.initarg << 0x10);
if (handleNAND.error & 0x4) return -1;
handleNAND.total_size = calcSDSize((u8*)&handleNAND.ret[0],0);
handleNAND.clk = 1;
setckl(1);
sdmmc_send_command(&handleNAND,0x10407,handleNAND.initarg << 0x10);
if (handleNAND.error & 0x4) return -1;
handleNAND.SDOPT = 1;
sdmmc_send_command(&handleNAND,0x10506,0x3B70100);
if (handleNAND.error & 0x4) return -1;
sdmmc_send_command(&handleNAND,0x10506,0x3B90100);
if (handleNAND.error & 0x4) return -1;
sdmmc_send_command(&handleNAND,0x1040D,handleNAND.initarg << 0x10);
if (handleNAND.error & 0x4) return -1;
sdmmc_send_command(&handleNAND,0x10410,0x200);
if (handleNAND.error & 0x4) return -1;
handleNAND.clk |= 0x200;
inittarget(&handleSD);
return 0;
}
static int SD_Init() static int SD_Init()
{ {
inittarget(&handleSD); inittarget(&handleSD);
@@ -395,10 +283,8 @@ static int SD_Init()
return 0; return 0;
} }
int sdmmc_sdcard_init() void sdmmc_sdcard_init()
{ {
InitSD(); InitSD();
int result = Nand_Init(); SD_Init();
return result | SD_Init(); }
}

View File

@@ -118,10 +118,5 @@ typedef struct mmcdevice {
u32 res; u32 res;
} mmcdevice; } mmcdevice;
int sdmmc_sdcard_init(); void 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);
mmcdevice *getMMCDevice(int drive);
u32 sdmmc_nand_readsectors(u32 sector_no, u32 numsectors, vu8 *out);
u32 sdmmc_nand_writesectors(u32 sector_no, u32 numsectors, vu8 *in);

View File

@@ -3,37 +3,56 @@
#include "fatfs/ff.h" #include "fatfs/ff.h"
#define PAYLOAD_ADDRESS 0x23F00000 #define PAYLOAD_ADDRESS 0x23F00000
#define LOAD_PAYLOAD(a) loadPayload(a "_*.bin")
static u32 loadPayload(const char *pattern)
{
char path[30] = "/luma/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[14] = '/';
u32 i;
for(i = 0; info.fname[i]; i++)
path[15 + i] = info.fname[i];
path[15 + i] = '\0';
static u32 loadPayload(const char *path){
FIL payload; FIL payload;
unsigned int br; unsigned int br;
if(f_open(&payload, path, FA_READ) == FR_OK)
{
f_read(&payload, (void *)PAYLOAD_ADDRESS, f_size(&payload), &br);
f_close(&payload);
return 1; f_open(&payload, path, FA_READ);
} f_read(&payload, (void *)PAYLOAD_ADDRESS, f_size(&payload), &br);
f_close(&payload);
return 0; return 1;
} }
void main(void){ void main(void)
{
FATFS fs; FATFS fs;
f_mount(&fs, "0:", 1); f_mount(&fs, "0:", 1);
//Get pressed buttons //Get pressed buttons
u16 pressed = HID_PAD; u32 pressed = HID_PAD;
if(((pressed & BUTTON_B) && loadPayload("/aurei/payloads/b.bin")) || if(((pressed & BUTTON_RIGHT) && LOAD_PAYLOAD("right")) ||
((pressed & BUTTON_X) && loadPayload("/aurei/payloads/x.bin")) || ((pressed & BUTTON_LEFT) && LOAD_PAYLOAD("left")) ||
((pressed & BUTTON_Y) && loadPayload("/aurei/payloads/y.bin")) || ((pressed & BUTTON_UP) && LOAD_PAYLOAD("up")) ||
((pressed & BUTTON_SELECT) && loadPayload("/aurei/payloads/select.bin")) || ((pressed & BUTTON_DOWN) && LOAD_PAYLOAD("down")) ||
((pressed & BUTTON_START) && loadPayload("/aurei/payloads/start.bin")) || ((pressed & BUTTON_X) && LOAD_PAYLOAD("x")) ||
((pressed & BUTTON_RIGHT) && loadPayload("/aurei/payloads/right.bin")) || ((pressed & BUTTON_Y) && LOAD_PAYLOAD("y")) ||
((pressed & BUTTON_LEFT) && loadPayload("/aurei/payloads/left.bin")) || ((pressed & BUTTON_R1) && LOAD_PAYLOAD("r")) ||
((pressed & BUTTON_UP) && loadPayload("/aurei/payloads/up.bin")) || ((pressed & BUTTON_A) && LOAD_PAYLOAD("a")) ||
((pressed & BUTTON_DOWN) && loadPayload("/aurei/payloads/down.bin")) || ((pressed & BUTTON_SELECT) && LOAD_PAYLOAD("sel")) ||
loadPayload("/aurei/payloads/default.bin")) LOAD_PAYLOAD("def"))
((void (*)())PAYLOAD_ADDRESS)(); ((void (*)())PAYLOAD_ADDRESS)();
} }

View File

@@ -2,17 +2,10 @@
.align 4 .align 4
.global _start .global _start
_start: _start:
@ Fix payloads like Decrypt9
mov r0, #0x5
mcr p15, 0, r0, c3, c0, 0 @ data bufferable
@ Flush caches @ Flush caches
mov r0, #0 mov r0, #0
mcr p15, 0, r0, c7, c5, 0 @ flush I-cache mcr p15, 0, r0, c7, c5, 0 @ flush I-cache
mcr p15, 0, r0, c7, c6, 0 @ flush D-cache mcr p15, 0, r0, c7, c6, 0 @ flush D-cache
mcr p15, 0, r0, c7, c10, 4 @ drain write buffer mcr p15, 0, r0, c7, c10, 4 @ drain write buffer
bl main b main
.die:
b .die

View File

@@ -1,9 +1,3 @@
/*
* types.h
* by Reisyukaku
* Copyright (c) 2015 All Rights Reserved
*/
#pragma once #pragma once
#include <stdint.h> #include <stdint.h>

View File

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

View File

@@ -1,221 +1,148 @@
.arm.little .arm.little
byteswritten equ 0x2000E000 payload_addr equ 0x23F00000 ; Brahma payload address.
kernelCode equ 0x080F0000 payload_maxsize equ 0x20000 ; Maximum size for the payload (200 KB will do).
buffer equ 0x24000000
fileOpen equ 0x4E45504F ;dummy
.create "reboot.bin", 0 .create "reboot.bin", 0
.arm .arm
//Code jumps here right after the sprintf call ; Interesting registers and locations to keep in mind, set before this code is ran:
process9Reboot: ; - sp + 0x3A8 - 0x70: FIRM path in exefs.
doPxi: ; - r7 (which is sp + 0x3A8 - 0x198): Reserved space for file handle
ldr r4, =0x44846 ; - *(sp + 0x3A8 - 0x198) + 0x28: fread function.
ldr r0, =0x10008000
readPxiLoop1:
ldrh r1, [r0,#4]
.word 0xE1B01B81 //lsls r1, r1, #0x17
bmi readPxiLoop1
ldr r0, [r0,#0xC]
cmp r0, r4
bne doPxi
GetFirmPath:
add r0, sp, #0x3A8-0x70+0x24
ldr r1, [r0], #4
ldr r2, =0x00300030
cmp r1, r2
ldreq r1, [r0], #4
ldreq r2, =0x002F0032
cmpeq r1, r2
OpenFirm:
ldreq r1, =(FileName - OpenFirm - 12)
addeq r1, pc
addne r1, sp, #0x3A8-0x70
moveq r2, #1
movne r2, #0
str r2, [externalFirm]
mov r2, #1
add r0, r7, #8
ldr r6, =fileOpen
blx r6
SeekFirm:
ldr r0, [externalFirm]
cmp r0, #1
moveq r0, r7
ldreq r1, =byteswritten
ldreq r2, =buffer
ldreq r3, =0x0
ldreq r6, [sp,#0x3A8-0x198]
ldreq r6, [r6,#0x28] //fread function stored here
blxeq r6
ReadFirm:
mov r0, r7
ldr r1, =byteswritten
ldr r2, =buffer
ldr r3, =0x200000
ldr r6, [sp,#0x3A8-0x198]
ldr r6, [r6,#0x28] //fread function stored here
blx r6
KernelSetState: pxi_wait_recv:
mov r2, #0 ldr r2, =0x44846
mov r3, r2 ldr r0, =0x10008000
mov r1, r2 readPxiLoop1:
mov r0, r2 ldrh r1, [r0, #4]
.word 0xEF00007C //SVC 0x7C lsls r1, #0x17
bmi readPxiLoop1
ldr r0, [r0, #0xC]
cmp r0, r2
bne pxi_wait_recv
GoToReboot: mov r4, #0
ldr r0, =(KernelCodeStart - GoToReboot - 12) adr r1, bin_fname
add r0, pc b open_payload
ldr r1, =kernelCode
ldr r2, =0x300
bl Memcpy
ldr r0, =kernelCode
.word 0xEF00007B //SVC 0x7B
InfiniteLoop: fallback:
b InfiniteLoop mov r4, #1
adr r1, dat_fname
Memcpy: open_payload:
MOV R12, LR ; Open file
STMFD SP!, {R0-R4} add r0, r7, #8
ADD R2, R2, R0 mov r2, #1
ldr r6, [fopen]
orr r6, 1
blx r6
cmp r0, #0
bne fallback ; If the .bin is not found, try the .dat.
memcpyLoop: read_payload:
LDR R3, [R0],#4 ; Read file
STR R3, [R1],#4 mov r0, r7
CMP R0, R2 adr r1, bytes_read
BLT memcpyLoop ldr r2, =payload_addr
LDMFD SP!, {R0-R4} cmp r4, #0
MOV LR, R12 movne r3, #0x12000 ; Skip the first 0x12000 bytes.
BX LR moveq r3, payload_maxsize
ldr r6, [sp, #0x3A8-0x198]
ldr r6, [r6, #0x28]
blx r6
cmp r4, #0
movne r4, #0
bne read_payload ; Go read the real payload.
FileName: add r0, sp, #0x3A8 - 0x70
.dcw "sdmc:/aurei/patched_firmware_sys.bin" ldr r0, [r0, #0x27]
.word 0x0 ldr r1, =payload_addr + 4
str r0, [r1] ; Copy the last digits of the wanted firm to the 5th byte of the payload.
externalFirm: ; Set kernel state
.word 0x2000A000 mov r0, #0
mov r1, #0
mov r2, #0
mov r3, #0
swi 0x7C
goto_reboot:
; Jump to reboot code
ldr r0, =(kernelcode_start - goto_reboot - 12)
add r0, pc
swi 0x7B
die:
b die
bytes_read: .word 0
fopen: .ascii "OPEN"
.pool .pool
bin_fname: .dcw "sdmc:/arm9loaderhax.bin"
.word 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
dat_fname: .dcw "sdmc:/Luma3DS.dat"
.word 0
// Kernel Code
.align 4 .align 4
KernelCodeStart: kernelcode_start:
memorySetting: ; Set MPU settings
MRC p15, 0, R0,c2,c0, 0 mrc p15, 0, r0, c2, c0, 0 ; dcacheable
MRC p15, 0, R12,c2,c0, 1 mrc p15, 0, r12, c2, c0, 1 ; icacheable
MRC p15, 0, R1,c3,c0, 0 mrc p15, 0, r1, c3, c0, 0 ; write bufferable
MRC p15, 0, R2,c5,c0, 2 mrc p15, 0, r2, c5, c0, 2 ; daccess
MRC p15, 0, R3,c5,c0, 3 mrc p15, 0, r3, c5, c0, 3 ; iaccess
LDR R4, =0x18000035 ldr r4, =0x18000035 ; 0x18000000 128M
BIC R2, R2, #0xF0000 bic r2, r2, #0xF0000 ; unprotect region 4
BIC R3, R3, #0xF0000 bic r3, r3, #0xF0000 ; unprotect region 4
ORR R0, R0, #0x10 orr r0, r0, #0x10 ; dcacheable region 4
ORR R2, R2, #0x30000 orr r2, r2, #0x30000 ; region 4 r/w
ORR R3, R3, #0x30000 orr r3, r3, #0x30000 ; region 4 r/w
ORR R12, R12, #0x10 orr r12, r12, #0x10 ; icacheable region 4
ORR R1, R1, #0x10 orr r1, r1, #0x10 ; write bufferable region 4
MCR p15, 0, R0,c2,c0, 0 mcr p15, 0, r0, c2, c0, 0
MCR p15, 0, R12,c2,c0, 1 mcr p15, 0, r12, c2, c0, 1
MCR p15, 0, R1,c3,c0, 0 mcr p15, 0, r1, c3, c0, 0 ; write bufferable
MCR p15, 0, R2,c5,c0, 2 mcr p15, 0, r2, c5, c0, 2 ; daccess
MCR p15, 0, R3,c5,c0, 3 mcr p15, 0, r3, c5, c0, 3 ; iaccess
MCR p15, 0, R4,c6,c4, 0 mcr p15, 0, r4, c6, c4, 0 ; region 4 (hmmm)
MRC p15, 0, R0,c2,c0, 0
MRC p15, 0, R1,c2,c0, 1
MRC p15, 0, R2,c3,c0, 0
ORR R0, R0, #0x20
ORR R1, R1, #0x20
ORR R2, R2, #0x20
MCR p15, 0, R0,c2,c0, 0
MCR p15, 0, R1,c2,c0, 1
MCR p15, 0, R2,c3,c0, 0
copyFirmPartitions: mrc p15, 0, r0, c2, c0, 0 ; dcacheable
LDR R4, =buffer mrc p15, 0, r1, c2, c0, 1 ; icacheable
ADD R3, R4, #0x40 mrc p15, 0, r2, c3, c0, 0 ; write bufferable
LDR R0, [R3] orr r0, r0, #0x20 ; dcacheable region 5
ADD R0, R0, R4 orr r1, r1, #0x20 ; icacheable region 5
LDR R1, [R3,#4] orr r2, r2, #0x20 ; write bufferable region 5
LDR R2, [R3,#8] mcr p15, 0, r0, c2, c0, 0 ; dcacheable
bl KernelMemcpy mcr p15, 0, r1, c2, c0, 1 ; icacheable
mcr p15, 0, r2, c3, c0, 0 ; write bufferable
ADD R3, R4, #0x70
LDR R0, [R3] ; Flush cache
ADD R0, R0, R4 mov r2, #0
LDR R1, [R3,#4] mov r1, r2
LDR R2, [R3,#8] flush_cache:
bl KernelMemcpy mov r0, #0
mov r3, r2, lsl #30
ADD R3, R4, #0xA0 flush_cache_inner_loop:
LDR R0, [R3] orr r12, r3, r0, lsl#5
ADD R0, R0, R4 mcr p15, 0, r1, c7, c10, 4 ; drain write buffer
LDR R1, [R3,#4] mcr p15, 0, r12, c7, c14, 2 ; clean and flush dcache entry (index and segment)
LDR R2, [R3,#8] add r0, #1
bl KernelMemcpy cmp r0, #0x20
bcc flush_cache_inner_loop
ADD R3, R4, #0xD0 add r2, #1
LDR R0, [R3] cmp r2, #4
CMP R0, #0 bcc flush_cache
BEQ invalidateDataCache
ADD R0, R0, R4 ; Enable MPU
LDR R1, [R3,#4] ldr r0, =0x42078 ; alt vector select, enable itcm
LDR R2, [R3,#8] mcr p15, 0, r0, c1, c0, 0
bl KernelMemcpy mcr p15, 0, r1, c7, c5, 0 ; flush dcache
mcr p15, 0, r1, c7, c6, 0 ; flush icache
invalidateDataCache: mcr p15, 0, r1, c7, c10, 4 ; drain write buffer
MOV R2, #0
MOV R1, R2 ; Jump to payload
loc_809460C: ldr r0, =payload_addr
MOV R0, #0 bx r0
MOV R3, R2,LSL#30
loc_8094614:
ORR R12, R3, R0,LSL#5
MCR p15, 0, R1,c7,c10, 4
MCR p15, 0, R12,c7,c14, 2
ADD R0, R0, #1
CMP R0, #0x20
BCC loc_8094614
ADD R2, R2, #1
CMP R2, #4
BCC loc_809460C
jumpToEntrypoint:
MCR p15, 0, R1,c7,c10, 4
LDR R0, =0x42078
MCR p15, 0, R0,c1,c0, 0
MCR p15, 0, R1,c7,c5, 0
MCR p15, 0, R1,c7,c6, 0
MCR p15, 0, R1,c7,c10, 4
LDR R4, =buffer
MOV R1, #0x1FFFFFFC
LDR R2, [R4,#8]
STR R2, [R1]
LDR R0, [R4,#0xC]
BX R0
.pool .pool
KernelMemcpy:
MOV R12, LR
STMFD SP!, {R0-R4}
ADD R2, R2, R0
kmemcpyLoop:
LDR R3, [R0],#4
STR R3, [R1],#4
CMP R0, R2
BLT kmemcpyLoop
LDMFD SP!, {R0-R4}
MOV LR, R12
BX LR
.pool
KernelCodeEnd:
.close .close

98
pathchanger/pathchanger.c Normal file
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 a Luma3DS payload?\n", message);
exit(0);
}
int main(int argc, char **argv)
{
if(argc == 1)
{
printf("Usage: %s <Luma3DS 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

@@ -0,0 +1,40 @@
#!/usr/bin/env python
# Requires Python >= 3.2 or >= 2.7
# This is part of Luma3DS
__author__ = "TuxSH"
__copyright__ = "Copyright (c) 2016 TuxSH"
__license__ = "GPLv3"
__version__ = "v1.0"
import argparse
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Changes the path to Luma3DS for reboot patches")
parser.add_argument("payload", help="Path to the Luma3DS payload")
parser.add_argument("new_path", help="New Luma3DS payload path")
args = parser.parse_args()
data = b""
if len(args.new_path) > 37:
raise SystemExit("The new payload path is too large (37 characters max.)")
with open(args.payload, "rb") as f: data = bytearray(f.read())
if len(data) == 0: raise SystemExit("Could not read {0}".format(args.payload))
if len(data) > 0x20000:
raise SystemExit("The input file is too large, are you sure you're using a Luma3DS payload?")
found_index = data.find("sdmc:/".encode("utf-16-le"))
if found_index == -1:
raise SystemExit("The pattern was not found, are you sure you're usinga a Luma3DS payload?")
namebuf = args.new_path.encode("utf-16-le")
namebuf += b'\x00' * (74 - len(namebuf))
data[found_index + 12 : found_index + 12 + 74] = namebuf
with open(args.payload, "wb+") as f: f.write(data)

47
screeninit/Makefile Executable file
View File

@@ -0,0 +1,47 @@
rwildcard = $(foreach d, $(wildcard $1*), $(filter $(subst *, %, $2), $d) $(call rwildcard, $d/, $2))
ifeq ($(strip $(DEVKITARM)),)
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
endif
include $(DEVKITARM)/3ds_rules
CC := arm-none-eabi-gcc
AS := arm-none-eabi-as
LD := arm-none-eabi-ld
OC := arm-none-eabi-objcopy
name := $(shell basename $(CURDIR))
dir_source := source
dir_build := build
ASFLAGS := -mcpu=mpcore -mfloat-abi=hard
CFLAGS := -Wall -Wextra -MMD -MP -mthumb -mthumb-interwork $(ASFLAGS) -fno-builtin -std=c11 -Wno-main -O2 -flto -ffast-math
LDFLAGS := -nostdlib
objects = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \
$(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \
$(call rwildcard, $(dir_source), *.s *.c)))
.PHONY: all
all: $(name).bin
.PHONY: clean
clean:
@rm -rf $(dir_build)
$(name).bin: $(dir_build)/$(name).elf
$(OC) -S -O binary $< $@
$(dir_build)/$(name).elf: $(objects)
$(LINK.o) -T linker.ld $(OUTPUT_OPTION) $^
$(dir_build)/%.o: $(dir_source)/%.c
@mkdir -p "$(@D)"
$(COMPILE.c) $(OUTPUT_OPTION) $<
$(dir_build)/%.o: $(dir_source)/%.s
@mkdir -p "$(@D)"
$(COMPILE.s) $(OUTPUT_OPTION) $<
include $(call rwildcard, $(dir_build), *.d)

12
screeninit/linker.ld Executable file
View File

@@ -0,0 +1,12 @@
ENTRY(_start)
SECTIONS
{
. = 0x24F03000;
.text.start : { *(.text.start) }
.text : { *(.text) }
.data : { *(.data) }
.bss : { *(.bss COMMON) }
.rodata : { *(.rodata) }
. = ALIGN(4);
}

105
screeninit/source/main.c Executable file
View File

@@ -0,0 +1,105 @@
#include "types.h"
void main(void)
{
const u32 brightness[4] = {0x5F, 0x4C, 0x39, 0x26};
u32 brightnessLevel = *(vu32 *)0x24F03008;
vu32 *const arm11 = (u32 *)0x1FFFFFF8;
*(vu32 *)0x10141200 = 0x1007F;
*(vu32 *)0x10202014 = 0x00000001;
*(vu32 *)0x1020200C &= 0xFFFEFFFE;
*(vu32 *)0x10202240 = brightness[brightnessLevel];
*(vu32 *)0x10202A40 = brightness[brightnessLevel];
*(vu32 *)0x10202244 = 0x1023E;
*(vu32 *)0x10202A44 = 0x1023E;
// Top screen
*(vu32 *)0x10400400 = 0x000001c2;
*(vu32 *)0x10400404 = 0x000000d1;
*(vu32 *)0x10400408 = 0x000001c1;
*(vu32 *)0x1040040c = 0x000001c1;
*(vu32 *)0x10400410 = 0x00000000;
*(vu32 *)0x10400414 = 0x000000cf;
*(vu32 *)0x10400418 = 0x000000d1;
*(vu32 *)0x1040041c = 0x01c501c1;
*(vu32 *)0x10400420 = 0x00010000;
*(vu32 *)0x10400424 = 0x0000019d;
*(vu32 *)0x10400428 = 0x00000002;
*(vu32 *)0x1040042c = 0x00000192;
*(vu32 *)0x10400430 = 0x00000192;
*(vu32 *)0x10400434 = 0x00000192;
*(vu32 *)0x10400438 = 0x00000001;
*(vu32 *)0x1040043c = 0x00000002;
*(vu32 *)0x10400440 = 0x01960192;
*(vu32 *)0x10400444 = 0x00000000;
*(vu32 *)0x10400448 = 0x00000000;
*(vu32 *)0x1040045C = 0x00f00190;
*(vu32 *)0x10400460 = 0x01c100d1;
*(vu32 *)0x10400464 = 0x01920002;
*(vu32 *)0x10400468 = 0x18300000;
*(vu32 *)0x10400470 = 0x80341;
*(vu32 *)0x10400474 = 0x00010501;
*(vu32 *)0x10400478 = 0;
*(vu32 *)0x10400490 = 0x000002D0;
*(vu32 *)0x1040049C = 0x00000000;
// Disco register
for(u32 i = 0; i < 256; i++)
*(vu32 *)0x10400484 = 0x10101 * i;
// Bottom screen
*(vu32 *)0x10400500 = 0x000001c2;
*(vu32 *)0x10400504 = 0x000000d1;
*(vu32 *)0x10400508 = 0x000001c1;
*(vu32 *)0x1040050c = 0x000001c1;
*(vu32 *)0x10400510 = 0x000000cd;
*(vu32 *)0x10400514 = 0x000000cf;
*(vu32 *)0x10400518 = 0x000000d1;
*(vu32 *)0x1040051c = 0x01c501c1;
*(vu32 *)0x10400520 = 0x00010000;
*(vu32 *)0x10400524 = 0x0000019d;
*(vu32 *)0x10400528 = 0x00000052;
*(vu32 *)0x1040052c = 0x00000192;
*(vu32 *)0x10400530 = 0x00000192;
*(vu32 *)0x10400534 = 0x0000004f;
*(vu32 *)0x10400538 = 0x00000050;
*(vu32 *)0x1040053c = 0x00000052;
*(vu32 *)0x10400540 = 0x01980194;
*(vu32 *)0x10400544 = 0x00000000;
*(vu32 *)0x10400548 = 0x00000011;
*(vu32 *)0x1040055C = 0x00f00140;
*(vu32 *)0x10400560 = 0x01c100d1;
*(vu32 *)0x10400564 = 0x01920052;
*(vu32 *)0x10400568 = 0x18300000 + 0x46500;
*(vu32 *)0x10400570 = 0x80301;
*(vu32 *)0x10400574 = 0x00010501;
*(vu32 *)0x10400578 = 0;
*(vu32 *)0x10400590 = 0x000002D0;
*(vu32 *)0x1040059C = 0x00000000;
// Disco register
for(u32 i = 0; i < 256; i++)
*(vu32 *)0x10400584 = 0x10101 * i;
*(vu32 *)0x10400468 = 0x18300000;
*(vu32 *)0x1040046c = 0x18300000;
*(vu32 *)0x10400494 = 0x18300000;
*(vu32 *)0x10400498 = 0x18300000;
*(vu32 *)0x10400568 = 0x18346500;
*(vu32 *)0x1040056c = 0x18346500;
//Set CakeBrah framebuffers
*((vu32 *)0x23FFFE00) = 0x18300000;
*((vu32 *)0x23FFFE04) = 0x18300000;
*((vu32 *)0x23FFFE08) = 0x18346500;
//Clear ARM11 entry offset
*arm11 = 0;
//Wait for the entry to be set
while(!*arm11);
//Jump to it
((void (*)())*arm11)();
}

10
screeninit/source/start.s Normal file
View File

@@ -0,0 +1,10 @@
.section .text.start
.align 4
.global _start
_start:
@ Disable interrupts
CPSID aif
b main
.word 0

13
screeninit/source/types.h Executable file
View File

@@ -0,0 +1,13 @@
#pragma once
#include <stdint.h>
//Common data types
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;
typedef volatile u8 vu8;
typedef volatile u16 vu16;
typedef volatile u32 vu32;
typedef volatile u64 vu64;

View File

@@ -1,26 +1,26 @@
/* /*
* buttons.h * buttons.h
* by Aurora Wright
* Copyright (c) 2016 All Rights Reserved
*/ */
#pragma once #pragma once
#include "types.h" #include "types.h"
#define HID_PAD (*(vu16 *)0x10146000 ^ 0xFFF) #define HID_PAD (*(vu32 *)0x10146000 ^ 0xFFF)
#define BUTTON_R1 (1 << 8) #define BUTTON_R1 (1 << 8)
#define BUTTON_L1 (1 << 9) #define BUTTON_L1 (1 << 9)
#define BUTTON_A 1 #define BUTTON_A 1
#define BUTTON_B (1 << 1) #define BUTTON_B (1 << 1)
#define BUTTON_SELECT (1 << 2) #define BUTTON_X (1 << 10)
#define BUTTON_START (1 << 3) #define BUTTON_Y (1 << 11)
#define BUTTON_RIGHT (1 << 4) #define BUTTON_SELECT (1 << 2)
#define BUTTON_LEFT (1 << 5) #define BUTTON_START (1 << 3)
#define BUTTON_UP (1 << 6) #define BUTTON_RIGHT (1 << 4)
#define BUTTON_DOWN (1 << 7) #define BUTTON_LEFT (1 << 5)
#define BUTTON_L1R1 ((1 << 8) | (1 << 9)) #define BUTTON_UP (1 << 6)
#define SAFE_MODE (BUTTON_L1R1 | BUTTON_A | BUTTON_UP) #define BUTTON_DOWN (1 << 7)
#define OPTION_BUTTONS (BUTTON_L1R1 | BUTTON_A) #define SAFE_MODE (BUTTON_R1 | BUTTON_L1 | BUTTON_A | BUTTON_UP)
#define PAYLOAD_BUTTONS ((BUTTON_L1 | BUTTON_A) ^ 0xFFF) #define OVERRIDE_BUTTONS (BUTTON_B ^ 0xFFF)
#define MENU_BUTTONS (BUTTON_LEFT | BUTTON_RIGHT | BUTTON_UP | BUTTON_DOWN | BUTTON_A | BUTTON_START) #define SINGLE_PAYLOAD_BUTTONS (BUTTON_LEFT | BUTTON_RIGHT | BUTTON_UP | BUTTON_DOWN | BUTTON_START | BUTTON_X | BUTTON_Y)
#define L_PAYLOAD_BUTTONS (BUTTON_R1 | BUTTON_A | BUTTON_SELECT)
#define MENU_BUTTONS (BUTTON_LEFT | BUTTON_RIGHT | BUTTON_UP | BUTTON_DOWN | BUTTON_A | BUTTON_START)

181
source/config.c Normal file
View File

@@ -0,0 +1,181 @@
/*
* config.c
*/
#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",
"( ) SysNAND is updated (A9LH-only)",
"( ) Force A9LH detection",
"( ) Use second EmuNAND as default",
"( ) Enable region/language emulation",
"( ) 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();
}

17
source/config.h Normal file
View File

@@ -0,0 +1,17 @@
/*
* config.h
*/
#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

@@ -1,9 +1,7 @@
/* /*
* crypto.c * crypto.c
* by Reisyukaku / Aurora Wright
* Crypto libs from http://github.com/b1l1s/ctr
* *
* Copyright (c) 2016 All Rights Reserved * Crypto libs from http://github.com/b1l1s/ctr
*/ */
#include "crypto.h" #include "crypto.h"
@@ -11,7 +9,7 @@
#include "fatfs/sdmmc/sdmmc.h" #include "fatfs/sdmmc/sdmmc.h"
/**************************************************************** /****************************************************************
* Crypto Libs * Crypto libs
****************************************************************/ ****************************************************************/
/* original version by megazig */ /* original version by megazig */
@@ -229,80 +227,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
****************************************************************/ ****************************************************************/
//Nand key#2 (0x12C10) static u8 nandCTR[0x10],
static const u8 key2[0x10] = { nandSlot;
0x42, 0x3F, 0x81, 0x7A, 0x23, 0x52, 0x58, 0x31, 0x6E, 0x75, 0x8E, 0x3A, 0x39, 0x43, 0x2E, 0xD0
};
//Get Nand CTR key static u32 fatStart;
static void getNandCTR(u8 *buf, u32 console){
u8 *addr = (console ? (u8 *)0x080D8BBC : (u8 *)0x080D797C) + 0x0F; //Initialize the CTRNAND crypto
for(u8 keyLen = 0x10; keyLen; keyLen--) void ctrNandInit(void)
*(buf++) = *(addr--); {
u8 cid[0x10];
u8 shaSum[0x20];
sdmmc_get_cid(1, (u32 *)cid);
sha(shaSum, cid, 0x10, SHA_256_MODE);
memcpy(nandCTR, shaSum, 0x10);
if(console)
{
u8 keyY0x5[0x10] = {0x4D, 0x80, 0x4F, 0x4E, 0x99, 0x90, 0x19, 0x46, 0x13, 0xA2, 0x04, 0xAC, 0x58, 0x44, 0x60, 0xBE};
aes_setkey(0x05, keyY0x5, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL);
nandSlot = 0x05;
fatStart = 0x5CAD7;
}
else
{
nandSlot = 0x04;
fatStart = 0x5CAE5;
}
} }
//Read firm0 from NAND and write to buffer //Read and decrypt from the selected CTRNAND
void nandFirm0(u8 *outbuf, u32 size, u32 console){ u32 ctrNandRead(u32 sector, u32 sectorCount, u8 *outbuf)
u8 CTR[0x10]; {
getNandCTR(CTR, console); u8 tmpCTR[0x10];
memcpy(tmpCTR, nandCTR, 0x10);
aes_advctr(tmpCTR, ((sector + fatStart) * 0x200) / AES_BLOCK_SIZE, AES_INPUT_BE | AES_INPUT_NORMAL);
sdmmc_nand_readsectors(0x0B130000 / 0x200, size / 0x200, outbuf); //Read
u32 result;
if(!firmSource)
result = sdmmc_nand_readsectors(sector + fatStart, sectorCount, outbuf);
else
{
sector += emuOffset;
result = sdmmc_sdcard_readsectors(sector + fatStart, sectorCount, outbuf);
}
aes_advctr(CTR, 0x0B130000/0x10, AES_INPUT_BE | AES_INPUT_NORMAL); //Decrypt
aes_use_keyslot(0x06); aes_use_keyslot(nandSlot);
aes(outbuf, outbuf, size / AES_BLOCK_SIZE, CTR, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL); aes(outbuf, outbuf, sectorCount * 0x200 / AES_BLOCK_SIZE, tmpCTR, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
return result;
} }
//Decrypts the N3DS arm9bin //Decrypt a FIRM ExeFS
void decryptArm9Bin(u8 *arm9Section, u32 mode){ void decryptExeFs(u8 *inbuf)
{
u8 *exeFsOffset = inbuf + *(u32 *)(inbuf + 0x1A0) * 0x200;
u32 exeFsSize = *(u32 *)(inbuf + 0x1A4) * 0x200;
u8 ncchCTR[0x10] = {0};
for(u32 i = 0; i < 8; i++)
ncchCTR[7 - i] = *(inbuf + 0x108 + i);
ncchCTR[8] = 2;
aes_setkey(0x2C, inbuf, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL);
aes_setiv(ncchCTR, AES_INPUT_BE | AES_INPUT_NORMAL);
aes_use_keyslot(0x2C);
aes(inbuf - 0x200, exeFsOffset, exeFsSize / AES_BLOCK_SIZE, ncchCTR, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
}
//ARM9Loader replacement
void arm9Loader(u8 *arm9Section, u32 mode)
{
//Firm keys //Firm keys
u8 keyY[0x10]; u8 keyY[0x10],
u8 CTR[0x10]; arm9BinCTR[0x10],
u8 slot = mode ? 0x16 : 0x15; arm9BinSlot = mode ? 0x16 : 0x15;
//Setup keys needed for arm9bin decryption //Setup keys needed for arm9bin decryption
memcpy(keyY, arm9Section + 0x10, 0x10); memcpy(keyY, arm9Section + 0x10, 0x10);
memcpy(CTR, arm9Section + 0x20, 0x10); memcpy(arm9BinCTR, arm9Section + 0x20, 0x10);
u32 size = 0;
//Calculate the size of the ARM9 binary
u32 arm9BinSize = 0;
//http://stackoverflow.com/questions/12791077/atoi-implementation-in-c //http://stackoverflow.com/questions/12791077/atoi-implementation-in-c
for(u8 *tmp = arm9Section + 0x30; *tmp; tmp++) for(u8 *tmp = arm9Section + 0x30; *tmp; tmp++)
size = (size << 3) + (size << 1) + (*tmp) - '0'; arm9BinSize = (arm9BinSize << 3) + (arm9BinSize << 1) + *tmp - '0';
if(mode){ if(mode)
{
const u8 key2[0x10] = {0x42, 0x3F, 0x81, 0x7A, 0x23, 0x52, 0x58, 0x31, 0x6E, 0x75, 0x8E, 0x3A, 0x39, 0x43, 0x2E, 0xD0};
u8 keyX[0x10]; u8 keyX[0x10];
//Set 0x11 to key2 for the arm9bin and misc keys //Set 0x11 to key2 for the arm9bin and misc keys
aes_setkey(0x11, key2, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL); aes_setkey(0x11, key2, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL);
aes_use_keyslot(0x11); aes_use_keyslot(0x11);
aes(keyX, arm9Section + 0x60, 1, NULL, AES_ECB_DECRYPT_MODE, 0); aes(keyX, arm9Section + 0x60, 1, NULL, AES_ECB_DECRYPT_MODE, 0);
aes_setkey(slot, keyX, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL); aes_setkey(arm9BinSlot, keyX, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
} }
aes_setkey(slot, keyY, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL); aes_setkey(arm9BinSlot, keyY, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL);
aes_setiv(CTR, AES_INPUT_BE | AES_INPUT_NORMAL); aes_setiv(arm9BinCTR, AES_INPUT_BE | AES_INPUT_NORMAL);
aes_use_keyslot(slot); aes_use_keyslot(arm9BinSlot);
//Decrypt arm9bin //Decrypt arm9bin
aes(arm9Section + 0x800, arm9Section + 0x800, size/AES_BLOCK_SIZE, CTR, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL); aes(arm9Section + 0x800, arm9Section + 0x800, arm9BinSize / AES_BLOCK_SIZE, arm9BinCTR, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
}
//Sets the N3DS 9.6 KeyXs //Set >=9.6 KeyXs
void setKeyXs(u8 *arm9Section){ if(mode)
{
u8 keyData[0x10] = {0xDD, 0xDA, 0xA4, 0xC6, 0x2C, 0xC4, 0x50, 0xE9, 0xDA, 0xB6, 0x9B, 0x0D, 0x9D, 0x2A, 0x21, 0x98},
decKey[0x10];
u8 *keyData = arm9Section + 0x89814; //Set keys 0x19..0x1F keyXs
u8 *decKey = keyData + 0x10; aes_use_keyslot(0x11);
for(u8 slot = 0x19; slot < 0x20; slot++)
//Set keys 0x19..0x1F keyXs {
aes_setkey(0x11, key2, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL); aes(decKey, keyData, 1, NULL, AES_ECB_DECRYPT_MODE, 0);
aes_use_keyslot(0x11); aes_setkey(slot, decKey, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
for(u8 slot = 0x19; slot < 0x20; slot++){ keyData[0xF] += 1;
aes(decKey, keyData, 1, NULL, AES_ECB_DECRYPT_MODE, 0); }
aes_setkey(slot, decKey, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
*(keyData + 0xF) += 1;
} }
} }

View File

@@ -1,9 +1,7 @@
/* /*
* crypto.h * crypto.h
* by Reisyukaku / Aurora Wright
* Crypto libs from http://github.com/b1l1s/ctr
* *
* Copyright (c) 2016 All Rights Reserved * Crypto libs from http://github.com/b1l1s/ctr
*/ */
#pragma once #pragma once
@@ -53,7 +51,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

@@ -1,12 +1,11 @@
/* /*
* draw.c * draw.c
* by Reisyukaku / Aurora Wright
* Code to print to the screen by mid-kid @CakesFW
* *
* Copyright (c) 2016 All Rights Reserved * Code to print to the screen by mid-kid @CakesFW
*/ */
#include "draw.h" #include "draw.h"
#include "screeninit.h"
#include "fs.h" #include "fs.h"
#include "memory.h" #include "memory.h"
#include "font.h" #include "font.h"
@@ -20,59 +19,71 @@ static const struct fb {
u8 *bottom; u8 *bottom;
} *const fb = (struct fb *)0x23FFFE00; } *const fb = (struct fb *)0x23FFFE00;
static int strlen(const char *string){ static inline int strlen(const char *string)
{
char *stringEnd = (char *)string; char *stringEnd = (char *)string;
while(*stringEnd) stringEnd++; while(*stringEnd) stringEnd++;
return stringEnd - string; return stringEnd - string;
} }
void clearScreens(void){ void clearScreens(void)
{
memset32(fb->top_left, 0, 0x46500); memset32(fb->top_left, 0, 0x46500);
memset32(fb->top_right, 0, 0x46500); memset32(fb->top_right, 0, 0x46500);
memset32(fb->bottom, 0, 0x38400); memset32(fb->bottom, 0, 0x38400);
} }
void loadSplash(void){ void loadSplash(void)
clearScreens(); {
initScreens();
//Don't delay boot if no splash image is on the SD //Don't delay boot if no splash image is on the SD
if(fileRead(fb->top_left, "/aurei/splash.bin", 0x46500) + if(fileRead(fb->top_left, "/luma/splash.bin", 0x46500) +
fileRead(fb->bottom, "/aurei/splashbottom.bin", 0x38400)){ fileRead(fb->bottom, "/luma/splashbottom.bin", 0x38400))
u64 i = 0x1300000; while(--i) __asm("mov r0, r0"); //Less Ghetto sleep func {
u64 i = 0x1400000;
while(i--) __asm("mov r0, r0"); //Less Ghetto sleep func
} }
} }
void drawCharacter(char character, int posX, int posY, u32 color){ void drawCharacter(char character, int posX, int posY, u32 color)
{
u8 *const select = fb->top_left; u8 *const select = fb->top_left;
for(int y = 0; y < 8; y++){ for(int y = 0; y < 8; y++)
{
char charPos = font[character * 8 + y]; char charPos = font[character * 8 + y];
for(int x = 7; x >= 0; x--){ for(int x = 7; x >= 0; x--)
int screenPos = (posX * SCREEN_TOP_HEIGHT * 3 + (SCREEN_TOP_HEIGHT - y - posY - 1) * 3) + (7 - x) * 3 * SCREEN_TOP_HEIGHT; if ((charPos >> x) & 1)
{
int screenPos = (posX * SCREEN_TOP_HEIGHT * 3 + (SCREEN_TOP_HEIGHT - y - posY - 1) * 3) + (7 - x) * 3 * SCREEN_TOP_HEIGHT;
if ((charPos >> x) & 1) {
select[screenPos] = color >> 16; select[screenPos] = color >> 16;
select[screenPos + 1] = color >> 8; select[screenPos + 1] = color >> 8;
select[screenPos + 2] = color; select[screenPos + 2] = color;
} }
}
} }
} }
int drawString(const char *string, int posX, int posY, u32 color){ int drawString(const char *string, int posX, int posY, u32 color)
int length = strlen(string); {
for(int i = 0, line_i = 0; i < strlen(string); i++, line_i++)
for(int i = 0, line_i = 0; i < length; i++, line_i++){ {
if(string[i] == '\n'){ if(string[i] == '\n')
{
posY += SPACING_Y; posY += SPACING_Y;
line_i = 0; line_i = 0;
i++; i++;
} else if(line_i >= (SCREEN_TOP_WIDTH - posX) / SPACING_X){ }
else if(line_i >= (SCREEN_TOP_WIDTH - posX) / SPACING_X)
{
// Make sure we never get out of the screen. // Make sure we never get out of the screen.
posY += SPACING_Y; posY += SPACING_Y;
line_i = 2; // Little offset so we know the same string continues. line_i = 2; //Little offset so we know the same string continues.
if(string[i] == ' ') i++; // Spaces at the start look weird if(string[i] == ' ') i++; //Spaces at the start look weird
} }
drawCharacter(string[i], posX + line_i * SPACING_X, posY, color); drawCharacter(string[i], posX + line_i * SPACING_X, posY, color);

View File

@@ -1,17 +1,19 @@
/* /*
* draw.h * draw.h
* by Reisyukaku / Aurora Wright
* Code to print to the screen by mid-kid @CakesFW
* *
* Copyright (c) 2016 All Rights Reserved * Code to print to the screen by mid-kid @CakesFW
*/ */
#pragma once #pragma once
#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

@@ -1,39 +1,50 @@
/* /*
* emunand.c * emunand.c
* by Reisyukaku / Aurora Wright
* Copyright (c) 2016 All Rights Reserved
*/ */
#include "emunand.h" #include "emunand.h"
#include "memory.h" #include "memory.h"
#include "fatfs/sdmmc/sdmmc.h" #include "fatfs/sdmmc/sdmmc.h"
void getEmunandSect(u32 *off, u32 *head, u32 emuNAND){ void getEmunandSect(u32 *off, u32 *head, u32 *emuNAND)
u8 *const temp = (u8 *)0x24300000; {
static u8 *const temp = (u8 *)0x24300000;
u32 nandSize = getMMCDevice(0)->total_size; const u32 nandSize = getMMCDevice(0)->total_size;
u32 nandOffset = emuNAND == 1 ? 0 : u32 nandOffset = *emuNAND == 1 ? 0 :
(nandSize > 0x200000 ? 0x400000 : 0x200000); (nandSize > 0x200000 ? 0x400000 : 0x200000);
//Check for RedNAND //Check for RedNAND
if(sdmmc_sdcard_readsectors(nandOffset + 1, 1, temp) == 0){ if(sdmmc_sdcard_readsectors(nandOffset + 1, 1, temp) == 0)
if(*(u32 *)(temp + 0x100) == NCSD_MAGIC){ {
if(*(u32 *)(temp + 0x100) == NCSD_MAGIC)
{
*off = nandOffset + 1; *off = nandOffset + 1;
*head = nandOffset + 1; *head = nandOffset + 1;
} }
//Check for Gateway emuNAND //Check for Gateway emuNAND
else if(sdmmc_sdcard_readsectors(nandOffset + nandSize, 1, temp) == 0){ else if(sdmmc_sdcard_readsectors(nandOffset + nandSize, 1, temp) == 0)
if(*(u32 *)(temp + 0x100) == NCSD_MAGIC){ {
if(*(u32 *)(temp + 0x100) == NCSD_MAGIC)
{
*off = nandOffset; *off = nandOffset;
*head = nandOffset + nandSize; *head = nandOffset + nandSize;
} }
//Fallback to the first emuNAND if there's no second one
else if(emuNAND == 2) getEmunandSect(off, head, 1); /* Fallback to the first emuNAND if there's no second one,
or to SysNAND if there isn't any */
else
{
(*emuNAND)--;
if(*emuNAND) getEmunandSect(off, head, emuNAND);
}
} }
} }
} }
u32 getSDMMC(u8 *pos, u32 size){ u32 getSDMMC(u8 *pos, u32 size)
{
//Look for struct code //Look for struct code
const u8 pattern[] = {0x21, 0x20, 0x18, 0x20}; const u8 pattern[] = {0x21, 0x20, 0x18, 0x20};
const u8 *off = memsearch(pos, pattern, size, 4) - 1; const u8 *off = memsearch(pos, pattern, size, 4) - 1;
@@ -41,7 +52,8 @@ u32 getSDMMC(u8 *pos, u32 size){
return *(u32 *)(off + 0x0A) + *(u32 *)(off + 0x0E); return *(u32 *)(off + 0x0A) + *(u32 *)(off + 0x0E);
} }
void getEmuRW(u8 *pos, u32 size, u32 *readOff, u32 *writeOff){ void getEmuRW(u8 *pos, u32 size, u32 *readOff, u32 *writeOff)
{
//Look for read/write code //Look for read/write code
const u8 pattern[] = {0x1E, 0x00, 0xC8, 0x05}; const u8 pattern[] = {0x1E, 0x00, 0xC8, 0x05};
@@ -49,14 +61,16 @@ void getEmuRW(u8 *pos, u32 size, u32 *readOff, u32 *writeOff){
*writeOff = (u32)memsearch((u8 *)(*readOff + 0xA), pattern, 0x100, 4) - 6; *writeOff = (u32)memsearch((u8 *)(*readOff + 0xA), pattern, 0x100, 4) - 6;
} }
u32 *getMPU(u8 *pos, u32 size){ u32 *getMPU(u8 *pos, u32 size)
{
//Look for MPU pattern //Look for MPU pattern
const u8 pattern[] = {0x03, 0x00, 0x24, 0x00}; const u8 pattern[] = {0x03, 0x00, 0x24, 0x00};
return (u32 *)memsearch(pos, pattern, size, 4); return (u32 *)memsearch(pos, pattern, size, 4);
} }
void *getEmuCode(u8 *proc9Offset){ void *getEmuCode(u8 *proc9Offset)
{
const u8 pattern[] = {0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00}; const u8 pattern[] = {0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00};
//Looking for the last free space before Process9 //Looking for the last free space before Process9

View File

@@ -1,16 +1,14 @@
/* /*
* emunand.h * emunand.h
* by Reisyukaku / Aurora Wright
* Copyright (c) 2016 All Rights Reserved
*/ */
#pragma once #pragma once
#include "types.h" #include "types.h"
#define NCSD_MAGIC (0x4453434E) #define NCSD_MAGIC 0x4453434E
void getEmunandSect(u32 *off, u32 *head, u32 emuNAND); void getEmunandSect(u32 *off, u32 *head, u32 *emuNAND);
u32 getSDMMC(u8 *pos, u32 size); u32 getSDMMC(u8 *pos, u32 size);
void getEmuRW(u8 *pos, u32 size, u32 *readOff, u32 *writeOff); void getEmuRW(u8 *pos, u32 size, u32 *readOff, u32 *writeOff);
u32 *getMPU(u8 *pos, u32 size); u32 *getMPU(u8 *pos, u32 size);

View File

@@ -1,180 +1,254 @@
---------------------------------------------------------------------------- ----------------------------------------------------------------------------
Revision history of FatFs module Revision history of FatFs module
---------------------------------------------------------------------------- ----------------------------------------------------------------------------
R0.00 (February 26, 2006) R0.00 (February 26, 2006)
Prototype.
Prototype.
R0.01 (April 29, 2006)
First stable version.
R0.01 (April 29, 2006)
R0.02 (June 01, 2006) First stable version.
Added FAT12 support.
Removed unbuffered mode.
Fixed a problem on small (<32M) partition.
R0.02 (June 01, 2006)
R0.02a (June 10, 2006) Added FAT12 support.
Added a configuration option (_FS_MINIMUM). Removed unbuffered mode.
Fixed a problem on small (<32M) partition.
R0.03 (September 22, 2006)
Added f_rename().
Changed option _FS_MINIMUM to _FS_MINIMIZE. R0.02a (June 10, 2006)
Added a configuration option (_FS_MINIMUM).
R0.03a (December 11, 2006)
Improved cluster scan algorithm to write files fast.
Fixed f_mkdir() creates incorrect directory on FAT32.
R0.03 (September 22, 2006)
R0.04 (February 04, 2007) Added f_rename().
Added f_mkfs(). Changed option _FS_MINIMUM to _FS_MINIMIZE.
Supported multiple drive system.
Changed some interfaces for multiple drive system.
Changed f_mountdrv() to f_mount().
R0.03a (December 11, 2006)
R0.04a (April 01, 2007) Improved cluster scan algorithm to write files fast.
Supported multiple partitions on a physical drive. Fixed f_mkdir() creates incorrect directory on FAT32.
Added a capability of extending file size to f_lseek().
Added minimization level 3.
Fixed an endian sensitive code in f_mkfs().
R0.04 (February 04, 2007)
R0.04b (May 05, 2007) Added f_mkfs().
Added a configuration option _USE_NTFLAG. Supported multiple drive system.
Added FSINFO support. Changed some interfaces for multiple drive system.
Fixed DBCS name can result FR_INVALID_NAME. Changed f_mountdrv() to f_mount().
Fixed short seek (<= csize) collapses the file object.
R0.05 (August 25, 2007) R0.04a (April 01, 2007)
Changed arguments of f_read(), f_write() and f_mkfs().
Fixed f_mkfs() on FAT32 creates incorrect FSINFO. Supported multiple partitions on a physical drive.
Fixed f_mkdir() on FAT32 creates incorrect directory. Added a capability of extending file size to f_lseek().
Added minimization level 3.
Fixed an endian sensitive code in f_mkfs().
R0.05a (February 03, 2008)
Added f_truncate() and f_utime().
Fixed off by one error at FAT sub-type determination.
Fixed btr in f_read() can be mistruncated. R0.04b (May 05, 2007)
Fixed cached sector is not flushed when create and close without write.
Added a configuration option _USE_NTFLAG.
Added FSINFO support.
R0.06 (April 01, 2008) Fixed DBCS name can result FR_INVALID_NAME.
Added fputc(), fputs(), fprintf() and fgets(). Fixed short seek (<= csize) collapses the file object.
Improved performance of f_lseek() on moving to the same or following cluster.
R0.07 (April 01, 2009) R0.05 (August 25, 2007)
Merged Tiny-FatFs as a configuration option. (_FS_TINY)
Added long file name feature. (_USE_LFN) Changed arguments of f_read(), f_write() and f_mkfs().
Added multiple code page feature. (_CODE_PAGE) Fixed f_mkfs() on FAT32 creates incorrect FSINFO.
Added re-entrancy for multitask operation. (_FS_REENTRANT) Fixed f_mkdir() on FAT32 creates incorrect directory.
Added auto cluster size selection to f_mkfs().
Added rewind option to f_readdir().
Changed result code of critical errors.
Renamed string functions to avoid name collision. R0.05a (February 03, 2008)
Added f_truncate() and f_utime().
R0.07a (April 14, 2009) Fixed off by one error at FAT sub-type determination.
Septemberarated out OS dependent code on reentrant cfg. Fixed btr in f_read() can be mistruncated.
Added multiple sector size feature. Fixed cached sector is not flushed when create and close without write.
R0.07c (June 21, 2009)
Fixed f_unlink() can return FR_OK on error. R0.06 (April 01, 2008)
Fixed wrong cache control in f_lseek().
Added relative path feature. Added fputc(), fputs(), fprintf() and fgets().
Added f_chdir() and f_chdrive(). Improved performance of f_lseek() on moving to the same or following cluster.
Added proper case conversion to extended character.
R0.07e (November 03, 2009) R0.07 (April 01, 2009)
Septemberarated out configuration options from ff.h to ffconf.h.
Fixed f_unlink() fails to remove a sub-directory on _FS_RPATH. Merged Tiny-FatFs as a configuration option. (_FS_TINY)
Fixed name matching error on the 13 character boundary. Added long file name feature. (_USE_LFN)
Added a configuration option, _LFN_UNICODE. Added multiple code page feature. (_CODE_PAGE)
Changed f_readdir() to return the SFN with always upper case on non-LFN cfg. Added re-entrancy for multitask operation. (_FS_REENTRANT)
Added auto cluster size selection to f_mkfs().
Added rewind option to f_readdir().
R0.08 (May 15, 2010) Changed result code of critical errors.
Added a memory configuration option. (_USE_LFN = 3) Renamed string functions to avoid name collision.
Added file lock feature. (_FS_SHARE)
Added fast seek feature. (_USE_FASTSEEK)
Changed some types on the API, XCHAR->TCHAR.
Changed .fname in the FILINFO structure on Unicode cfg. R0.07a (April 14, 2009)
String functions support UTF-8 encoding files on Unicode cfg.
Septemberarated out OS dependent code on reentrant cfg.
Added multiple sector size feature.
R0.08a (August 16, 2010)
Added f_getcwd(). (_FS_RPATH = 2)
Added sector erase feature. (_USE_ERASE)
Moved file lock semaphore table from fs object to the bss. R0.07c (June 21, 2009)
Fixed f_mkfs() creates wrong FAT32 volume.
Fixed f_unlink() can return FR_OK on error.
Fixed wrong cache control in f_lseek().
R0.08b (January 15, 2011) Added relative path feature.
Fast seek feature is also applied to f_read() and f_write(). Added f_chdir() and f_chdrive().
f_lseek() reports required table size on creating CLMP. Added proper case conversion to extended character.
Extended format syntax of f_printf().
Ignores duplicated directory separators in given path name.
R0.07e (November 03, 2009)
R0.09 (September 06, 2011)
f_mkfs() supports multiple partition to complete the multiple partition feature. Septemberarated out configuration options from ff.h to ffconf.h.
Added f_fdisk(). Fixed f_unlink() fails to remove a sub-directory on _FS_RPATH.
Fixed name matching error on the 13 character boundary.
Added a configuration option, _LFN_UNICODE.
R0.09a (August 27, 2012) Changed f_readdir() to return the SFN with always upper case on non-LFN cfg.
Changed f_open() and f_opendir() reject null object pointer to avoid crash.
Changed option name _FS_SHARE to _FS_LOCK.
Fixed assertion failure due to OS/2 EA on FAT12/16 volume.
R0.08 (May 15, 2010)
R0.09b (January 24, 2013) Added a memory configuration option. (_USE_LFN = 3)
Added f_setlabel() and f_getlabel(). Added file lock feature. (_FS_SHARE)
Added fast seek feature. (_USE_FASTSEEK)
Changed some types on the API, XCHAR->TCHAR.
R0.10 (October 02, 2013) Changed .fname in the FILINFO structure on Unicode cfg.
Added selection of character encoding on the file. (_STRF_ENCODE) String functions support UTF-8 encoding files on Unicode cfg.
Added f_closedir().
Added forced full FAT scan for f_getfree(). (_FS_NOFSINFO)
Added forced mount feature with changes of f_mount().
Improved behavior of volume auto detection. R0.08a (August 16, 2010)
Improved write throughput of f_puts() and f_printf().
Changed argument of f_chdrive(), f_mkfs(), disk_read() and disk_write(). Added f_getcwd(). (_FS_RPATH = 2)
Fixed f_write() can be truncated when the file size is close to 4GB. Added sector erase feature. (_USE_ERASE)
Fixed f_open(), f_mkdir() and f_setlabel() can return incorrect error code. Moved file lock semaphore table from fs object to the bss.
Fixed f_mkfs() creates wrong FAT32 volume.
R0.10a (January 15, 2014)
Added arbitrary strings as drive number in the path name. (_STR_VOLUME_ID)
Added a configuration option of minimum sector size. (_MIN_SS) R0.08b (January 15, 2011)
2nd argument of f_rename() can have a drive number and it will be ignored.
Fixed f_mount() with forced mount fails when drive number is >= 1. (appeared at R0.10) Fast seek feature is also applied to f_read() and f_write().
Fixed f_close() invalidates the file object without volume lock. f_lseek() reports required table size on creating CLMP.
Fixed f_closedir() returns but the volume lock is left acquired. (appeared at R0.10) Extended format syntax of f_printf().
Fixed creation of an entry with LFN fails on too many SFN collisions. (appeared at R0.07) Ignores duplicated directory separators in given path name.
R0.10b (May 19, 2014)
Fixed a hard error in the disk I/O layer can collapse the directory entry. R0.09 (September 06, 2011)
Fixed LFN entry is not deleted on delete/rename an object with lossy converted SFN. (appeared at R0.07)
f_mkfs() supports multiple partition to complete the multiple partition feature.
Added f_fdisk().
R0.10c (November 09, 2014)
Added a configuration option for the platforms without RTC. (_FS_NORTC)
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) R0.09a (August 27, 2012)
Fixed a potential problem of FAT access that can appear on disk error.
Fixed null pointer dereference on attempting to delete the root direcotry. (appeared at R0.08) Changed f_open() and f_opendir() reject null object pointer to avoid crash.
Changed option name _FS_SHARE to _FS_LOCK.
Fixed assertion failure due to OS/2 EA on FAT12/16 volume.
R0.11 (February 09, 2015)
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 _FS_NORTC option does not work properly. (appeared at R0.10c) R0.09b (January 24, 2013)
Added f_setlabel() and f_getlabel().
R0.10 (October 02, 2013)
Added selection of character encoding on the file. (_STRF_ENCODE)
Added f_closedir().
Added forced full FAT scan for f_getfree(). (_FS_NOFSINFO)
Added forced mount feature with changes of f_mount().
Improved behavior of volume auto detection.
Improved write throughput of f_puts() and f_printf().
Changed argument of f_chdrive(), f_mkfs(), disk_read() and disk_write().
Fixed f_write() can be truncated when the file size is close to 4GB.
Fixed f_open(), f_mkdir() and f_setlabel() can return incorrect value on error.
R0.10a (January 15, 2014)
Added arbitrary strings as drive number in the path name. (_STR_VOLUME_ID)
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.
Fixed f_mount() with forced mount fails when drive number is >= 1. (appeared at R0.10)
Fixed f_close() invalidates the file object without volume lock.
Fixed f_closedir() returns but the volume lock is left acquired. (appeared at R0.10)
Fixed creation of an entry with LFN fails on too many SFN collisions. (appeared at R0.07)
R0.10b (May 19, 2014)
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)
R0.10c (November 09, 2014)
Added a configuration option for the platforms without RTC. (_FS_NORTC)
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 a potential problem of FAT access that can appear on disk error.
Fixed null pointer dereference on attempting to delete the root direcotry. (appeared at R0.08)
R0.11 (February 09, 2015)
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 _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).
R0.12 (April 12, 2016)
Added support of exFAT file system. (_FS_EXFAT)
Added f_expand(). (_USE_EXPAND)
Changed some members in FINFO structure and behavior of f_readdir().
Added an option _USE_CHMOD and removed an option _WORD_ACCESS.
Fixed errors in the case conversion teble of Unicode (cc*.c).

View File

@@ -1,21 +1,21 @@
FatFs Module Source Files R0.11 FatFs Module Source Files R0.12
FILES FILES
00readme.txt This file. 00readme.txt This file.
history.txt Revision history. history.txt Revision history.
ffconf.h Configuration file for FatFs module. ffconf.h Configuration file for FatFs module.
ff.h Common include file for FatFs and application module. ff.h Common include file for FatFs and application module.
ff.c FatFs module. ff.c FatFs module.
diskio.h Common include file for FatFs and disk I/O module. diskio.h Common include file for FatFs and disk I/O module.
diskio.c An example of glue function to attach existing disk I/O module to FatFs. diskio.c An example of glue function to attach existing disk I/O module to FatFs.
integer.h Integer type definitions for FatFs. integer.h Integer type definitions for FatFs.
option Optional external functions. option Optional external functions.
Low level disk I/O module is not included in this archive because the FatFs Low level disk I/O module is not included in this archive because the FatFs
module is only a generic file system layer and not depend on any specific module is only a generic file system layer and not depend on any specific
storage device. You have to provide a low level disk I/O module that written storage device. You have to provide a low level disk I/O module that written
to control the target storage device. to control the target storage device.

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 */
@@ -30,11 +33,19 @@ DSTATUS disk_status (
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
DSTATUS disk_initialize ( DSTATUS disk_initialize (
__attribute__((unused))
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;
} }
@@ -45,18 +56,25 @@ DSTATUS disk_initialize (
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
DRESULT disk_read ( DRESULT disk_read (
__attribute__((unused))
BYTE pdrv, /* Physical drive nmuber to identify the drive */ BYTE pdrv, /* Physical drive nmuber to identify the drive */
BYTE *buff, /* Data buffer to store read data */ BYTE *buff, /* Data buffer to store read data */
DWORD sector, /* Sector address in LBA */ DWORD sector, /* Sector address in LBA */
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;
} }
@@ -67,18 +85,16 @@ DRESULT disk_read (
#if _USE_WRITE #if _USE_WRITE
DRESULT disk_write ( DRESULT disk_write (
__attribute__((unused))
BYTE pdrv, /* Physical drive nmuber to identify the drive */ BYTE pdrv, /* Physical drive nmuber to identify the drive */
const BYTE *buff, /* Data to be written */ const BYTE *buff, /* Data to be written */
DWORD sector, /* Sector address in LBA */ DWORD sector, /* Sector address in LBA */
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

File diff suppressed because it is too large Load Diff

View File

@@ -1,350 +1,366 @@
/*---------------------------------------------------------------------------/ /*---------------------------------------------------------------------------/
/ FatFs - FAT file system module include R0.11 (C)ChaN, 2015 / FatFs - FAT file system module include R0.12 (C)ChaN, 2016
/----------------------------------------------------------------------------/ /----------------------------------------------------------------------------/
/ 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.
/ /
/ Copyright (C) 2015, ChaN, all right reserved. / Copyright (C) 2016, ChaN, all right reserved.
/ /
/ 1. Redistributions of source code must retain the above copyright notice, / 1. Redistributions of source code must retain the above copyright notice,
/ this condition and the following disclaimer. / this condition and the following disclaimer.
/ /
/ This software is provided by the copyright holder and contributors "AS IS" / This software is provided by the copyright holder and contributors "AS IS"
/ and any warranties related to this software are DISCLAIMED. / and any warranties related to this software are DISCLAIMED.
/ The copyright owner or contributors be NOT LIABLE for any damages caused / The copyright owner or contributors be NOT LIABLE for any damages caused
/ by use of this software. / by use of this software.
/---------------------------------------------------------------------------*/ /---------------------------------------------------------------------------*/
#ifndef _FATFS #ifndef _FATFS
#define _FATFS 32020 /* Revision ID */ #define _FATFS 88100 /* Revision ID */
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
#include "integer.h" /* Basic integer types */ #include "integer.h" /* Basic integer types */
#include "ffconf.h" /* FatFs configuration options */ #include "ffconf.h" /* FatFs configuration options */
#if _FATFS != _FFCONF #if _FATFS != _FFCONF
#error Wrong configuration file (ffconf.h). #error Wrong configuration file (ffconf.h).
#endif #endif
/* Definitions of volume management */ /* Definitions of volume management */
#if _MULTI_PARTITION /* Multiple partition configuration */ #if _MULTI_PARTITION /* Multiple partition configuration */
typedef struct { typedef struct {
BYTE pd; /* Physical drive number */ BYTE pd; /* Physical drive number */
BYTE pt; /* Partition: 0:Auto detect, 1-4:Forced partition) */ BYTE pt; /* Partition: 0:Auto detect, 1-4:Forced partition) */
} PARTITION; } PARTITION;
extern PARTITION VolToPart[]; /* Volume - Partition resolution table */ extern PARTITION VolToPart[]; /* Volume - Partition resolution table */
#define LD2PD(vol) (VolToPart[vol].pd) /* Get physical drive number */ #define LD2PD(vol) (VolToPart[vol].pd) /* Get physical drive number */
#define LD2PT(vol) (VolToPart[vol].pt) /* Get partition index */ #define LD2PT(vol) (VolToPart[vol].pt) /* Get partition index */
#else /* Single partition configuration */ #else /* Single partition configuration */
#define LD2PD(vol) (BYTE)(vol) /* Each logical drive is bound to the same physical drive number */ #define LD2PD(vol) (BYTE)(vol) /* Each logical drive is bound to the same physical drive number */
#define LD2PT(vol) 0 /* Find first valid partition or in SFD */ #define LD2PT(vol) 0 /* Find first valid partition or in SFD */
#endif #endif
/* Type of path name strings on FatFs API */ /* Type of path name strings on FatFs API */
#if _LFN_UNICODE /* Unicode string */ #if _LFN_UNICODE /* Unicode string */
#if !_USE_LFN #if _USE_LFN == 0
#error _LFN_UNICODE must be 0 at non-LFN cfg. #error _LFN_UNICODE must be 0 at non-LFN cfg.
#endif #endif
#ifndef _INC_TCHAR #ifndef _INC_TCHAR
typedef WCHAR TCHAR; typedef WCHAR TCHAR;
#define _T(x) L ## x #define _T(x) L ## x
#define _TEXT(x) L ## x #define _TEXT(x) L ## x
#endif #endif
#else /* ANSI/OEM string */ #else /* ANSI/OEM string */
#ifndef _INC_TCHAR #ifndef _INC_TCHAR
typedef char TCHAR; typedef char TCHAR;
#define _T(x) x #define _T(x) x
#define _TEXT(x) x #define _TEXT(x) x
#endif #endif
#endif #endif
/* File system object structure (FATFS) */ /* File system object structure (FATFS) */
typedef struct { typedef struct {
BYTE fs_type; /* FAT sub-type (0:Not mounted) */ BYTE fs_type; /* File system type (0:N/A) */
BYTE drv; /* Physical drive number */ BYTE drv; /* Physical drive number */
BYTE csize; /* Sectors per cluster (1,2,4...128) */ BYTE n_fats; /* Number of FATs (1 or 2) */
BYTE n_fats; /* Number of FAT copies (1 or 2) */ BYTE wflag; /* win[] flag (b0:dirty) */
BYTE wflag; /* win[] flag (b0:dirty) */ BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */
BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */ WORD id; /* File system mount ID */
WORD id; /* File system mount ID */ WORD n_rootdir; /* Number of root directory entries (FAT12/16) */
WORD n_rootdir; /* Number of root directory entries (FAT12/16) */ WORD csize; /* Cluster size [sectors] */
#if _MAX_SS != _MIN_SS #if _MAX_SS != _MIN_SS
WORD ssize; /* Bytes per sector (512, 1024, 2048 or 4096) */ WORD ssize; /* Sector size (512, 1024, 2048 or 4096) */
#endif #endif
#if _FS_REENTRANT #if _FS_EXFAT
_SYNC_t sobj; /* Identifier of sync object */ BYTE* dirbuf; /* Directory entry block scratchpad buffer */
#endif #endif
#if !_FS_READONLY #if _FS_REENTRANT
DWORD last_clust; /* Last allocated cluster */ _SYNC_t sobj; /* Identifier of sync object */
DWORD free_clust; /* Number of free clusters */ #endif
#endif #if !_FS_READONLY
#if _FS_RPATH DWORD last_clst; /* Last allocated cluster */
DWORD cdir; /* Current directory start cluster (0:root) */ DWORD free_clst; /* Number of free clusters */
#endif #endif
DWORD n_fatent; /* Number of FAT entries, = number of clusters + 2 */ #if _FS_RPATH != 0
DWORD fsize; /* Sectors per FAT */ DWORD cdir; /* Current directory start cluster (0:root) */
DWORD volbase; /* Volume start sector */ #if _FS_EXFAT
DWORD fatbase; /* FAT start sector */ DWORD cdc_scl; /* Containing directory start cluster (invalid when cdir is 0) */
DWORD dirbase; /* Root directory start sector (FAT32:Cluster#) */ DWORD cdc_size; /* b31-b8:Size of containing directory, b7-b0: Chain status */
DWORD database; /* Data start sector */ DWORD cdc_ofs; /* Offset in the containing directory (invalid when cdir is 0) */
DWORD winsect; /* Current sector appearing in the win[] */ #endif
BYTE win[_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */ #endif
} FATFS; DWORD n_fatent; /* Number of FAT entries (number of clusters + 2) */
DWORD fsize; /* Size of an FAT [sectors] */
DWORD volbase; /* Volume base sector */
DWORD fatbase; /* FAT base sector */
/* File object structure (FIL) */ DWORD dirbase; /* Root directory base sector/cluster */
DWORD database; /* Data base sector */
typedef struct { DWORD winsect; /* Current sector appearing in the win[] */
FATFS* fs; /* Pointer to the related file system object (**do not change order**) */ BYTE win[_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */
WORD id; /* Owner file system mount ID (**do not change order**) */ } FATFS;
BYTE flag; /* Status flags */
BYTE err; /* Abort flag (error code) */
DWORD fptr; /* File read/write pointer (Zeroed on file open) */
DWORD fsize; /* File size */ /* Type of file size variables and object identifier */
DWORD sclust; /* File start cluster (0:no cluster chain, always 0 when fsize is 0) */
DWORD clust; /* Current cluster of fpter (not valid when fprt is 0) */ #if _FS_EXFAT
DWORD dsect; /* Sector number appearing in buf[] (0:invalid) */ #if _USE_LFN == 0
#if !_FS_READONLY #error LFN must be enabled when enable exFAT
DWORD dir_sect; /* Sector number containing the directory entry */ #endif
BYTE* dir_ptr; /* Pointer to the directory entry in the win[] */ typedef QWORD FSIZE_t;
#endif #else
#if _USE_FASTSEEK typedef DWORD FSIZE_t;
DWORD* cltbl; /* Pointer to the cluster link map table (Nulled on file open) */ #endif
#endif
#if _FS_LOCK
UINT lockid; /* File lock ID origin from 1 (index of file semaphore table Files[]) */
#endif /* Object ID and allocation information (_FDID) */
#if !_FS_TINY
BYTE buf[_MAX_SS]; /* File private data read/write window */ typedef struct {
#endif FATFS* fs; /* Pointer to the owner file system object */
} FIL; WORD id; /* Owner file system mount ID */
BYTE attr; /* Object attribute */
BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous (no data on FAT), =3:got flagmented, b2:sub-directory stretched) */
DWORD sclust; /* Object start cluster (0:no cluster or root directory) */
/* Directory object structure (DIR) */ FSIZE_t objsize; /* Object size (valid when sclust != 0) */
#if _FS_EXFAT
typedef struct { DWORD n_cont; /* Size of coutiguous part, clusters - 1 (valid when stat == 3) */
FATFS* fs; /* Pointer to the owner file system object (**do not change order**) */ DWORD c_scl; /* Containing directory start cluster (valid when sclust != 0) */
WORD id; /* Owner file system mount ID (**do not change order**) */ DWORD c_size; /* b31-b8:Size of containing directory, b7-b0: Chain status (valid when c_scl != 0) */
WORD index; /* Current read/write index number */ DWORD c_ofs; /* Offset in the containing directory (valid when sclust != 0) */
DWORD sclust; /* Table start cluster (0:Root dir) */ #endif
DWORD clust; /* Current cluster */ #if _FS_LOCK != 0
DWORD sect; /* Current sector */ UINT lockid; /* File lock ID origin from 1 (index of file semaphore table Files[]) */
BYTE* dir; /* Pointer to the current SFN entry in the win[] */ #endif
BYTE* fn; /* Pointer to the SFN (in/out) {file[8],ext[3],status[1]} */ } _FDID;
#if _FS_LOCK
UINT lockid; /* File lock ID (index of file semaphore table Files[]) */
#endif
#if _USE_LFN /* File object structure (FIL) */
WCHAR* lfn; /* Pointer to the LFN working buffer */
WORD lfn_idx; /* Last matched LFN index number (0xFFFF:No LFN) */ typedef struct {
#endif _FDID obj; /* Object identifier */
#if _USE_FIND BYTE flag; /* File status flags */
const TCHAR* pat; /* Pointer to the name matching pattern */ BYTE err; /* Abort flag (error code) */
#endif FSIZE_t fptr; /* File read/write pointer (Zeroed on file open) */
} DIR; DWORD clust; /* Current cluster of fpter (not valid when fprt is 0) */
DWORD sect; /* Sector number appearing in buf[] (0:invalid) */
#if !_FS_READONLY
DWORD dir_sect; /* Sector number containing the directory entry */
/* File information structure (FILINFO) */ BYTE* dir_ptr; /* Pointer to the directory entry in the win[] */
#endif
typedef struct { #if _USE_FASTSEEK
DWORD fsize; /* File size */ DWORD* cltbl; /* Pointer to the cluster link map table (Nulled on file open) */
WORD fdate; /* Last modified date */ #endif
WORD ftime; /* Last modified time */ #if !_FS_TINY
BYTE fattrib; /* Attribute */ BYTE buf[_MAX_SS]; /* File private data read/write window */
TCHAR fname[13]; /* Short file name (8.3 format) */ #endif
#if _USE_LFN } FIL;
TCHAR* lfname; /* Pointer to the LFN buffer */
UINT lfsize; /* Size of LFN buffer in TCHAR */
#endif
} FILINFO; /* Directory object structure (DIR) */
typedef struct {
_FDID obj; /* Object identifier */
/* File function return code (FRESULT) */ DWORD dptr; /* Current read/write offset */
DWORD clust; /* Current cluster */
typedef enum { DWORD sect; /* Current sector */
FR_OK = 0, /* (0) Succeeded */ BYTE* dir; /* Pointer to the directory item in the win[] */
FR_DISK_ERR, /* (1) A hard error occurred in the low level disk I/O layer */ BYTE* fn; /* Pointer to the SFN (in/out) {body[8],ext[3],status[1]} */
FR_INT_ERR, /* (2) Assertion failed */ #if _USE_LFN != 0
FR_NOT_READY, /* (3) The physical drive cannot work */ DWORD blk_ofs; /* Offset of current entry block being processed (0xFFFFFFFF:Invalid) */
FR_NO_FILE, /* (4) Could not find the file */ WCHAR* lfn; /* Pointer to the LFN working buffer */
FR_NO_PATH, /* (5) Could not find the path */ #endif
FR_INVALID_NAME, /* (6) The path name format is invalid */ #if _USE_FIND
FR_DENIED, /* (7) Access denied due to prohibited access or directory full */ const TCHAR* pat; /* Pointer to the name matching pattern */
FR_EXIST, /* (8) Access denied due to prohibited access */ #endif
FR_INVALID_OBJECT, /* (9) The file/directory object is invalid */ } DIR;
FR_WRITE_PROTECTED, /* (10) The physical drive is write protected */
FR_INVALID_DRIVE, /* (11) The logical drive number is invalid */
FR_NOT_ENABLED, /* (12) The volume has no work area */
FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume */ /* File information structure (FILINFO) */
FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any parameter error */
FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */ typedef struct {
FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */ FSIZE_t fsize; /* File size */
FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */ WORD fdate; /* Modified date */
FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > _FS_SHARE */ WORD ftime; /* Modified time */
FR_INVALID_PARAMETER /* (19) Given parameter is invalid */ BYTE fattrib; /* File attribute */
} FRESULT; #if _USE_LFN != 0
TCHAR altname[13]; /* Altenative file name */
TCHAR fname[_MAX_LFN + 1]; /* Primary file name */
#else
/*--------------------------------------------------------------*/ TCHAR fname[13]; /* File name */
/* FatFs module application interface */ #endif
} FILINFO;
FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */
FRESULT f_close (FIL* fp); /* Close an open file object */
FRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br); /* Read data from a file */
FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to a file */ /* File function return code (FRESULT) */
FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */
FRESULT f_lseek (FIL* fp, DWORD ofs); /* Move file pointer of a file object */ typedef enum {
FRESULT f_truncate (FIL* fp); /* Truncate file */ FR_OK = 0, /* (0) Succeeded */
FRESULT f_sync (FIL* fp); /* Flush cached data of a writing file */ FR_DISK_ERR, /* (1) A hard error occurred in the low level disk I/O layer */
FRESULT f_opendir (DIR* dp, const TCHAR* path); /* Open a directory */ FR_INT_ERR, /* (2) Assertion failed */
FRESULT f_closedir (DIR* dp); /* Close an open directory */ FR_NOT_READY, /* (3) The physical drive cannot work */
FRESULT f_readdir (DIR* dp, FILINFO* fno); /* Read a directory item */ FR_NO_FILE, /* (4) Could not find the file */
FRESULT f_findfirst (DIR* dp, FILINFO* fno, const TCHAR* path, const TCHAR* pattern); /* Find first file */ FR_NO_PATH, /* (5) Could not find the path */
FRESULT f_findnext (DIR* dp, FILINFO* fno); /* Find next file */ FR_INVALID_NAME, /* (6) The path name format is invalid */
FRESULT f_mkdir (const TCHAR* path); /* Create a sub directory */ FR_DENIED, /* (7) Access denied due to prohibited access or directory full */
FRESULT f_unlink (const TCHAR* path); /* Delete an existing file or directory */ FR_EXIST, /* (8) Access denied due to prohibited access */
FRESULT f_rename (const TCHAR* path_old, const TCHAR* path_new); /* Rename/Move a file or directory */ FR_INVALID_OBJECT, /* (9) The file/directory object is invalid */
FRESULT f_stat (const TCHAR* path, FILINFO* fno); /* Get file status */ FR_WRITE_PROTECTED, /* (10) The physical drive is write protected */
FRESULT f_chmod (const TCHAR* path, BYTE attr, BYTE mask); /* Change attribute of the file/dir */ FR_INVALID_DRIVE, /* (11) The logical drive number is invalid */
FRESULT f_utime (const TCHAR* path, const FILINFO* fno); /* Change times-tamp of the file/dir */ FR_NOT_ENABLED, /* (12) The volume has no work area */
FRESULT f_chdir (const TCHAR* path); /* Change current directory */ FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume */
FRESULT f_chdrive (const TCHAR* path); /* Change current drive */ FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any parameter error */
FRESULT f_getcwd (TCHAR* buff, UINT len); /* Get current directory */ FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */
FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs); /* Get number of free clusters on the drive */ FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */
FRESULT f_getlabel (const TCHAR* path, TCHAR* label, DWORD* vsn); /* Get volume label */ FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */
FRESULT f_setlabel (const TCHAR* label); /* Set volume label */ FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > _FS_LOCK */
FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */ FR_INVALID_PARAMETER /* (19) Given parameter is invalid */
FRESULT f_mkfs (const TCHAR* path, BYTE sfd, UINT au); /* Create a file system on the volume */ } FRESULT;
FRESULT f_fdisk (BYTE pdrv, const DWORD szt[], void* work); /* Divide a physical drive into some partitions */
int f_putc (TCHAR c, FIL* fp); /* Put a character to the file */
int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */
int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */ /*--------------------------------------------------------------*/
TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the file */ /* FatFs module application interface */
#define f_eof(fp) ((int)((fp)->fptr == (fp)->fsize)) FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */
#define f_error(fp) ((fp)->err) FRESULT f_close (FIL* fp); /* Close an open file object */
#define f_tell(fp) ((fp)->fptr) FRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br); /* Read data from a file */
#define f_size(fp) ((fp)->fsize) FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to a file */
#define f_rewind(fp) f_lseek((fp), 0) FRESULT f_lseek (FIL* fp, FSIZE_t ofs); /* Move file pointer of a file object */
#define f_rewinddir(dp) f_readdir((dp), 0) FRESULT f_truncate (FIL* fp); /* Truncate file */
FRESULT f_sync (FIL* fp); /* Flush cached data of a writing file */
#ifndef EOF FRESULT f_opendir (DIR* dp, const TCHAR* path); /* Open a directory */
#define EOF (-1) FRESULT f_closedir (DIR* dp); /* Close an open directory */
#endif FRESULT f_readdir (DIR* dp, FILINFO* fno); /* Read a directory item */
FRESULT f_findfirst (DIR* dp, FILINFO* fno, const TCHAR* path, const TCHAR* pattern); /* Find first file */
FRESULT f_findnext (DIR* dp, FILINFO* fno); /* Find next file */
FRESULT f_mkdir (const TCHAR* path); /* Create a sub directory */
FRESULT f_unlink (const TCHAR* path); /* Delete an existing file or directory */
/*--------------------------------------------------------------*/ FRESULT f_rename (const TCHAR* path_old, const TCHAR* path_new); /* Rename/Move a file or directory */
/* Additional user defined functions */ FRESULT f_stat (const TCHAR* path, FILINFO* fno); /* Get file status */
FRESULT f_chmod (const TCHAR* path, BYTE attr, BYTE mask); /* Change attribute of the file/dir */
/* RTC function */ FRESULT f_utime (const TCHAR* path, const FILINFO* fno); /* Change timestamp of the file/dir */
#if !_FS_READONLY && !_FS_NORTC FRESULT f_chdir (const TCHAR* path); /* Change current directory */
DWORD get_fattime (void); FRESULT f_chdrive (const TCHAR* path); /* Change current drive */
#endif FRESULT f_getcwd (TCHAR* buff, UINT len); /* Get current directory */
FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs); /* Get number of free clusters on the drive */
/* Unicode support functions */ FRESULT f_getlabel (const TCHAR* path, TCHAR* label, DWORD* vsn); /* Get volume label */
#if _USE_LFN /* Unicode - OEM code conversion */ FRESULT f_setlabel (const TCHAR* label); /* Set volume label */
WCHAR ff_convert (WCHAR chr, UINT dir); /* OEM-Unicode bidirectional conversion */ FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */
WCHAR ff_wtoupper (WCHAR chr); /* Unicode upper-case conversion */ FRESULT f_expand (FIL* fp, FSIZE_t szf, BYTE opt); /* Allocate a contiguous block to the file */
#if _USE_LFN == 3 /* Memory functions */ FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */
void* ff_memalloc (UINT msize); /* Allocate memory block */ FRESULT f_mkfs (const TCHAR* path, BYTE sfd, UINT au); /* Create a file system on the volume */
void ff_memfree (void* mblock); /* Free memory block */ FRESULT f_fdisk (BYTE pdrv, const DWORD szt[], void* work); /* Divide a physical drive into some partitions */
#endif int f_putc (TCHAR c, FIL* fp); /* Put a character to the file */
#endif int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */
int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */
/* Sync functions */ TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the file */
#if _FS_REENTRANT
int ff_cre_syncobj (BYTE vol, _SYNC_t* sobj); /* Create a sync object */ #define f_eof(fp) ((int)((fp)->fptr == (fp)->obj.objsize))
int ff_req_grant (_SYNC_t sobj); /* Lock sync object */ #define f_error(fp) ((fp)->err)
void ff_rel_grant (_SYNC_t sobj); /* Unlock sync object */ #define f_tell(fp) ((fp)->fptr)
int ff_del_syncobj (_SYNC_t sobj); /* Delete a sync object */ #define f_size(fp) ((fp)->obj.objsize)
#endif #define f_rewind(fp) f_lseek((fp), 0)
#define f_rewinddir(dp) f_readdir((dp), 0)
#ifndef EOF
#define EOF (-1)
/*--------------------------------------------------------------*/ #endif
/* Flags and offset address */
/* File access control and file status flags (FIL.flag) */
/*--------------------------------------------------------------*/
#define FA_READ 0x01 /* Additional user defined functions */
#define FA_OPEN_EXISTING 0x00
/* RTC function */
#if !_FS_READONLY #if !_FS_READONLY && !_FS_NORTC
#define FA_WRITE 0x02 DWORD get_fattime (void);
#define FA_CREATE_NEW 0x04 #endif
#define FA_CREATE_ALWAYS 0x08
#define FA_OPEN_ALWAYS 0x10 /* Unicode support functions */
#define FA__WRITTEN 0x20 #if _USE_LFN != 0 /* Unicode - OEM code conversion */
#define FA__DIRTY 0x40 WCHAR ff_convert (WCHAR chr, UINT dir); /* OEM-Unicode bidirectional conversion */
#endif WCHAR ff_wtoupper (WCHAR chr); /* Unicode upper-case conversion */
#if _USE_LFN == 3 /* Memory functions */
void* ff_memalloc (UINT msize); /* Allocate memory block */
/* FAT sub type (FATFS.fs_type) */ void ff_memfree (void* mblock); /* Free memory block */
#endif
#define FS_FAT12 1 #endif
#define FS_FAT16 2
#define FS_FAT32 3 /* Sync functions */
#if _FS_REENTRANT
int ff_cre_syncobj (BYTE vol, _SYNC_t* sobj); /* Create a sync object */
/* File attribute bits for directory entry */ int ff_req_grant (_SYNC_t sobj); /* Lock sync object */
void ff_rel_grant (_SYNC_t sobj); /* Unlock sync object */
#define AM_RDO 0x01 /* Read only */ int ff_del_syncobj (_SYNC_t sobj); /* Delete a sync object */
#define AM_HID 0x02 /* Hidden */ #endif
#define AM_SYS 0x04 /* System */
#define AM_VOL 0x08 /* Volume label */
#define AM_LFN 0x0F /* LFN entry */
#define AM_DIR 0x10 /* Directory */
#define AM_ARC 0x20 /* Archive */ /*--------------------------------------------------------------*/
#define AM_MASK 0x3F /* Mask of defined bits */ /* Flags and offset address */
/* Fast seek feature */ /* File access control and file status flags (FIL.flag) */
#define CREATE_LINKMAP 0xFFFFFFFF
#define FA_READ 0x01
#define FA_WRITE 0x02
#define FA_OPEN_EXISTING 0x00
/*--------------------------------*/ #define FA_CREATE_NEW 0x04
/* Multi-byte word access macros */ #define FA_CREATE_ALWAYS 0x08
#define FA_OPEN_ALWAYS 0x10
#if _WORD_ACCESS == 1 /* Enable word access to the FAT structure */ #define _FA_MODIFIED 0x20
#define LD_WORD(ptr) (WORD)(*(WORD*)(BYTE*)(ptr)) #define _FA_DIRTY 0x40
#define LD_DWORD(ptr) (DWORD)(*(DWORD*)(BYTE*)(ptr))
#define ST_WORD(ptr,val) *(WORD*)(BYTE*)(ptr)=(WORD)(val)
#define ST_DWORD(ptr,val) *(DWORD*)(BYTE*)(ptr)=(DWORD)(val) /* FAT sub type (FATFS.fs_type) */
#else /* Use byte-by-byte access to the FAT structure */
#define LD_WORD(ptr) (WORD)(((WORD)*((BYTE*)(ptr)+1)<<8)|(WORD)*(BYTE*)(ptr)) #define FS_FAT12 1
#define LD_DWORD(ptr) (DWORD)(((DWORD)*((BYTE*)(ptr)+3)<<24)|((DWORD)*((BYTE*)(ptr)+2)<<16)|((WORD)*((BYTE*)(ptr)+1)<<8)|*(BYTE*)(ptr)) #define FS_FAT16 2
#define ST_WORD(ptr,val) *(BYTE*)(ptr)=(BYTE)(val); *((BYTE*)(ptr)+1)=(BYTE)((WORD)(val)>>8) #define FS_FAT32 3
#define ST_DWORD(ptr,val) *(BYTE*)(ptr)=(BYTE)(val); *((BYTE*)(ptr)+1)=(BYTE)((WORD)(val)>>8); *((BYTE*)(ptr)+2)=(BYTE)((DWORD)(val)>>16); *((BYTE*)(ptr)+3)=(BYTE)((DWORD)(val)>>24) #define FS_EXFAT 4
#endif
#ifdef __cplusplus /* File attribute bits for directory entry */
}
#endif #define AM_RDO 0x01 /* Read only */
#define AM_HID 0x02 /* Hidden */
#endif /* _FATFS */ #define AM_SYS 0x04 /* System */
#define AM_VOL 0x08 /* Volume label */
#define AM_LFN 0x0F /* LFN entry */
#define AM_DIR 0x10 /* Directory */
#define AM_ARC 0x20 /* Archive */
#define AM_MASK 0x3F /* Mask of defined bits */
/* Fast seek controls */
#define CREATE_LINKMAP ((FSIZE_t)0 - 1)
#ifdef __cplusplus
}
#endif
#endif /* _FATFS */

View File

@@ -1,271 +1,266 @@
/*---------------------------------------------------------------------------/ /*---------------------------------------------------------------------------/
/ FatFs - FAT file system module configuration file R0.11 (C)ChaN, 2015 / FatFs - FAT file system module configuration file R0.12 (C)ChaN, 2016
/---------------------------------------------------------------------------*/ /---------------------------------------------------------------------------*/
#define _FFCONF 32020 /* Revision ID */ #define _FFCONF 88100 /* Revision ID */
/*---------------------------------------------------------------------------/ /*---------------------------------------------------------------------------/
/ Functions and Buffer Configurations / Function Configurations
/---------------------------------------------------------------------------*/ /---------------------------------------------------------------------------*/
#define _FS_TINY 0 #define _FS_READONLY 0
/* This option switches tiny buffer configuration. (0:Normal or 1:Tiny) /* This option switches read-only configuration. (0:Read/Write or 1:Read-only)
/ At the tiny configuration, size of the file object (FIL) is reduced _MAX_SS / Read-only configuration removes writing API functions, f_write(), f_sync(),
/ bytes. Instead of private sector buffer eliminated from the file object, / f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree()
/ common sector buffer in the file system object (FATFS) is used for the file / and optional writing functions as well. */
/ data transfer. */
#define _FS_MINIMIZE 1
#define _FS_READONLY 0 /* This option defines minimization level to remove some basic API functions.
/* This option switches read-only configuration. (0:Read/Write or 1:Read-only) /
/ Read-only configuration removes writing API functions, f_write(), f_sync(), / 0: All basic functions are enabled.
/ f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree() / 1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_truncate() and f_rename()
/ and optional writing functions as well. */ / are removed.
/ 2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1.
/ 3: f_lseek() function is removed in addition to 2. */
#define _FS_MINIMIZE 0
/* This option defines minimization level to remove some basic API functions.
/ #define _USE_STRFUNC 0
/ 0: All basic functions are enabled. /* This option switches string functions, f_gets(), f_putc(), f_puts() and
/ 1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_chmod(), f_utime(), / f_printf().
/ f_truncate() and f_rename() function are removed. /
/ 2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1. / 0: Disable string functions.
/ 3: f_lseek() function is removed in addition to 2. */ / 1: Enable without LF-CRLF conversion.
/ 2: Enable with LF-CRLF conversion. */
#define _USE_STRFUNC 0
/* This option switches string functions, f_gets(), f_putc(), f_puts() and #define _USE_FIND 1
/ f_printf(). /* This option switches filtered directory read functions, f_findfirst() and
/ / f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */
/ 0: Disable string functions.
/ 1: Enable without LF-CRLF conversion.
/ 2: Enable with LF-CRLF conversion. */ #define _USE_MKFS 0
/* This option switches f_mkfs() function. (0:Disable or 1:Enable) */
#define _USE_FIND 0
/* This option switches filtered directory read feature and related functions, #define _USE_FASTSEEK 0
/ f_findfirst() and f_findnext(). (0:Disable or 1:Enable) */ /* This option switches fast seek function. (0:Disable or 1:Enable) */
#define _USE_MKFS 0 #define _USE_EXPAND 0
/* This option switches f_mkfs() function. (0:Disable or 1:Enable) */ /* This option switches f_expand function. (0:Disable or 1:Enable) */
#define _USE_FASTSEEK 0 #define _USE_CHMOD 0
/* This option switches fast seek feature. (0:Disable or 1:Enable) */ /* This option switches attribute manipulation functions, f_chmod() and f_utime().
/ (0:Disable or 1:Enable) Also _FS_READONLY needs to be 0 to enable this option. */
#define _USE_LABEL 0
/* This option switches volume label functions, f_getlabel() and f_setlabel(). #define _USE_LABEL 0
/ (0:Disable or 1:Enable) */ /* This option switches volume label functions, f_getlabel() and f_setlabel().
/ (0:Disable or 1:Enable) */
#define _USE_FORWARD 0
/* This option switches f_forward() function. (0:Disable or 1:Enable) #define _USE_FORWARD 0
/ To enable it, also _FS_TINY need to be set to 1. */ /* This option switches f_forward() function. (0:Disable or 1:Enable)
/ To enable it, also _FS_TINY need to be 1. */
/*---------------------------------------------------------------------------/
/ Locale and Namespace Configurations /*---------------------------------------------------------------------------/
/---------------------------------------------------------------------------*/ / Locale and Namespace Configurations
/---------------------------------------------------------------------------*/
#define _CODE_PAGE 437
/* This option specifies the OEM code page to be used on the target system. #define _CODE_PAGE 437
/ Incorrect setting of the code page can cause a file open failure. /* 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.
/ 1 - ASCII (No extended character. Non-LFN cfg. only) /
/ 437 - U.S. / 1 - ASCII (No extended character. Non-LFN cfg. only)
/ 720 - Arabic / 437 - U.S.
/ 737 - Greek / 720 - Arabic
/ 775 - Baltic / 737 - Greek
/ 850 - Multilingual Latin 1 / 771 - KBL
/ 852 - Latin 2 / 775 - Baltic
/ 855 - Cyrillic / 850 - Latin 1
/ 857 - Turkish / 852 - Latin 2
/ 858 - Multilingual Latin 1 + Euro / 855 - Cyrillic
/ 862 - Hebrew / 857 - Turkish
/ 866 - Russian / 860 - Portuguese
/ 874 - Thai / 861 - Icelandic
/ 932 - Japanese Shift_JIS (DBCS) / 862 - Hebrew
/ 936 - Simplified Chinese GBK (DBCS) / 863 - Canadian French
/ 949 - Korean (DBCS) / 864 - Arabic
/ 950 - Traditional Chinese Big5 (DBCS) / 865 - Nordic
*/ / 866 - Russian
/ 869 - Greek 2
/ 932 - Japanese (DBCS)
#define _USE_LFN 2 / 936 - Simplified Chinese (DBCS)
#define _MAX_LFN 255 / 949 - Korean (DBCS)
/* The _USE_LFN option switches the LFN feature. / 950 - Traditional Chinese (DBCS)
/ */
/ 0: Disable LFN feature. _MAX_LFN has no effect.
/ 1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe.
/ 2: Enable LFN with dynamic working buffer on the STACK. #define _USE_LFN 2
/ 3: Enable LFN with dynamic working buffer on the HEAP. #define _MAX_LFN 255
/ /* The _USE_LFN switches the support of long file name (LFN).
/ When enable the LFN feature, Unicode handling functions (option/unicode.c) must /
/ be added to the project. The LFN working buffer occupies (_MAX_LFN + 1) * 2 bytes. / 0: Disable support of LFN. _MAX_LFN has no effect.
/ When use stack for the working buffer, take care on stack overflow. When use heap / 1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe.
/ memory for the working buffer, memory management functions, ff_memalloc() and / 2: Enable LFN with dynamic working buffer on the STACK.
/ ff_memfree(), must be added to the project. */ / 3: Enable LFN with dynamic working buffer on the HEAP.
/
/ To enable the LFN, Unicode handling functions (option/unicode.c) must be added
#define _LFN_UNICODE 0 / to the project. The working buffer occupies (_MAX_LFN + 1) * 2 bytes and
/* This option switches character encoding on the API. (0:ANSI/OEM or 1:Unicode) / additional 608 bytes at exFAT enabled. _MAX_LFN can be in range from 12 to 255.
/ To use Unicode string for the path name, enable LFN feature and set _LFN_UNICODE / It should be set 255 to support full featured LFN operations.
/ to 1. This option also affects behavior of string I/O functions. */ / When use stack for the working buffer, take care on stack overflow. When use heap
/ memory for the working buffer, memory management functions, ff_memalloc() and
/ ff_memfree(), must be added to the project. */
#define _STRF_ENCODE 0
/* 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(). #define _LFN_UNICODE 0
/ /* This option switches character encoding on the API. (0:ANSI/OEM or 1:Unicode)
/ 0: ANSI/OEM / To use Unicode string for the path name, enable LFN and set _LFN_UNICODE = 1.
/ 1: UTF-16LE / This option also affects behavior of string I/O functions. */
/ 2: UTF-16BE
/ 3: UTF-8
/ #define _STRF_ENCODE 3
/ When _LFN_UNICODE is 0, this option has no effect. */ /* When _LFN_UNICODE == 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().
/
#define _FS_RPATH 0 / 0: ANSI/OEM
/* This option configures relative path feature. / 1: UTF-16LE
/ / 2: UTF-16BE
/ 0: Disable relative path feature and remove related functions. / 3: UTF-8
/ 1: Enable relative path feature. f_chdir() and f_chdrive() are available. /
/ 2: f_getcwd() function is available in addition to 1. / This option has no effect when _LFN_UNICODE == 0. */
/
/ Note that directory items read via f_readdir() are affected by this option. */
#define _FS_RPATH 0
/* This option configures support of relative path.
/*---------------------------------------------------------------------------/ /
/ Drive/Volume Configurations / 0: Disable relative path and remove related functions.
/---------------------------------------------------------------------------*/ / 1: Enable relative path. f_chdir() and f_chdrive() are available.
/ 2: f_getcwd() function is available in addition to 1.
#define _VOLUMES 1 */
/* Number of volumes (logical drives) to be used. */
/*---------------------------------------------------------------------------/
#define _STR_VOLUME_ID 0 / Drive/Volume Configurations
#define _VOLUME_STRS "RAM","NAND","CF","SD1","SD2","USB1","USB2","USB3" /---------------------------------------------------------------------------*/
/* _STR_VOLUME_ID option switches string volume ID feature.
/ When _STR_VOLUME_ID is set to 1, also pre-defined strings can be used as drive #define _VOLUMES 2
/ number in the path name. _VOLUME_STRS defines the drive ID strings for each /* Number of volumes (logical drives) to be used. */
/ logical drives. Number of items must be equal to _VOLUMES. Valid characters for
/ the drive ID strings are: A-Z and 0-9. */
#define _STR_VOLUME_ID 0
#define _VOLUME_STRS "RAM","NAND","CF","SD1","SD2","USB1","USB2","USB3"
#define _MULTI_PARTITION 0 /* _STR_VOLUME_ID switches string support of volume ID.
/* This option switches multi-partition feature. By default (0), each logical drive / When _STR_VOLUME_ID is set to 1, also pre-defined strings can be used as drive
/ number is bound to the same physical drive number and only an FAT volume found on / number in the path name. _VOLUME_STRS defines the drive ID strings for each
/ the physical drive will be mounted. When multi-partition feature is enabled (1), / logical drives. Number of items must be equal to _VOLUMES. Valid characters for
/ each logical drive number is bound to arbitrary physical drive and partition / the drive ID strings are: A-Z and 0-9. */
/ listed in the VolToPart[]. Also f_fdisk() funciton will be available. */
#define _MULTI_PARTITION 0
#define _MIN_SS 512 /* This option switches support of multi-partition on a physical drive.
#define _MAX_SS 512 / By default (0), each logical drive number is bound to the same physical drive
/* These options configure the range of sector size to be supported. (512, 1024, / number and only an FAT volume found on the physical drive will be mounted.
/ 2048 or 4096) Always set both 512 for most systems, all type of memory cards and / When multi-partition is enabled (1), each logical drive number can be bound to
/ harddisk. But a larger value may be required for on-board flash memory and some / arbitrary physical drive and partition listed in the VolToPart[]. Also f_fdisk()
/ type of optical media. When _MAX_SS is larger than _MIN_SS, FatFs is configured / funciton will be available. */
/ to variable sector size and GET_SECTOR_SIZE command must be implemented to the
/ disk_ioctl() function. */
#define _MIN_SS 512
#define _MAX_SS 512
#define _USE_TRIM 0 /* These options configure the range of sector size to be supported. (512, 1024,
/* This option switches ATA-TRIM feature. (0:Disable or 1:Enable) / 2048 or 4096) Always set both 512 for most systems, all type of memory cards and
/ To enable Trim feature, also CTRL_TRIM command should be implemented to the / harddisk. But a larger value may be required for on-board flash memory and some
/ disk_ioctl() function. */ / type of optical media. When _MAX_SS is larger than _MIN_SS, FatFs is configured
/ to variable sector size and GET_SECTOR_SIZE command must be implemented to the
/ disk_ioctl() function. */
#define _FS_NOFSINFO 0
/* If you need to know correct free space on the FAT32 volume, set bit 0 of this
/ option, and f_getfree() function at first time after volume mount will force #define _USE_TRIM 0
/ a full FAT scan. Bit 1 controls the use of last allocated cluster number. /* This option switches support of ATA-TRIM. (0:Disable or 1:Enable)
/ / To enable Trim function, also CTRL_TRIM command should be implemented to the
/ bit0=0: Use free cluster count in the FSINFO if available. / disk_ioctl() function. */
/ bit0=1: Do not trust free cluster count in the FSINFO.
/ bit1=0: Use last allocated cluster number in the FSINFO if available.
/ bit1=1: Do not trust last allocated cluster number in the FSINFO. #define _FS_NOFSINFO 0
*/ /* If you need to know correct free space on the FAT32 volume, set bit 0 of this
/ option, and f_getfree() function at first time after volume mount will force
/ a full FAT scan. Bit 1 controls the use of last allocated cluster number.
/
/*---------------------------------------------------------------------------/ / bit0=0: Use free cluster count in the FSINFO if available.
/ System Configurations / bit0=1: Do not trust free cluster count in the FSINFO.
/---------------------------------------------------------------------------*/ / bit1=0: Use last allocated cluster number in the FSINFO if available.
/ bit1=1: Do not trust last allocated cluster number in the FSINFO.
#define _FS_NORTC 1 */
#define _NORTC_MON 2
#define _NORTC_MDAY 1
#define _NORTC_YEAR 2015
/* 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 / System Configurations
/ the timestamp feature. All objects modified by FatFs will have a fixed timestamp /---------------------------------------------------------------------------*/
/ defined by _NORTC_MON, _NORTC_MDAY and _NORTC_YEAR.
/ When timestamp feature is enabled (_FS_NORTC == 0), get_fattime() function need #define _FS_TINY 0
/ to be added to the project to read current time form RTC. _NORTC_MON, /* This option switches tiny buffer configuration. (0:Normal or 1:Tiny)
/ _NORTC_MDAY and _NORTC_YEAR have no effect. / At the tiny configuration, size of the file object (FIL) is reduced _MAX_SS bytes.
/ These options have no effect at read-only configuration (_FS_READONLY == 1). */ / 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_LOCK 0
/* The _FS_LOCK option switches file lock feature to control duplicated file open #define _FS_EXFAT 0
/ and illegal operation to open objects. This option must be 0 when _FS_READONLY /* This option switches support of exFAT file system in addition to the traditional
/ is 1. / FAT file system. (0:Disable or 1:Enable) To enable exFAT, also LFN must be enabled.
/ / Note that enabling exFAT discards C89 compatibility. */
/ 0: Disable file lock feature. To avoid volume corruption, application program
/ should avoid illegal open, remove and rename to the open objects.
/ >0: Enable file lock feature. The value defines how many files/sub-directories #define _FS_NORTC 1
/ can be opened simultaneously under file lock control. Note that the file #define _NORTC_MON 3
/ lock feature is independent of re-entrancy. */ #define _NORTC_MDAY 1
#define _NORTC_YEAR 2016
/* The option _FS_NORTC switches timestamp functiton. If the system does not have
#define _FS_REENTRANT 0 / any RTC function or valid timestamp is not needed, set _FS_NORTC = 1 to disable
#define _FS_TIMEOUT 1000 / the timestamp function. All objects modified by FatFs will have a fixed timestamp
#define _SYNC_t HANDLE / defined by _NORTC_MON, _NORTC_MDAY and _NORTC_YEAR in local time.
/* The _FS_REENTRANT option switches the re-entrancy (thread safe) of the FatFs / To enable timestamp function (_FS_NORTC = 0), get_fattime() function need to be
/ module itself. Note that regardless of this option, file access to different / added to the project to get current time form real-time clock. _NORTC_MON,
/ volume is always re-entrant and volume control functions, f_mount(), f_mkfs() / _NORTC_MDAY and _NORTC_YEAR have no effect.
/ and f_fdisk() function, are always not re-entrant. Only file/directory access / These options have no effect at read-only configuration (_FS_READONLY = 1). */
/ to the same volume is under control of this feature.
/
/ 0: Disable re-entrancy. _FS_TIMEOUT and _SYNC_t have no effect. #define _FS_LOCK 0
/ 1: Enable re-entrancy. Also user provided synchronization handlers, /* The option _FS_LOCK switches file lock function to control duplicated file open
/ ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj() / and illegal operation to open objects. This option must be 0 when _FS_READONLY
/ function, must be added to the project. Samples are available in / is 1.
/ option/syscall.c. /
/ / 0: Disable file lock function. To avoid volume corruption, application program
/ The _FS_TIMEOUT defines timeout period in unit of time tick. / should avoid illegal open, remove and rename to the open objects.
/ The _SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*, / >0: Enable file lock function. The value defines how many files/sub-directories
/ SemaphoreHandle_t and etc.. A header file for O/S definitions needs to be / can be opened simultaneously under file lock control. Note that the file
/ included somewhere in the scope of ff.c. */ / lock control is independent of re-entrancy. */
#define _WORD_ACCESS 0 #define _FS_REENTRANT 0
/* The _WORD_ACCESS option is an only platform dependent option. It defines #define _FS_TIMEOUT 1000
/ which access method is used to the word data on the FAT volume. #define _SYNC_t HANDLE
/ /* The option _FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs
/ 0: Byte-by-byte access. Always compatible with all platforms. / module itself. Note that regardless of this option, file access to different
/ 1: Word access. Do not choose this unless under both the following conditions. / volume is always re-entrant and volume control functions, f_mount(), f_mkfs()
/ / and f_fdisk() function, are always not re-entrant. Only file/directory access
/ * Address misaligned memory access is always allowed to ALL instructions. / to the same volume is under control of this function.
/ * Byte order on the memory is little-endian. /
/ / 0: Disable re-entrancy. _FS_TIMEOUT and _SYNC_t have no effect.
/ If it is the case, _WORD_ACCESS can also be set to 1 to reduce code size. / 1: Enable re-entrancy. Also user provided synchronization handlers,
/ Following table shows allowable settings of some processor types. / ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj()
/ / function, must be added to the project. Samples are available in
/ ARM7TDMI 0 *2 ColdFire 0 *1 V850E 0 *2 / option/syscall.c.
/ Cortex-M3 0 *3 Z80 0/1 V850ES 0/1 /
/ Cortex-M0 0 *2 x86 0/1 TLCS-870 0/1 / The _FS_TIMEOUT defines timeout period in unit of time tick.
/ AVR 0/1 RX600(LE) 0/1 TLCS-900 0/1 / The _SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*,
/ AVR32 0 *1 RL78 0 *2 R32C 0 *2 / SemaphoreHandle_t and etc.. A header file for O/S definitions needs to be
/ PIC18 0/1 SH-2 0 *1 M16C 0/1 / included somewhere in the scope of ff.c. */
/ PIC24 0 *2 H8S 0 *1 MSP430 0 *2
/ PIC32 0 *1 H8/300H 0 *1 8051 0/1
/ /*--- End of configuration options ---*/
/ *1:Big-endian.
/ *2:Unaligned memory access is not supported.
/ *3:Some compilers generate LDM/STM for mem_cpy function.
*/

View File

@@ -1,33 +1,38 @@
/*-------------------------------------------*/ /*-------------------------------------------*/
/* Integer type definitions for FatFs module */ /* Integer type definitions for FatFs module */
/*-------------------------------------------*/ /*-------------------------------------------*/
#ifndef _FF_INTEGER #ifndef _FF_INTEGER
#define _FF_INTEGER #define _FF_INTEGER
#ifdef _WIN32 /* FatFs development platform */ #ifdef _WIN32 /* FatFs development platform */
#include <windows.h> #include <windows.h>
#include <tchar.h> #include <tchar.h>
typedef unsigned __int64 QWORD;
#else /* Embedded platform */
/* This type MUST be 8 bit */ #else /* Embedded platform */
typedef unsigned char BYTE;
/* These types MUST be 16-bit or 32-bit */
/* These types MUST be 16 bit */ typedef int INT;
typedef short SHORT; typedef unsigned int UINT;
typedef unsigned short WORD;
typedef unsigned short WCHAR; /* This type MUST be 8-bit */
typedef unsigned char BYTE;
/* These types MUST be 16 bit or 32 bit */
typedef int INT; /* These types MUST be 16-bit */
typedef unsigned int UINT; typedef short SHORT;
typedef unsigned short WORD;
/* These types MUST be 32 bit */ typedef unsigned short WCHAR;
typedef long LONG;
typedef unsigned long DWORD; /* These types MUST be 32-bit */
typedef long LONG;
#endif typedef unsigned long DWORD;
#endif /* This type MUST be 64-bit (Remove this for C89 compatibility) */
typedef unsigned long long QWORD;
#endif
#endif

View File

@@ -0,0 +1,388 @@
/*------------------------------------------------------------------------*/
/* 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 (BMP only) */
)
{
/* Compressed upper conversion table */
static const WCHAR cvt1[] = { /* U+0000 - U+0FFF */
/* Basic Latin */
0x0061,0x031A,
/* Latin-1 Supplement */
0x00E0,0x0317, 0x00F8,0x0307, 0x00FF,0x0001,0x0178,
/* Latin Extended-A */
0x0100,0x0130, 0x0132,0x0106, 0x0139,0x0110, 0x014A,0x012E, 0x0179,0x0106,
/* Latin Extended-B */
0x0180,0x004D,0x0243,0x0181,0x0182,0x0182,0x0184,0x0184,0x0186,0x0187,0x0187,0x0189,0x018A,0x018B,0x018B,0x018D,0x018E,0x018F,0x0190,0x0191,0x0191,0x0193,0x0194,0x01F6,0x0196,0x0197,0x0198,0x0198,0x023D,0x019B,0x019C,0x019D,0x0220,0x019F,0x01A0,0x01A0,0x01A2,0x01A2,0x01A4,0x01A4,0x01A6,0x01A7,0x01A7,0x01A9,0x01AA,0x01AB,0x01AC,0x01AC,0x01AE,0x01AF,0x01AF,0x01B1,0x01B2,0x01B3,0x01B3,0x01B5,0x01B5,0x01B7,0x01B8,0x01B8,0x01BA,0x01BB,0x01BC,0x01BC,0x01BE,0x01F7,0x01C0,0x01C1,0x01C2,0x01C3,0x01C4,0x01C5,0x01C4,0x01C7,0x01C8,0x01C7,0x01CA,0x01CB,0x01CA,
0x01CD,0x0110, 0x01DD,0x0001,0x018E, 0x01DE,0x0112, 0x01F3,0x0003,0x01F1,0x01F4,0x01F4, 0x01F8,0x0128,
0x0222,0x0112, 0x023A,0x0009,0x2C65,0x023B,0x023B,0x023D,0x2C66,0x023F,0x0240,0x0241,0x0241, 0x0246,0x010A,
/* IPA Extensions */
0x0253,0x0040,0x0181,0x0186,0x0255,0x0189,0x018A,0x0258,0x018F,0x025A,0x0190,0x025C,0x025D,0x025E,0x025F,0x0193,0x0261,0x0262,0x0194,0x0264,0x0265,0x0266,0x0267,0x0197,0x0196,0x026A,0x2C62,0x026C,0x026D,0x026E,0x019C,0x0270,0x0271,0x019D,0x0273,0x0274,0x019F,0x0276,0x0277,0x0278,0x0279,0x027A,0x027B,0x027C,0x2C64,0x027E,0x027F,0x01A6,0x0281,0x0282,0x01A9,0x0284,0x0285,0x0286,0x0287,0x01AE,0x0244,0x01B1,0x01B2,0x0245,0x028D,0x028E,0x028F,0x0290,0x0291,0x01B7,
/* Greek, Coptic */
0x037B,0x0003,0x03FD,0x03FE,0x03FF, 0x03AC,0x0004,0x0386,0x0388,0x0389,0x038A, 0x03B1,0x0311,
0x03C2,0x0002,0x03A3,0x03A3, 0x03C4,0x0308, 0x03CC,0x0003,0x038C,0x038E,0x038F, 0x03D8,0x0118,
0x03F2,0x000A,0x03F9,0x03F3,0x03F4,0x03F5,0x03F6,0x03F7,0x03F7,0x03F9,0x03FA,0x03FA,
/* Cyrillic */
0x0430,0x0320, 0x0450,0x0710, 0x0460,0x0122, 0x048A,0x0136, 0x04C1,0x010E, 0x04CF,0x0001,0x04C0, 0x04D0,0x0144,
/* Armenian */
0x0561,0x0426,
0x0000
};
static const WCHAR cvt2[] = { /* U+1000 - U+FFFF */
/* Phonetic Extensions */
0x1D7D,0x0001,0x2C63,
/* Latin Extended Additional */
0x1E00,0x0196, 0x1EA0,0x015A,
/* Greek Extended */
0x1F00,0x0608, 0x1F10,0x0606, 0x1F20,0x0608, 0x1F30,0x0608, 0x1F40,0x0606,
0x1F51,0x0007,0x1F59,0x1F52,0x1F5B,0x1F54,0x1F5D,0x1F56,0x1F5F, 0x1F60,0x0608,
0x1F70,0x000E,0x1FBA,0x1FBB,0x1FC8,0x1FC9,0x1FCA,0x1FCB,0x1FDA,0x1FDB,0x1FF8,0x1FF9,0x1FEA,0x1FEB,0x1FFA,0x1FFB,
0x1F80,0x0608, 0x1F90,0x0608, 0x1FA0,0x0608, 0x1FB0,0x0004,0x1FB8,0x1FB9,0x1FB2,0x1FBC,
0x1FCC,0x0001,0x1FC3, 0x1FD0,0x0602, 0x1FE0,0x0602, 0x1FE5,0x0001,0x1FEC, 0x1FF2,0x0001,0x1FFC,
/* Letterlike Symbols */
0x214E,0x0001,0x2132,
/* Number forms */
0x2170,0x0210, 0x2184,0x0001,0x2183,
/* Enclosed Alphanumerics */
0x24D0,0x051A, 0x2C30,0x042F,
/* Latin Extended-C */
0x2C60,0x0102, 0x2C67,0x0106, 0x2C75,0x0102,
/* Coptic */
0x2C80,0x0164,
/* Georgian Supplement */
0x2D00,0x0826,
/* Full-width */
0xFF41,0x031A,
0x0000
};
const WCHAR *p;
WCHAR bc, nc, cmd;
p = chr < 0x1000 ? cvt1 : cvt2;
for (;;) {
bc = *p++; /* Get block base */
if (!bc || chr < bc) break;
nc = *p++; cmd = nc >> 8; nc &= 0xFF; /* Get processing command and block size */
if (chr < bc + nc) { /* In the block? */
switch (cmd) {
case 0: chr = p[chr - bc]; break; /* Table conversion */
case 1: chr -= (chr - bc) & 1; break; /* Case pairs */
case 2: chr -= 16; break; /* Shift -16 */
case 3: chr -= 32; break; /* Shift -32 */
case 4: chr -= 48; break; /* Shift -48 */
case 5: chr -= 26; break; /* Shift -26 */
case 6: chr += 8; break; /* Shift +8 */
case 7: chr -= 80; break; /* Shift -80 */
case 8: chr -= 0x1C60; break; /* Shift -0x1C60 */
}
break;
}
if (!cmd) p += nc;
}
return chr;
}

View File

@@ -1,4 +1,5 @@
#pragma once #pragma once
#include <stdbool.h> #include <stdbool.h>
#include "../../types.h" #include "../../types.h"
#include "../../crypto.h"

View File

@@ -194,22 +194,6 @@ u32 __attribute__((noinline)) sdmmc_nand_readsectors(u32 sector_no, u32 numsecto
return geterror(&handleNAND); return geterror(&handleNAND);
} }
u32 __attribute__((noinline)) sdmmc_nand_writesectors(u32 sector_no, u32 numsectors, vu8 *in) //experimental
{
if (handleNAND.isSDHC == 0)
sector_no <<= 9;
inittarget(&handleNAND);
sdmmc_write16(REG_SDSTOP,0x100);
sdmmc_write16(REG_SDBLKCOUNT,numsectors);
handleNAND.data = in;
handleNAND.size = numsectors << 9;
sdmmc_send_command(&handleNAND,0x52C19,sector_no);
inittarget(&handleSD);
return geterror(&handleNAND);
}
static u32 calcSDSize(u8* csd, int type) static u32 calcSDSize(u8* csd, int type)
{ {
u32 result = 0; u32 result = 0;
@@ -395,10 +379,51 @@ static int SD_Init()
return 0; return 0;
} }
int sdmmc_sdcard_init() void sdmmc_sdcard_init()
{ {
InitSD(); InitSD();
int result = Nand_Init(); Nand_Init();
return result | SD_Init(); 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

@@ -118,10 +118,12 @@ typedef struct mmcdevice {
u32 res; u32 res;
} mmcdevice; } mmcdevice;
int sdmmc_sdcard_init();
u32 sdmmc_sdcard_readsectors(u32 sector_no, u32 numsectors, vu8 *out);
u32 sdmmc_sdcard_writesectors(u32 sector_no, u32 numsectors, vu8 *in);
mmcdevice *getMMCDevice(int drive); mmcdevice *getMMCDevice(int drive);
void sdmmc_sdcard_init();
u32 sdmmc_sdcard_readsectors(u32 sector_no, u32 numsectors, vu8 *out);
u32 sdmmc_sdcard_writesectors(u32 sector_no, u32 numsectors, vu8 *in);
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);
int sdmmc_get_cid( int isNand, uint32_t *info);

View File

@@ -1,183 +1,266 @@
/* /*
* firm.c * firm.c
* by Reisyukaku / Aurora Wright
* Copyright (c) 2016 All Rights Reserved
*/ */
#include "firm.h" #include "firm.h"
#include "config.h"
#include "utils.h"
#include "fs.h"
#include "patches.h" #include "patches.h"
#include "memory.h" #include "memory.h"
#include "fs.h"
#include "emunand.h" #include "emunand.h"
#include "crypto.h" #include "crypto.h"
#include "draw.h" #include "draw.h"
#include "screeninit.h" #include "screeninit.h"
#include "loader.h" #include "loader.h"
#include "utils.h"
#include "buttons.h" #include "buttons.h"
#include "../build/patches.h" #include "../build/patches.h"
//FIRM patches version
#define PATCH_VER 2
static firmHeader *const firm = (firmHeader *)0x24000000; static firmHeader *const firm = (firmHeader *)0x24000000;
static const firmSectionHeader *section; static const firmSectionHeader *section;
static u8 *arm9Section;
static const char *patchedFirms[] = { "/aurei/patched_firmware_sys.bin",
"/aurei/patched_firmware_emu.bin",
"/aurei/patched_firmware_em2.bin",
"/aurei/patched_firmware90.bin" };
static u32 firmSize,
console,
mode,
emuNAND,
a9lhSetup,
selectedFirm,
usePatchedFirm;
void setupCFW(void){ u32 config,
console,
firmSource,
emuOffset;
void main(void)
{
u32 bootType,
firmType,
nandType,
a9lhInstalled,
updatedSys,
needConfig,
newConfig,
emuHeader;
//Determine if booting with A9LH
u32 a9lhBoot = (PDN_SPI_CNT == 0x0) ? 1 : 0;
//Retrieve the last booted FIRM
u8 previousFirm = CFG_BOOTENV;
//Detect the console being used //Detect the console being used
console = (PDN_MPCORE_CFG == 1) ? 0 : 1; console = (PDN_MPCORE_CFG == 1) ? 0 : 1;
//Get pressed buttons
u16 pressed = HID_PAD; //Mount filesystems. CTRNAND will be mounted only if/when needed
mountFs();
//Attempt to read the configuration file //Attempt to read the configuration file
const char configPath[] = "aurei/config.bin"; const char configPath[] = "/luma/config.bin";
u32 config = 0; if(fileRead(&config, configPath, 4)) needConfig = 1;
u32 needConfig = fileRead(&config, configPath, 3) ? 1 : 2; else
{
//Determine if A9LH is installed and the user has an updated sysNAND config = 0;
u32 updatedSys; needConfig = 2;
if(a9lhBoot || (config >> 2) & 0x1){
if(pressed == SAFE_MODE)
error("Using Safe Mode would brick you, or remove A9LH!");
a9lhSetup = 1;
//Check setting for > 9.2 sysNAND
updatedSys = config & 0x1;
} else{
a9lhSetup = 0;
updatedSys = 0;
} }
/* If booting with A9LH, it's a MCU reboot and a previous configuration exists, //Determine if this is a firmlaunch boot
try to force boot options */ if(*(vu8 *)0x23F00005)
if(a9lhBoot && previousFirm && needConfig == 1){ {
//Always force a sysNAND boot when quitting AGB_FIRM if(needConfig == 2) mcuReboot();
if(previousFirm == 0x7){
if(!updatedSys) mode = (config >> 12) & 0x1; bootType = 1;
emuNAND = 0;
needConfig = 0; //'0' = NATIVE_FIRM, '1' = TWL_FIRM, '2' = AGB_FIRM
//Else, force the last used boot options unless A, L or R are pressed firmType = *(vu8 *)0x23F00005 - '0';
} else if(!(pressed & OPTION_BUTTONS)){
mode = (config >> 12) & 0x1; nandType = BOOTCONFIG(0, 3);
emuNAND = (config >> 13) & 0x3; firmSource = BOOTCONFIG(2, 1);
needConfig = 0; a9lhInstalled = BOOTCONFIG(3, 1);
updatedSys = (a9lhInstalled && CONFIG(1)) ? 1 : 0;
}
else
{
bootType = 0;
firmType = 0;
//Determine if booting with A9LH
u32 a9lhBoot = !PDN_SPI_CNT ? 1 : 0;
//Retrieve the last booted FIRM
u32 previousFirm = CFG_BOOTENV;
//Get pressed buttons
u32 pressed = HID_PAD;
//Determine if A9LH is installed and the user has an updated sysNAND
if(a9lhBoot || CONFIG(2))
{
if(pressed == SAFE_MODE)
error("Using Safe Mode would brick you, or remove A9LH!");
a9lhInstalled = 1;
//Check setting for > 9.2 sysNAND
updatedSys = CONFIG(1);
}
else
{
a9lhInstalled = 0;
updatedSys = 0;
}
newConfig = a9lhInstalled << 3;
/* If booting with A9LH, it's a MCU reboot and a previous configuration exists,
try to force boot options */
if(a9lhBoot && previousFirm && needConfig == 1)
{
//Always force a sysNAND boot when quitting AGB_FIRM
if(previousFirm == 7)
{
nandType = 0;
firmSource = updatedSys ? 0 : BOOTCONFIG(2, 1);
needConfig = 0;
//Flag to prevent multiple boot options-forcing
newConfig |= 1 << 4;
}
/* Else, force the last used boot options unless a payload button or A/L/R are pressed
or the no-forcing flag is set */
else if(!(pressed & OVERRIDE_BUTTONS) && !BOOTCONFIG(4, 1))
{
nandType = BOOTCONFIG(0, 3);
firmSource = BOOTCONFIG(2, 1);
needConfig = 0;
}
}
//Boot options aren't being forced
if(needConfig)
{
/* If L and R/Select or one of the single payload buttons are pressed and, if not using A9LH,
the Safe Mode combo is not pressed, chainload an external payload */
if(((pressed & SINGLE_PAYLOAD_BUTTONS) || ((pressed & BUTTON_L1) && (pressed & L_PAYLOAD_BUTTONS)))
&& pressed != SAFE_MODE)
loadPayload();
//If no configuration file exists or SELECT is held, load configuration menu
if(needConfig == 2 || (pressed & BUTTON_SELECT))
configureCFW(configPath);
//If screens are inited or the corresponding option is set, load splash screen
if(PDN_GPU_CNT != 1 || CONFIG(7)) loadSplash();
u32 autoBootSys = CONFIG(0);
//Determine if we need to boot an emuNAND or sysNAND
nandType = (pressed & BUTTON_L1) ? autoBootSys : ((pressed & BUTTON_R1) ? updatedSys : !autoBootSys);
/* If we're booting emuNAND the second emuNAND is set as default and B isn't pressed,
or vice-versa, boot the second emuNAND */
if(nandType && ((!(pressed & BUTTON_B)) == CONFIG(3))) nandType++;
//Determine the NAND we should take the FIRM from
firmSource = (pressed & BUTTON_R1) ? !nandType : (nandType != 0);
} }
} }
if(needConfig){ //If we need to boot emuNAND, make sure it exists
if(nandType)
{
getEmunandSect(&emuOffset, &emuHeader, &nandType);
if(!nandType) firmSource = 0;
}
/* If L and one of the payload buttons are pressed, and if not using A9LH //Same if we're using emuNAND as the FIRM source
the Safe Mode combo is not pressed, chainload an external payload */ else if(firmSource)
if((pressed & BUTTON_L1) && (pressed & PAYLOAD_BUTTONS) && getEmunandSect(&emuOffset, &emuHeader, &firmSource);
pressed != SAFE_MODE) loadPayload();
//If no configuration file exists or SELECT is held, load configuration menu if(!bootType)
if(needConfig == 2 || (pressed & BUTTON_SELECT)) {
configureCFW(configPath, patchedFirms[3]); newConfig |= nandType | (firmSource << 2);
//If screens are inited, load splash screen /* If the boot configuration is different from previously, overwrite it.
if(PDN_GPU_CNT != 0x1) loadSplash(); Just the no-forcing flag being set is not enough */
if((newConfig & 0x2F) != (config & 0x3F))
{
//Preserve user settings (last 26 bits)
newConfig |= config & 0xFFFFFFC0;
/* If L is pressed, boot 9.0 FIRM */ fileWrite(&newConfig, configPath, 4);
mode = ((config >> 3) & 0x1) ? ((!(pressed & BUTTON_L1R1)) ? 0 : 1) :
((pressed & BUTTON_L1) ? 0 : 1);
/* If L or R aren't pressed on a 9.0/9.2 sysNAND, or the 9.0 FIRM is selected
or R is pressed on a > 9.2 sysNAND, boot emuNAND */
if((updatedSys && (!mode || (pressed & BUTTON_R1))) ||
(!updatedSys && mode && !(pressed & BUTTON_R1))){
//If not 9.0 FIRM and B is pressed, attempt booting the second emuNAND
emuNAND = (mode && ((!(pressed & BUTTON_B)) == ((config >> 4) & 0x1))) ? 2 : 1;
} else emuNAND = 0;
u32 tempConfig = (PATCH_VER << 17) | (a9lhSetup << 16) | (emuNAND << 13) | (mode << 12);
/* If tha FIRM patches version is different or user switched to/from A9LH,
delete all patched FIRMs */
if((tempConfig & 0xFF0000) != (config & 0xFF0000))
deleteFirms(patchedFirms, sizeof(patchedFirms) / sizeof(char *));
//If the boot configuration is different from previously, overwrite it
if((tempConfig & 0xFFF000) != (config & 0xFFF000)){
//Preserve user settings (first 12 bits)
tempConfig |= config & 0xFFF;
fileWrite(&tempConfig, configPath, 3);
} }
} }
/* Determine which patched FIRM we need to write or attempt to use (if any). loadFirm(firmType, !firmType && updatedSys == !firmSource);
Patched 9.0 FIRM is only needed if "Use pre-patched FIRMs" is set */
selectedFirm = mode ? (emuNAND ? (emuNAND == 1 ? 2 : 3) : 1) :
(((config >> 1) & 0x1) ? 4 : 0);
//If "Use pre-patched FIRMs" is set and the appropriate FIRM exists, use it if(!firmType) patchNativeFirm(nandType, emuHeader, a9lhInstalled);
usePatchedFirm = (((config >> 1) & 0x1) && fileExists(patchedFirms[selectedFirm - 1])) ? 1 : 0; else patchTwlAgbFirm(firmType);
launchFirm(bootType);
} }
//Load FIRM into FCRAM static inline void loadFirm(u32 firmType, u32 externalFirm)
void loadFirm(void){ {
//If not using an A9LH setup or the patched FIRM, load 9.0 FIRM from NAND
if(!usePatchedFirm && !a9lhSetup && !mode){
//Read FIRM from NAND and write to FCRAM
firmSize = console ? 0xF2000 : 0xE9000;
nandFirm0((u8 *)firm, firmSize, console);
//Check for correct decryption
if(memcmp(firm, "FIRM", 4) != 0)
error("Couldn't decrypt NAND FIRM0 (O3DS not on 9.x?)");
}
//Load FIRM from SD
else{
const char *path = usePatchedFirm ? patchedFirms[selectedFirm - 1] :
(mode ? "/aurei/firmware.bin" : "/aurei/firmware90.bin");
firmSize = fileSize(path);
if(!firmSize) error("aurei/firmware(90).bin doesn't exist");
fileRead(firm, path, firmSize);
}
section = firm->section; section = firm->section;
//Check that the loaded FIRM matches the console /* If the conditions to load the external FIRM aren't met, or reading fails, or the FIRM
if((((u32)section[2].address >> 8) & 0xFF) != (console ? 0x60 : 0x68)) doesn't match the console, load it from CTRNAND */
error("aurei/firmware(90).bin doesn't match this\nconsole, or it's encrypted"); if(!externalFirm || !fileRead(firm, "/luma/firmware.bin", 0) ||
(((u32)section[2].address >> 8) & 0xFF) != (console ? 0x60 : 0x68))
{
const char *firmFolders[3][2] = {{ "00000002", "20000002" },
{ "00000102", "20000102" },
{ "00000202", "20000202" }};
arm9Section = (u8 *)firm + section[2].offset; firmRead(firm, firmFolders[firmType][console]);
decryptExeFs((u8 *)firm);
if(console && !usePatchedFirm) decryptArm9Bin(arm9Section, mode); }
} }
//NAND redirection static inline void patchNativeFirm(u32 nandType, u32 emuHeader, u32 a9lhInstalled)
static void loadEmu(u8 *proc9Offset){ {
u8 *arm9Section = (u8 *)firm + section[2].offset;
u32 emuOffset, u32 nativeFirmType;
emuHeader = 0,
emuRead,
emuWrite;
//Look for emuNAND if(console)
getEmunandSect(&emuOffset, &emuHeader, emuNAND); {
//Determine if we're booting the 9.0 FIRM
nativeFirmType = (arm9Section[0x51] == 0xFF) ? 0 : 1;
//No emuNAND detected //Decrypt ARM9Bin and patch ARM9 entrypoint to skip arm9loader
if(!emuHeader) error("No emuNAND has been detected"); arm9Loader(arm9Section, nativeFirmType);
firm->arm9Entry = (u8 *)0x801B01C;
}
else
{
//Determine if we're booting the 9.0 FIRM
u8 firm90Hash[0x10] = {0x27, 0x2D, 0xFE, 0xEB, 0xAF, 0x3F, 0x6B, 0x3B, 0xF5, 0xDE, 0x4C, 0x41, 0xDE, 0x95, 0x27, 0x6A};
nativeFirmType = (memcmp(section[2].hash, firm90Hash, 0x10) == 0) ? 0 : 1;
}
if(nativeFirmType || nandType)
{
//Find the Process9 NCCH location
u8 *proc9Offset = getProc9(arm9Section, section[2].size);
//Apply emuNAND patches
if(nandType) patchEmuNAND(arm9Section, proc9Offset, emuHeader);
//Apply FIRM reboot patches, not on 9.0 FIRM as it breaks firmlaunchhax
if(nativeFirmType) patchReboots(arm9Section, proc9Offset);
}
//Apply FIRM0/1 writes patches on sysNAND to protect A9LH
if(a9lhInstalled && !nandType)
{
u16 *writeOffset = getFirmWrite(arm9Section, section[2].size);
*writeOffset = writeBlock[0];
*(writeOffset + 1) = writeBlock[1];
}
//Apply signature checks patches
u32 sigOffset,
sigOffset2;
getSigChecks(arm9Section, section[2].size, &sigOffset, &sigOffset2);
*(u16 *)sigOffset = sigPatch[0];
*(u16 *)sigOffset2 = sigPatch[0];
*((u16 *)sigOffset2 + 1) = sigPatch[1];
//Replace the FIRM loader with the injector
injectLoader();
}
static inline void patchEmuNAND(u8 *arm9Section, u8 *proc9Offset, u32 emuHeader)
{
//Copy emuNAND code //Copy emuNAND code
void *emuCodeOffset = getEmuCode(proc9Offset); void *emuCodeOffset = getEmuCode(proc9Offset);
memcpy(emuCodeOffset, emunand, emunand_size); memcpy(emuCodeOffset, emunand, emunand_size);
@@ -196,7 +279,10 @@ static void loadEmu(u8 *proc9Offset){
u32 branchOffset = (u32)emuCodeOffset - (u32)firm - u32 branchOffset = (u32)emuCodeOffset - (u32)firm -
section[2].offset + (u32)section[2].address; section[2].offset + (u32)section[2].address;
//Add emunand hooks //Add emuNAND hooks
u32 emuRead,
emuWrite;
getEmuRW(arm9Section, section[2].size, &emuRead, &emuWrite); getEmuRW(arm9Section, section[2].size, &emuRead, &emuWrite);
*(u16 *)emuRead = nandRedir[0]; *(u16 *)emuRead = nandRedir[0];
*((u16 *)emuRead + 1) = nandRedir[1]; *((u16 *)emuRead + 1) = nandRedir[1];
@@ -212,94 +298,105 @@ static void loadEmu(u8 *proc9Offset){
*(mpuOffset + 9) = mpuPatch[2]; *(mpuOffset + 9) = mpuPatch[2];
} }
//Patches static inline void patchReboots(u8 *arm9Section, u8 *proc9Offset)
void patchFirm(void){ {
//Calculate offset for the firmlaunch code
void *rebootOffset = getReboot(arm9Section, section[2].size);
//Skip patching //Calculate offset for the fOpen function
if(usePatchedFirm) return; u32 fOpenOffset = getfOpen(proc9Offset, rebootOffset);
if(mode || emuNAND){ //Copy firmlaunch code
//Find the Process9 NCCH location memcpy(rebootOffset, reboot, reboot_size);
u8 *proc9Offset = getProc9(arm9Section, section[2].size);
//Apply emuNAND patches //Put the fOpen offset in the right location
if(emuNAND) loadEmu(proc9Offset); u32 *pos_fopen = (u32 *)memsearch(rebootOffset, "OPEN", reboot_size, 4);
*pos_fopen = fOpenOffset;
}
//Patch FIRM reboots, not on 9.0 FIRM as it breaks firmlaunchhax static inline void injectLoader(void)
if(mode){ {
//Calculate offset for the firmlaunch code u32 loaderSize;
void *rebootOffset = getReboot(arm9Section, section[2].size);
//Calculate offset for the fOpen function
u32 fOpenOffset = getfOpen(proc9Offset, rebootOffset);
//Copy firmlaunch code void *loaderOffset = getLoader((u8 *)firm + section[0].offset, section[0].size, &loaderSize);
memcpy(rebootOffset, reboot, reboot_size);
//Put the fOpen offset in the right location //Check that the injector CXI isn't larger than the original
u32 *pos_fopen = (u32 *)memsearch(rebootOffset, "OPEN", reboot_size, 4); if((u32)injector_size <= loaderSize)
*pos_fopen = fOpenOffset; {
memcpy(loaderOffset, injector, injector_size);
//Patch path for emuNAND-patched FIRM //Patch content size and ExeFS size to match the repaced loader's ones
if(emuNAND){
void *pos_path = memsearch(rebootOffset, L"sy", reboot_size, 4);
memcpy(pos_path, emuNAND == 1 ? L"emu" : L"em2", 5);
}
}
}
if(a9lhSetup && !emuNAND){
//Patch FIRM partitions writes on sysNAND to protect A9LH
u16 *writeOffset = getFirmWrite(arm9Section, section[2].size);
*writeOffset = writeBlock[0];
*(writeOffset + 1) = writeBlock[1];
}
//Disable signature checks
u32 sigOffset,
sigOffset2;
getSigChecks(arm9Section, section[2].size, &sigOffset, &sigOffset2);
*(u16 *)sigOffset = sigPatch[0];
*(u16 *)sigOffset2 = sigPatch[0];
*((u16 *)sigOffset2 + 1) = sigPatch[1];
//Replace the FIRM loader with the injector
u32 loaderOffset,
loaderSize;
getLoader((u8 *)firm + section[0].offset, section[0].size, &loaderOffset, &loaderSize);
if(injector_size <= (int)loaderSize){
memset((void *)loaderOffset, 0, loaderSize);
memcpy((void *)loaderOffset, injector, injector_size);
*((u32 *)loaderOffset + 0x41) = loaderSize / 0x200; *((u32 *)loaderOffset + 0x41) = loaderSize / 0x200;
*((u32 *)loaderOffset + 0x69) = loaderSize / 0x200 - 5; *((u32 *)loaderOffset + 0x69) = loaderSize / 0x200 - 5;
} }
//Patch ARM9 entrypoint on N3DS to skip arm9loader
if(console)
firm->arm9Entry = (u8 *)0x801B01C;
//Write patched FIRM to SD if needed
if(selectedFirm)
if(!fileWrite(firm, patchedFirms[selectedFirm - 1], firmSize))
error("Couldn't write the patched FIRM (no free space?)");
} }
void launchFirm(void){ static inline void patchTwlAgbFirm(u32 firmType)
{
//On N3DS, decrypt ARM9Bin and patch ARM9 entrypoint to skip arm9loader
if(console)
{
arm9Loader((u8 *)firm + section[3].offset, 0);
firm->arm9Entry = (u8 *)0x801301C;
}
if(console && mode) setKeyXs(arm9Section); const patchData twlPatches[] = {
{{0x1650C0, 0x165D64}, {{ 6, 0x00, 0x20, 0x4E, 0xB0, 0x70, 0xBD }}, 0},
{{0x173A0E, 0x17474A}, { .type1 = 0x2001 }, 1},
{{0x174802, 0x17553E}, { .type1 = 0x2000 }, 2},
{{0x174964, 0x1756A0}, { .type1 = 0x2000 }, 2},
{{0x174D52, 0x175A8E}, { .type1 = 0x2001 }, 2},
{{0x174D5E, 0x175A9A}, { .type1 = 0x2001 }, 2},
{{0x174D6A, 0x175AA6}, { .type1 = 0x2001 }, 2},
{{0x174E56, 0x175B92}, { .type1 = 0x2001 }, 1},
{{0x174E58, 0x175B94}, { .type1 = 0x4770 }, 1}
},
agbPatches[] = {
{{0x9D2A8, 0x9DF64}, {{ 6, 0x00, 0x20, 0x4E, 0xB0, 0x70, 0xBD }}, 0},
{{0xD7A12, 0xD8B8A}, { .type1 = 0xEF26 }, 1}
};
//Copy firm partitions to respective memory locations /* Calculate the amount of patches to apply. Only count the boot screen patch for AGB_FIRM
memcpy(section[0].address, (u8 *)firm + section[0].offset, section[0].size); if the matching option was enabled (keep it as last) */
memcpy(section[1].address, (u8 *)firm + section[1].offset, section[1].size); u32 numPatches = firmType == 1 ? (sizeof(twlPatches) / sizeof(patchData)) :
memcpy(section[2].address, arm9Section, section[2].size); (sizeof(agbPatches) / sizeof(patchData) - !CONFIG(6));
const patchData *patches = firmType == 1 ? twlPatches : agbPatches;
//Fixes N3DS 3D //Patch
deinitScreens(); for(u32 i = 0; i < numPatches; i++)
{
switch(patches[i].type)
{
case 0:
memcpy((u8 *)firm + patches[i].offset[console], patches[i].patch.type0 + 1, patches[i].patch.type0[0]);
break;
case 2:
*(u16 *)((u8 *)firm + patches[i].offset[console] + 2) = 0;
case 1:
*(u16 *)((u8 *)firm + patches[i].offset[console]) = patches[i].patch.type1;
break;
}
}
}
static inline void launchFirm(u32 bootType)
{
//Copy FIRM sections to respective memory locations
for(u32 i = 0; i < 4 && section[i].size; i++)
memcpy(section[i].address, (u8 *)firm + section[i].offset, section[i].size);
//Determine the ARM11 entry to use
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

@@ -1,15 +1,13 @@
/* /*
* firm.h * firm.h
* by Reisyukaku / Aurora Wright
* Copyright (c) 2016 All Rights Reserved
*/ */
#pragma once #pragma once
#include "types.h" #include "types.h"
#define PDN_MPCORE_CFG (*(vu8 *)0x10140FFC) #define PDN_MPCORE_CFG (*(vu32 *)0x10140FFC)
#define PDN_SPI_CNT (*(vu8 *)0x101401C0) #define PDN_SPI_CNT (*(vu32 *)0x101401C0)
//FIRM Header layout //FIRM Header layout
typedef struct firmSectionHeader { typedef struct firmSectionHeader {
@@ -29,7 +27,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

@@ -1,35 +1,42 @@
/* /*
* fs.c * fs.c
* by Reisyukaku / Aurora Wright
* Copyright (c) 2016 All Rights Reserved
*/ */
#include "fs.h" #include "fs.h"
#include "memory.h"
#include "fatfs/ff.h" #include "fatfs/ff.h"
static FATFS fs; static FATFS sdFs,
nandFs;
u32 mountFs(void)
{
if(f_mount(&sdFs, "0:", 1) != FR_OK) return 0;
f_mount(&nandFs, "1:", 0);
u32 mountSD(void){
if(f_mount(&fs, "0:", 1) != FR_OK) return 0;
return 1; return 1;
} }
u32 fileRead(void *dest, const char *path, u32 size){ u32 fileRead(void *dest, const char *path, u32 size)
{
FRESULT fr; FRESULT fr;
FIL fp; FIL fp;
unsigned int br = 0; unsigned int br = 0;
fr = f_open(&fp, path, FA_READ); fr = f_open(&fp, path, FA_READ);
if(fr == FR_OK){ if(fr == FR_OK)
{
if(!size) size = f_size(&fp); if(!size) size = f_size(&fp);
fr = f_read(&fp, dest, size, &br); fr = f_read(&fp, dest, size, &br);
} }
f_close(&fp); f_close(&fp);
return fr ? 0 : 1; return fr ? 0 : 1;
} }
u32 fileWrite(const void *buffer, const char *path, u32 size){ u32 fileWrite(const void *buffer, const char *path, u32 size)
{
FRESULT fr; FRESULT fr;
FIL fp; FIL fp;
unsigned int br = 0; unsigned int br = 0;
@@ -38,30 +45,67 @@ u32 fileWrite(const void *buffer, const char *path, u32 size){
if(fr == FR_OK) fr = f_write(&fp, buffer, size, &br); if(fr == FR_OK) fr = f_write(&fp, buffer, size, &br);
f_close(&fp); f_close(&fp);
return fr ? 0 : 1; return fr ? 0 : 1;
} }
u32 fileSize(const char *path){ u32 defPayloadExists(void)
FIL fp; {
u32 size = 0; DIR dir;
FILINFO info;
if(f_open(&fp, path, FA_READ) == FR_OK) FRESULT result = f_findfirst(&dir, &info, "/luma/payloads", "def_*.bin");
size = f_size(&fp);
f_close(&fp); f_closedir(&dir);
return size;
return (result == FR_OK && info.fname[0]);
} }
u32 fileExists(const char *path){ void firmRead(void *dest, const char *firmFolder)
FIL fp; {
u32 exists = 0; char path[48] = "1:/title/00040138/00000000/content";
memcpy(&path[18], firmFolder, 8);
if(f_open(&fp, path, FA_READ) == FR_OK) exists = 1; DIR dir;
FILINFO info;
f_close(&fp); f_opendir(&dir, path);
return exists;
}
void fileDelete(const char *path){ u32 id = 0xFFFFFFFF;
f_unlink(path);
//Parse the target directory
while(f_readdir(&dir, &info) == FR_OK && info.fname[0])
{
//Not a cxi
if(info.altname[9] != 'A') continue;
//Convert the .app name to an integer
u32 tempId = 0;
for(char *tmp = info.altname; *tmp != '.'; tmp++)
{
tempId <<= 4;
tempId += *tmp > '9' ? *tmp - 'A' + 10 : *tmp - '0';
}
//Found an older cxi
if(tempId < id) id = tempId;
}
f_closedir(&dir);
//Complete the string with the .app name
memcpy(&path[34], "/00000000.app", 14);
//Last digit of the .app
u32 i = 42;
//Convert back the .app name from integer to array
while(id)
{
static const char hexDigits[] = "0123456789ABCDEF";
path[i--] = hexDigits[id & 0xF];
id >>= 4;
}
fileRead(dest, path, 0);
} }

View File

@@ -1,16 +1,13 @@
/* /*
* fs.h * fs.h
* by Reisyukaku / Aurora Wright
* Copyright (c) 2016 All Rights Reserved
*/ */
#pragma once #pragma once
#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 defPayloadExists(void);
u32 fileExists(const char *path); void firmRead(void *dest, const char *firmFolder);
void fileDelete(const char *path);

View File

@@ -10,50 +10,58 @@ static const struct { u8 bus_id, reg_addr; } dev_data[] = {
{2, 0xA4}, {2, 0x9A}, {2, 0xA0}, {2, 0xA4}, {2, 0x9A}, {2, 0xA0},
}; };
static inline u8 i2cGetDeviceBusId(u8 device_id) { static inline u8 i2cGetDeviceBusId(u8 device_id)
{
return dev_data[device_id].bus_id; return dev_data[device_id].bus_id;
} }
static inline u8 i2cGetDeviceRegAddr(u8 device_id) { static inline u8 i2cGetDeviceRegAddr(u8 device_id)
{
return dev_data[device_id].reg_addr; return dev_data[device_id].reg_addr;
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
static vu8* reg_data_addrs[] = { static vu8 *reg_data_addrs[] = {
(vu8*)(I2C1_REG_OFF + I2C_REG_DATA), (vu8 *)(I2C1_REG_OFF + I2C_REG_DATA),
(vu8*)(I2C2_REG_OFF + I2C_REG_DATA), (vu8 *)(I2C2_REG_OFF + I2C_REG_DATA),
(vu8*)(I2C3_REG_OFF + I2C_REG_DATA), (vu8 *)(I2C3_REG_OFF + I2C_REG_DATA),
}; };
static inline vu8* i2cGetDataReg(u8 bus_id) { static inline vu8 *i2cGetDataReg(u8 bus_id)
{
return reg_data_addrs[bus_id]; return reg_data_addrs[bus_id];
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
static vu8* reg_cnt_addrs[] = { static vu8 *reg_cnt_addrs[] = {
(vu8*)(I2C1_REG_OFF + I2C_REG_CNT), (vu8 *)(I2C1_REG_OFF + I2C_REG_CNT),
(vu8*)(I2C2_REG_OFF + I2C_REG_CNT), (vu8 *)(I2C2_REG_OFF + I2C_REG_CNT),
(vu8*)(I2C3_REG_OFF + I2C_REG_CNT), (vu8 *)(I2C3_REG_OFF + I2C_REG_CNT),
}; };
static inline vu8* i2cGetCntReg(u8 bus_id) { static inline vu8 *i2cGetCntReg(u8 bus_id)
{
return reg_cnt_addrs[bus_id]; return reg_cnt_addrs[bus_id];
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
static inline void i2cWaitBusy(u8 bus_id) { static inline void i2cWaitBusy(u8 bus_id)
{
while (*i2cGetCntReg(bus_id) & 0x80); while (*i2cGetCntReg(bus_id) & 0x80);
} }
static inline u32 i2cGetResult(u8 bus_id) { static inline u32 i2cGetResult(u8 bus_id)
{
i2cWaitBusy(bus_id); i2cWaitBusy(bus_id);
return (*i2cGetCntReg(bus_id) >> 4) & 1; return (*i2cGetCntReg(bus_id) >> 4) & 1;
} }
static void i2cStop(u8 bus_id, u8 arg0) { static void i2cStop(u8 bus_id, u8 arg0)
{
*i2cGetCntReg(bus_id) = (arg0 << 5) | 0xC0; *i2cGetCntReg(bus_id) = (arg0 << 5) | 0xC0;
i2cWaitBusy(bus_id); i2cWaitBusy(bus_id);
*i2cGetCntReg(bus_id) = 0xC5; *i2cGetCntReg(bus_id) = 0xC5;
@@ -61,33 +69,41 @@ static void i2cStop(u8 bus_id, u8 arg0) {
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
static u32 i2cSelectDevice(u8 bus_id, u8 dev_reg) { static u32 i2cSelectDevice(u8 bus_id, u8 dev_reg)
{
i2cWaitBusy(bus_id); i2cWaitBusy(bus_id);
*i2cGetDataReg(bus_id) = dev_reg; *i2cGetDataReg(bus_id) = dev_reg;
*i2cGetCntReg(bus_id) = 0xC2; *i2cGetCntReg(bus_id) = 0xC2;
return i2cGetResult(bus_id); return i2cGetResult(bus_id);
} }
static u32 i2cSelectRegister(u8 bus_id, u8 reg) { static u32 i2cSelectRegister(u8 bus_id, u8 reg)
{
i2cWaitBusy(bus_id); i2cWaitBusy(bus_id);
*i2cGetDataReg(bus_id) = reg; *i2cGetDataReg(bus_id) = reg;
*i2cGetCntReg(bus_id) = 0xC0; *i2cGetCntReg(bus_id) = 0xC0;
return i2cGetResult(bus_id); return i2cGetResult(bus_id);
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
u32 i2cWriteRegister(u8 dev_id, u8 reg, u8 data) { u32 i2cWriteRegister(u8 dev_id, u8 reg, u8 data)
{
u8 bus_id = i2cGetDeviceBusId(dev_id); u8 bus_id = i2cGetDeviceBusId(dev_id);
u8 dev_addr = i2cGetDeviceRegAddr(dev_id); u8 dev_addr = i2cGetDeviceRegAddr(dev_id);
for (int i = 0; i < 8; i++) { for(u32 i = 0; i < 8; i++)
if (i2cSelectDevice(bus_id, dev_addr) && i2cSelectRegister(bus_id, reg)) { {
if(i2cSelectDevice(bus_id, dev_addr) && i2cSelectRegister(bus_id, reg))
{
i2cWaitBusy(bus_id); i2cWaitBusy(bus_id);
*i2cGetDataReg(bus_id) = data; *i2cGetDataReg(bus_id) = data;
*i2cGetCntReg(bus_id) = 0xC1; *i2cGetCntReg(bus_id) = 0xC1;
i2cStop(bus_id, 0); i2cStop(bus_id, 0);
if (i2cGetResult(bus_id))
if(i2cGetResult(bus_id))
return 1; return 1;
} }
*i2cGetCntReg(bus_id) = 0xC5; *i2cGetCntReg(bus_id) = 0xC5;
@@ -95,4 +111,4 @@ u32 i2cWriteRegister(u8 dev_id, u8 reg, u8 data) {
} }
return 0; return 0;
} }

View File

@@ -1,7 +1,5 @@
/* /*
* loader.c * loader.c
* by Aurora Wright
* Copyright (c) 2016 All Rights Reserved
*/ */
#include "loader.h" #include "loader.h"
@@ -12,8 +10,10 @@
#define PAYLOAD_ADDRESS 0x24F00000 #define PAYLOAD_ADDRESS 0x24F00000
void loadPayload(void){ void loadPayload(void)
if(fileExists("aurei/payloads/default.bin")){ {
if(defPayloadExists())
{
initScreens(); initScreens();
memcpy((void *)PAYLOAD_ADDRESS, loader, loader_size); memcpy((void *)PAYLOAD_ADDRESS, loader, loader_size);
((void (*)())PAYLOAD_ADDRESS)(); ((void (*)())PAYLOAD_ADDRESS)();

View File

@@ -1,7 +1,5 @@
/* /*
* loader.h * loader.h
* by Aurora Wright
* Copyright (c) 2016 All Rights Reserved
*/ */
#pragma once #pragma once

View File

@@ -1,18 +0,0 @@
/*
* main.c
* by Reisyukaku / Aurora Wright
* Copyright (c) 2016 All Rights Reserved
*
* Minimalist CFW for (N)3DS
*/
#include "fs.h"
#include "firm.h"
void main(void){
mountSD();
setupCFW();
loadFirm();
patchFirm();
launchFirm();
}

View File

@@ -1,47 +1,48 @@
/* /*
* memory.c * memory.c
* by Reisyukaku / Aurora Wright
* Copyright (c) 2016 All Rights Reserved
* *
* 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
*/ */
#include "memory.h" #include "memory.h"
void memcpy(void *dest, const void *src, u32 size){ void memcpy(void *dest, const void *src, u32 size)
{
u8 *destc = (u8 *)dest; u8 *destc = (u8 *)dest;
const u8 *srcc = (const u8 *)src; const u8 *srcc = (const u8 *)src;
for(u32 i = 0; i < size; i++) for(u32 i = 0; i < size; i++)
destc[i] = srcc[i]; destc[i] = srcc[i];
} }
void memset(void *dest, int filler, u32 size){ void memset32(void *dest, u32 filler, u32 size)
u8 *destc = (u8 *)dest; {
for(u32 i = 0; i < size; i++)
destc[i] = (u8)filler;
}
void memset32(void *dest, u32 filler, u32 size){
u32 *dest32 = (u32 *)dest; u32 *dest32 = (u32 *)dest;
for (u32 i = 0; i < size / 4; i++) for (u32 i = 0; i < size / 4; i++)
dest32[i] = filler; dest32[i] = filler;
} }
int memcmp(const void *buf1, const void *buf2, u32 size){ int memcmp(const void *buf1, const void *buf2, u32 size)
{
const u8 *buf1c = (const u8 *)buf1; const u8 *buf1c = (const u8 *)buf1;
const u8 *buf2c = (const u8 *)buf2; const u8 *buf2c = (const u8 *)buf2;
for(u32 i = 0; i < size; i++){
for(u32 i = 0; i < size; i++)
{
int cmp = buf1c[i] - buf2c[i]; int cmp = buf1c[i] - buf2c[i];
if(cmp) return cmp; if(cmp) return cmp;
} }
return 0; return 0;
} }
u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSize){ u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSize)
{
const u8 *patternc = (const u8 *)pattern; const u8 *patternc = (const u8 *)pattern;
//Preprocessing //Preprocessing
int table[256]; u32 table[256];
for(u32 i = 0; i < 256; ++i) for(u32 i = 0; i < 256; ++i)
table[i] = patternSize + 1; table[i] = patternSize + 1;
@@ -51,7 +52,8 @@ u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSize){
//Searching //Searching
u32 j = 0; u32 j = 0;
while(j <= size - patternSize){ while(j <= size - patternSize)
{
if(memcmp(patternc, startPos + j, patternSize) == 0) if(memcmp(patternc, startPos + j, patternSize) == 0)
return startPos + j; return startPos + j;
j += table[startPos[j + patternSize]]; j += table[startPos[j + patternSize]];

View File

@@ -1,7 +1,5 @@
/* /*
* memory.h * memory.h
* by Reisyukaku / Aurora Wright
* Copyright (c) 2016 All Rights Reserved
* *
* 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
*/ */
@@ -11,7 +9,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

@@ -1,7 +1,5 @@
/* /*
* patches.c * patches.c
* by Reisyukaku / Aurora Wright
* Copyright (c) 2016 All Rights Reserved
*/ */
#include "patches.h" #include "patches.h"
@@ -13,21 +11,21 @@
const u32 mpuPatch[3] = {0x00360003, 0x00200603, 0x001C0603}; const u32 mpuPatch[3] = {0x00360003, 0x00200603, 0x001C0603};
const u16 nandRedir[2] = {0x4C00, 0x47A0}; const u16 nandRedir[2] = {0x4C00, 0x47A0},
sigPatch[2] = {0x2000, 0x4770},
const u16 sigPatch[2] = {0x2000, 0x4770}; writeBlock[2] = {0x2000, 0x46C0};
const u16 writeBlock[2] = {0x2000, 0x46C0};
/************************************************** /**************************************************
* Functions * Functions
**************************************************/ **************************************************/
u8 *getProc9(u8 *pos, u32 size){ u8 *getProc9(u8 *pos, u32 size)
{
return memsearch(pos, "ess9", size, 4); return memsearch(pos, "ess9", size, 4);
} }
void getSigChecks(u8 *pos, u32 size, u32 *off, u32 *off2){ void getSigChecks(u8 *pos, u32 size, u32 *off, u32 *off2)
{
//Look for signature checks //Look for signature checks
const u8 pattern[] = {0xC0, 0x1C, 0x76, 0xE7}, const u8 pattern[] = {0xC0, 0x1C, 0x76, 0xE7},
pattern2[] = {0xB5, 0x22, 0x4D, 0x0C}; pattern2[] = {0xB5, 0x22, 0x4D, 0x0C};
@@ -36,16 +34,19 @@ void getSigChecks(u8 *pos, u32 size, u32 *off, u32 *off2){
*off2 = (u32)memsearch(pos, pattern2, size, 4) - 1; *off2 = (u32)memsearch(pos, pattern2, size, 4) - 1;
} }
void *getReboot(u8 *pos, u32 size){ void *getReboot(u8 *pos, u32 size)
{
//Look for FIRM reboot code //Look for FIRM reboot code
const u8 pattern[] = {0xDE, 0x1F, 0x8D, 0xE2}; const u8 pattern[] = {0xDE, 0x1F, 0x8D, 0xE2};
return memsearch(pos, pattern, size, 4) - 0x10; return memsearch(pos, pattern, size, 4) - 0x10;
} }
u32 getfOpen(u8 *proc9Offset, void *rebootOffset){ u32 getfOpen(u8 *proc9Offset, void *rebootOffset)
{
//Offset Process9 code gets loaded to in memory (defined in ExHeader) //Offset Process9 code gets loaded to in memory (defined in ExHeader)
u32 p9MemAddr = *(u32 *)(proc9Offset + 0xC); u32 p9MemAddr = *(u32 *)(proc9Offset + 0xC);
//Process9 code offset (start of NCCH + ExeFS offset + ExeFS header size) //Process9 code offset (start of NCCH + ExeFS offset + ExeFS header size)
u32 p9CodeOff = (u32)(proc9Offset - 0x204) + (*(u32 *)(proc9Offset - 0x64) * 0x200) + 0x200; u32 p9CodeOff = (u32)(proc9Offset - 0x204) + (*(u32 *)(proc9Offset - 0x64) * 0x200) + 0x200;
@@ -53,7 +54,8 @@ u32 getfOpen(u8 *proc9Offset, void *rebootOffset){
return (u32)rebootOffset + 9 - (-((*(u32 *)rebootOffset & 0x00FFFFFF) << 2) & 0xFFFFF) - p9CodeOff + p9MemAddr; return (u32)rebootOffset + 9 - (-((*(u32 *)rebootOffset & 0x00FFFFFF) << 2) & 0xFFFFF) - p9CodeOff + p9MemAddr;
} }
u16 *getFirmWrite(u8 *pos, u32 size){ u16 *getFirmWrite(u8 *pos, u32 size)
{
//Look for FIRM writing code //Look for FIRM writing code
u8 *const off = memsearch(pos, "exe:", size, 4); u8 *const off = memsearch(pos, "exe:", size, 4);
const u8 pattern[] = {0x00, 0x28, 0x01, 0xDA}; const u8 pattern[] = {0x00, 0x28, 0x01, 0xDA};
@@ -61,9 +63,11 @@ 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){ 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

@@ -1,7 +1,5 @@
/* /*
* patches.h * patches.h
* by Reisyukaku / Aurora Wright
* Copyright (c) 2016 All Rights Reserved
*/ */
#pragma once #pragma once
@@ -12,9 +10,9 @@
* Patches * Patches
**************************************************/ **************************************************/
const u32 mpuPatch[3]; const u32 mpuPatch[3];
const u16 nandRedir[2]; const u16 nandRedir[2],
const u16 sigPatch[2]; sigPatch[2],
const u16 writeBlock[2]; writeBlock[2];
/************************************************** /**************************************************
* Functions * Functions
@@ -24,4 +22,4 @@ 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); void *getLoader(u8 *pos, u32 size, u32 *loaderSize);

View File

@@ -1,151 +1,64 @@
/* /*
* screeninit.c * screeninit.c
* by Aurora Wright *
* Screen init code by dark_samus, bil1s, Normmatt, delebile and others. * Screen init code by dark_samus, bil1s, Normmatt, delebile and others.
* Screen deinit code by tiniVi. * Screen deinit code by tiniVi.
*
* Copyright (c) 2016 All Rights Reserved
*/ */
#include "screeninit.h" #include "screeninit.h"
#include "config.h"
#include "memory.h"
#include "draw.h" #include "draw.h"
#include "i2c.h" #include "i2c.h"
#include "../build/screeninit.h"
static vu32 *const arm11 = (u32 *)0x1FFFFFF8; #define SCREENINIT_ADDRESS 0x24F03000
void deinitScreens(void){ vu32 *arm11Entry = (u32 *)0x1FFFFFF8;
void __attribute__((naked)) ARM11(void){
void deinitScreens(void)
{
void __attribute__((naked)) ARM11(void)
{
//Disable interrupts //Disable interrupts
__asm(".word 0xF10C01C0"); __asm(".word 0xF10C01C0");
//Clear ARM11 entry offset //Clear ARM11 entry offset
*arm11 = 0; *arm11Entry = 0;
//Shutdown LCDs //Shutdown LCDs
*(vu32 *)0x10202A44 = 0; *(vu32 *)0x10202A44 = 0;
*(vu32 *)0x10202244 = 0; *(vu32 *)0x10202244 = 0;
*(vu32 *)0x10202014 = 0; *(vu32 *)0x10202014 = 0;
//Wait for the entry to be set //Wait for the entry to be set
while(!*arm11); while(!*arm11Entry);
//Jump to it //Jump to it
((void (*)())*arm11)(); ((void (*)())*arm11Entry)();
} }
if(PDN_GPU_CNT != 0x1){ if(PDN_GPU_CNT != 1)
*arm11 = (u32)ARM11; {
while(*arm11); *arm11Entry = (u32)ARM11;
while(*arm11Entry);
} }
} }
void initScreens(void){ void initScreens(void)
void __attribute__((naked)) ARM11(void){ {
//Disable interrupts if(PDN_GPU_CNT == 1)
__asm(".word 0xF10C01C0"); {
memcpy((void *)SCREENINIT_ADDRESS, screeninit, screeninit_size);
*(vu32 *)0x10141200 = 0x1007F; //Write brightness level for the stub to pick up
*(vu32 *)0x10202014 = 0x00000001; *(vu32 *)(SCREENINIT_ADDRESS + 8) = MULTICONFIG(0);
*(vu32 *)0x1020200C &= 0xFFFEFFFE;
*(vu32 *)0x10202240 = 0x45;
*(vu32 *)0x10202A40 = 0x45;
*(vu32 *)0x10202244 = 0x1023E;
*(vu32 *)0x10202A44 = 0x1023E;
// Top screen *arm11Entry = SCREENINIT_ADDRESS;
*(vu32 *)0x10400400 = 0x000001c2; while(*arm11Entry);
*(vu32 *)0x10400404 = 0x000000d1;
*(vu32 *)0x10400408 = 0x000001c1;
*(vu32 *)0x1040040c = 0x000001c1;
*(vu32 *)0x10400410 = 0x00000000;
*(vu32 *)0x10400414 = 0x000000cf;
*(vu32 *)0x10400418 = 0x000000d1;
*(vu32 *)0x1040041c = 0x01c501c1;
*(vu32 *)0x10400420 = 0x00010000;
*(vu32 *)0x10400424 = 0x0000019d;
*(vu32 *)0x10400428 = 0x00000002;
*(vu32 *)0x1040042c = 0x00000192;
*(vu32 *)0x10400430 = 0x00000192;
*(vu32 *)0x10400434 = 0x00000192;
*(vu32 *)0x10400438 = 0x00000001;
*(vu32 *)0x1040043c = 0x00000002;
*(vu32 *)0x10400440 = 0x01960192;
*(vu32 *)0x10400444 = 0x00000000;
*(vu32 *)0x10400448 = 0x00000000;
*(vu32 *)0x1040045C = 0x00f00190;
*(vu32 *)0x10400460 = 0x01c100d1;
*(vu32 *)0x10400464 = 0x01920002;
*(vu32 *)0x10400468 = 0x18300000;
*(vu32 *)0x10400470 = 0x80341;
*(vu32 *)0x10400474 = 0x00010501;
*(vu32 *)0x10400478 = 0;
*(vu32 *)0x10400490 = 0x000002D0;
*(vu32 *)0x1040049C = 0x00000000;
// Disco register //Turn on backlight
for(vu32 i = 0; i < 256; i++)
*(vu32 *)0x10400484 = 0x10101 * i;
// Bottom screen
*(vu32 *)0x10400500 = 0x000001c2;
*(vu32 *)0x10400504 = 0x000000d1;
*(vu32 *)0x10400508 = 0x000001c1;
*(vu32 *)0x1040050c = 0x000001c1;
*(vu32 *)0x10400510 = 0x000000cd;
*(vu32 *)0x10400514 = 0x000000cf;
*(vu32 *)0x10400518 = 0x000000d1;
*(vu32 *)0x1040051c = 0x01c501c1;
*(vu32 *)0x10400520 = 0x00010000;
*(vu32 *)0x10400524 = 0x0000019d;
*(vu32 *)0x10400528 = 0x00000052;
*(vu32 *)0x1040052c = 0x00000192;
*(vu32 *)0x10400530 = 0x00000192;
*(vu32 *)0x10400534 = 0x0000004f;
*(vu32 *)0x10400538 = 0x00000050;
*(vu32 *)0x1040053c = 0x00000052;
*(vu32 *)0x10400540 = 0x01980194;
*(vu32 *)0x10400544 = 0x00000000;
*(vu32 *)0x10400548 = 0x00000011;
*(vu32 *)0x1040055C = 0x00f00140;
*(vu32 *)0x10400560 = 0x01c100d1;
*(vu32 *)0x10400564 = 0x01920052;
*(vu32 *)0x10400568 = 0x18300000 + 0x46500;
*(vu32 *)0x10400570 = 0x80301;
*(vu32 *)0x10400574 = 0x00010501;
*(vu32 *)0x10400578 = 0;
*(vu32 *)0x10400590 = 0x000002D0;
*(vu32 *)0x1040059C = 0x00000000;
// Disco register
for(vu32 i = 0; i < 256; i++)
*(vu32 *)0x10400584 = 0x10101 * i;
// Enable backlight
i2cWriteRegister(I2C_DEV_MCU, 0x22, 0x2A); i2cWriteRegister(I2C_DEV_MCU, 0x22, 0x2A);
*(vu32 *)0x10400468 = 0x18300000;
*(vu32 *)0x1040046c = 0x18300000;
*(vu32 *)0x10400494 = 0x18300000;
*(vu32 *)0x10400498 = 0x18300000;
*(vu32 *)0x10400568 = 0x18346500;
*(vu32 *)0x1040056c = 0x18346500;
//Set CakeBrah framebuffers
*((vu32 *)0x23FFFE00) = 0x18300000;
*((vu32 *)0x23FFFE04) = 0x18300000;
*((vu32 *)0x23FFFE08) = 0x18346500;
//Clear ARM11 entry offset
*arm11 = 0;
//Wait for the entry to be set
while(!*arm11);
//Jump to it
((void (*)())*arm11)();
}
if(PDN_GPU_CNT == 0x1){
*arm11 = (u32)ARM11;
while(*arm11);
} }
clearScreens(); clearScreens();

View File

@@ -1,10 +1,8 @@
/* /*
* screeninit.h * screeninit.h
* by Aurora Wright *
* Screen init code by dark_samus, bil1s, Normmatt, delebile and others. * Screen init code by dark_samus, bil1s, Normmatt, delebile and others.
* Screen deinit code by tiniVi. * Screen deinit code by tiniVi.
*
* Copyright (c) 2016 All Rights Reserved
*/ */
#pragma once #pragma once

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
@@ -50,7 +55,4 @@ _start:
mov r1, #0x340 mov r1, #0x340
str r1, [r0] str r1, [r0]
bl main b main
.die:
b .die

View File

@@ -1,7 +1,5 @@
/* /*
* types.h * types.h
* by Reisyukaku
* Copyright (c) 2015 All Rights Reserved
*/ */
#pragma once #pragma once

View File

@@ -1,134 +1,54 @@
/* /*
* utils.c * utils.c
* by Aurora Wright
* Copyright (c) 2016 All Rights Reserved
*/ */
#include "utils.h" #include "utils.h"
#include "screeninit.h" #include "screeninit.h"
#include "draw.h" #include "draw.h"
#include "fs.h"
#include "i2c.h" #include "i2c.h"
#include "buttons.h" #include "buttons.h"
#define COLOR_TITLE 0xFF9900 u32 waitInput(void)
#define COLOR_WHITE 0xFFFFFF {
#define COLOR_RED 0x0000FF u32 pressedKey = 0,
#define COLOR_BLACK 0x000000 key;
struct option {
int posY;
u32 enabled;
};
static u16 waitInput(void){
u32 pressedKey = 0;
u16 key;
//Wait for no keys to be pressed //Wait for no keys to be pressed
while(HID_PAD); while(HID_PAD);
do { do
{
//Wait for a key to be pressed //Wait for a key to be pressed
while(!HID_PAD); while(!HID_PAD);
key = HID_PAD; key = HID_PAD;
//Make sure it's pressed //Make sure it's pressed
for(u32 i = 0x13000; i; i--){ for(u32 i = 0x13000; i; i--)
{
if(key != HID_PAD) break; if(key != HID_PAD) break;
if(i == 1) pressedKey = 1; if(i == 1) pressedKey = 1;
} }
} while(!pressedKey); }
while(!pressedKey);
return key; return key;
} }
void configureCFW(const char *configPath, const char *firm90Path){ void mcuShutDown(void)
initScreens(); {
i2cWriteRegister(I2C_DEV_MCU, 0x20, 1);
while(1);
}
drawString(CONFIG_TITLE, 10, 10, COLOR_TITLE); void mcuReboot(void)
drawString("Press A to select, START to save and reboot", 10, 30, COLOR_WHITE); {
const char *optionsText[] = { "( ) Updated SysNAND mode (A9LH-only)",
"( ) Use pre-patched FIRMs",
"( ) Force A9LH detection",
"( ) Use 9.0 FIRM as default",
"( ) Use second EmuNAND as default",
"( ) Show current NAND in System Settings" };
u32 optionsAmount = sizeof(optionsText) / sizeof(char *);
struct option options[optionsAmount];
//Read and parse the existing configuration
u32 tempConfig = 0;
fileRead(&tempConfig, configPath, 3);
for(u32 i = 0; i < optionsAmount; i++)
options[i].enabled = (tempConfig >> i) & 0x1;
//Pre-select the first configuration option
u32 selectedOption = 0;
//Boring configuration menu
while(1){
u16 pressed = 0;
do{
for(u32 i = 0; i < optionsAmount; i++){
options[i].posY = drawString(optionsText[i], 10, !i ? 60 : options[i - 1].posY + SPACING_Y, selectedOption == i ? COLOR_RED : COLOR_WHITE);
drawCharacter('x', 10 + SPACING_X, options[i].posY, options[i].enabled ? (selectedOption == i ? COLOR_RED : COLOR_WHITE) : COLOR_BLACK);
}
pressed = waitInput();
} while(!(pressed & MENU_BUTTONS));
switch(pressed){
case BUTTON_UP:
selectedOption = !selectedOption ? optionsAmount - 1 : selectedOption - 1;
break;
case BUTTON_DOWN:
selectedOption = selectedOption == optionsAmount - 1 ? 0 : selectedOption + 1;
break;
case BUTTON_LEFT:
selectedOption = 0;
break;
case BUTTON_RIGHT:
selectedOption = optionsAmount - 1;
break;
case BUTTON_A:
options[selectedOption].enabled = !options[selectedOption].enabled;
break;
}
if(pressed == BUTTON_START) break;
}
//If the user has been using A9LH and the "Updated SysNAND" setting changed, delete the patched 9.0 FIRM
if(((tempConfig >> 16) & 0x1) && ((tempConfig & 0x1) != options[0].enabled))
fileDelete(firm90Path);
//Preserve the last-used boot options (last 12 bits)
tempConfig &= 0xFFF000;
//Parse and write the selected options
for(u32 i = 0; i < optionsAmount; i++)
tempConfig |= options[i].enabled << i;
fileWrite(&tempConfig, configPath, 3);
//Zero the last booted FIRM flag
CFG_BOOTENV = 0;
//Reboot
i2cWriteRegister(I2C_DEV_MCU, 0x20, 1 << 2); i2cWriteRegister(I2C_DEV_MCU, 0x20, 1 << 2);
while(1); while(1);
} }
void deleteFirms(const char *firmPaths[], u32 firms){ void error(const char *message)
while(firms){ {
fileDelete(firmPaths[firms - 1]);
firms--;
}
}
void error(const char *message){
initScreens(); initScreens();
drawString("An error has occurred:", 10, 10, COLOR_RED); drawString("An error has occurred:", 10, 10, COLOR_RED);
@@ -137,7 +57,5 @@ void error(const char *message){
waitInput(); waitInput();
//Shutdown mcuShutDown();
i2cWriteRegister(I2C_DEV_MCU, 0x20, 1);
while(1);
} }

View File

@@ -1,15 +1,12 @@
/* /*
* utils.h * utils.h
* by Aurora Wright
* Copyright (c) 2016 All Rights Reserved
*/ */
#pragma once #pragma once
#include "types.h" #include "types.h"
#define CFG_BOOTENV (*(vu8 *)0x10010000) u32 waitInput(void);
void mcuShutDown(void);
void configureCFW(const char *configPath, const char *firm90Path); void mcuReboot(void);
void deleteFirms(const char *firmPaths[], u32 firms);
void error(const char *message); void error(const char *message);