From 47c03cb6dd3a5ce7894c4247e64a12c77ad3d533 Mon Sep 17 00:00:00 2001 From: dimok789 Date: Mon, 12 Dec 2016 19:31:02 +0100 Subject: [PATCH] first release --- .gitignore | 27 + Makefile | 238 ++++++ data/launch_image.tga | Bin 0 -> 903212 bytes ios_bsp/Makefile | 80 ++ ios_bsp/link.ld | 27 + ios_bsp/source/fsa.c | 81 ++ ios_bsp/source/fsa.h | 10 + ios_bsp/source/seeprom.c | 156 ++++ ios_bsp/source/seeprom_asm.s | 9 + ios_bsp/source/svc.h | 21 + ios_bsp/source/svc.s | 45 + ios_bsp/source/types.h | 29 + ios_fs/Makefile | 80 ++ ios_fs/link.ld | 26 + ios_fs/source/devices.c | 150 ++++ ios_fs/source/devices.h | 58 ++ ios_fs/source/dumper.c | 321 +++++++ ios_fs/source/dumper.h | 15 + ios_fs/source/fat32_format.c | 326 ++++++++ ios_fs/source/fat32_format.h | 7 + ios_fs/source/font.c | 49 ++ ios_fs/source/font_bin.h | 1 + ios_fs/source/function_hooks.s | 92 ++ ios_fs/source/hardware_registers.h | 9 + ios_fs/source/imports.h | 36 + ios_fs/source/main.c | 34 + ios_fs/source/mlcio.c | 11 + ios_fs/source/mlcio.h | 6 + ios_fs/source/sdio.c | 107 +++ ios_fs/source/sdio.h | 12 + ios_fs/source/svc.h | 29 + ios_fs/source/svc.s | 68 ++ ios_fs/source/text.c | 90 ++ ios_fs/source/text.h | 11 + ios_fs/source/types.h | 29 + ios_kernel/Makefile | 80 ++ ios_kernel/link.ld | 28 + ios_kernel/source/config.h | 31 + ios_kernel/source/crt0.s | 9 + ios_kernel/source/elf_abi.h | 591 +++++++++++++ ios_kernel/source/elf_patcher.c | 110 +++ ios_kernel/source/elf_patcher.h | 58 ++ ios_kernel/source/exception_handler.c | 62 ++ ios_kernel/source/exception_handler.h | 44 + ios_kernel/source/font_bin.h | 65 ++ ios_kernel/source/fsa.c | 236 ++++++ ios_kernel/source/fsa.h | 55 ++ ios_kernel/source/ios_bsp_patches.c | 80 ++ ios_kernel/source/ios_bsp_patches.h | 31 + ios_kernel/source/ios_fs_patches.c | 84 ++ ios_kernel/source/ios_fs_patches.h | 30 + ios_kernel/source/ios_fs_patches_asm.s | 40 + ios_kernel/source/ios_mcp_patches.c | 57 ++ ios_kernel/source/ios_mcp_patches.h | 32 + ios_kernel/source/ios_mcp_patches_asm.s | 39 + ios_kernel/source/kernel_patches.c | 108 +++ ios_kernel/source/kernel_patches.h | 31 + ios_kernel/source/kernel_patches_asm.s | 17 + ios_kernel/source/main.c | 246 ++++++ ios_kernel/source/text.c | 96 +++ ios_kernel/source/text.h | 11 + ios_kernel/source/types.h | 16 + ios_kernel/source/utils.c | 92 ++ ios_kernel/source/utils.h | 49 ++ ios_mcp/Makefile | 80 ++ ios_mcp/link.ld | 23 + ios_mcp/source/crt0.s | 14 + ios_mcp/source/font.c | 49 ++ ios_mcp/source/font_bin.h | 1 + ios_mcp/source/fsa.c | 437 ++++++++++ ios_mcp/source/fsa.h | 59 ++ ios_mcp/source/imports.c | 49 ++ ios_mcp/source/imports.h | 12 + ios_mcp/source/ipc.c | 480 +++++++++++ ios_mcp/source/ipc.h | 6 + ios_mcp/source/ipc_types.h | 83 ++ ios_mcp/source/logger.c | 71 ++ ios_mcp/source/logger.h | 24 + ios_mcp/source/main.c | 239 ++++++ ios_mcp/source/net_ifmgr_ncl.c | 63 ++ ios_mcp/source/net_ifmgr_ncl.h | 11 + ios_mcp/source/socket.c | 215 +++++ ios_mcp/source/socket.h | 131 +++ ios_mcp/source/svc.h | 31 + ios_mcp/source/svc.s | 99 +++ ios_mcp/source/text.c | 105 +++ ios_mcp/source/text.h | 11 + ios_mcp/source/types.h | 29 + ios_mcp/wupclient.py | 756 +++++++++++++++++ ios_usb/Makefile | 80 ++ ios_usb/link.ld | 17 + ios_usb/source/crt0.s | 9 + ios_usb/source/main.c | 26 + libs/libc.a | Bin 0 -> 909796 bytes libs/libgcc.a | Bin 0 -> 1521600 bytes src/cfw_config.c | 144 ++++ src/cfw_config.h | 46 + src/common/common.h | 36 + src/common/fs_defs.h | 62 ++ src/common/os_defs.h | 25 + src/common/types.h | 7 + src/dynamic_libs/.gitattributes | 17 + src/dynamic_libs/.gitignore | 47 ++ src/dynamic_libs/README.md | 2 + src/dynamic_libs/fs_defs.h | 61 ++ src/dynamic_libs/fs_functions.c | 131 +++ src/dynamic_libs/fs_functions.h | 95 +++ src/dynamic_libs/gx2_functions.c | 173 ++++ src/dynamic_libs/gx2_functions.h | 211 +++++ src/dynamic_libs/gx2_types.h | 699 ++++++++++++++++ src/dynamic_libs/os_functions.c | 216 +++++ src/dynamic_libs/os_functions.h | 150 ++++ src/dynamic_libs/os_types.h | 27 + src/dynamic_libs/socket_functions.c | 81 ++ src/dynamic_libs/socket_functions.h | 108 +++ src/dynamic_libs/sys_functions.c | 51 ++ src/dynamic_libs/sys_functions.h | 48 ++ src/dynamic_libs/vpad_functions.c | 55 ++ src/dynamic_libs/vpad_functions.h | 114 +++ src/entry.c | 14 + src/fs/fs_utils.c | 182 ++++ src/fs/fs_utils.h | 23 + src/fs/sd_fat_devoptab.c | 1019 +++++++++++++++++++++++ src/fs/sd_fat_devoptab.h | 38 + src/link.ld | 40 + src/main.c | 475 +++++++++++ src/main.h | 20 + src/menu.c | 240 ++++++ src/menu.h | 8 + src/system/exception_handler.c | 172 ++++ src/system/exception_handler.h | 14 + src/system/memory.c | 198 +++++ src/system/memory.h | 42 + src/utils/logger.c | 89 ++ src/utils/logger.h | 26 + src/utils/utils.h | 47 ++ 136 files changed, 13181 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 data/launch_image.tga create mode 100644 ios_bsp/Makefile create mode 100644 ios_bsp/link.ld create mode 100644 ios_bsp/source/fsa.c create mode 100644 ios_bsp/source/fsa.h create mode 100644 ios_bsp/source/seeprom.c create mode 100644 ios_bsp/source/seeprom_asm.s create mode 100644 ios_bsp/source/svc.h create mode 100644 ios_bsp/source/svc.s create mode 100644 ios_bsp/source/types.h create mode 100644 ios_fs/Makefile create mode 100644 ios_fs/link.ld create mode 100644 ios_fs/source/devices.c create mode 100644 ios_fs/source/devices.h create mode 100644 ios_fs/source/dumper.c create mode 100644 ios_fs/source/dumper.h create mode 100644 ios_fs/source/fat32_format.c create mode 100644 ios_fs/source/fat32_format.h create mode 100644 ios_fs/source/font.c create mode 100644 ios_fs/source/font_bin.h create mode 100644 ios_fs/source/function_hooks.s create mode 100644 ios_fs/source/hardware_registers.h create mode 100644 ios_fs/source/imports.h create mode 100644 ios_fs/source/main.c create mode 100644 ios_fs/source/mlcio.c create mode 100644 ios_fs/source/mlcio.h create mode 100644 ios_fs/source/sdio.c create mode 100644 ios_fs/source/sdio.h create mode 100644 ios_fs/source/svc.h create mode 100644 ios_fs/source/svc.s create mode 100644 ios_fs/source/text.c create mode 100644 ios_fs/source/text.h create mode 100644 ios_fs/source/types.h create mode 100644 ios_kernel/Makefile create mode 100644 ios_kernel/link.ld create mode 100644 ios_kernel/source/config.h create mode 100644 ios_kernel/source/crt0.s create mode 100644 ios_kernel/source/elf_abi.h create mode 100644 ios_kernel/source/elf_patcher.c create mode 100644 ios_kernel/source/elf_patcher.h create mode 100644 ios_kernel/source/exception_handler.c create mode 100644 ios_kernel/source/exception_handler.h create mode 100644 ios_kernel/source/font_bin.h create mode 100644 ios_kernel/source/fsa.c create mode 100644 ios_kernel/source/fsa.h create mode 100644 ios_kernel/source/ios_bsp_patches.c create mode 100644 ios_kernel/source/ios_bsp_patches.h create mode 100644 ios_kernel/source/ios_fs_patches.c create mode 100644 ios_kernel/source/ios_fs_patches.h create mode 100644 ios_kernel/source/ios_fs_patches_asm.s create mode 100644 ios_kernel/source/ios_mcp_patches.c create mode 100644 ios_kernel/source/ios_mcp_patches.h create mode 100644 ios_kernel/source/ios_mcp_patches_asm.s create mode 100644 ios_kernel/source/kernel_patches.c create mode 100644 ios_kernel/source/kernel_patches.h create mode 100644 ios_kernel/source/kernel_patches_asm.s create mode 100644 ios_kernel/source/main.c create mode 100644 ios_kernel/source/text.c create mode 100644 ios_kernel/source/text.h create mode 100644 ios_kernel/source/types.h create mode 100644 ios_kernel/source/utils.c create mode 100644 ios_kernel/source/utils.h create mode 100644 ios_mcp/Makefile create mode 100644 ios_mcp/link.ld create mode 100644 ios_mcp/source/crt0.s create mode 100644 ios_mcp/source/font.c create mode 100644 ios_mcp/source/font_bin.h create mode 100644 ios_mcp/source/fsa.c create mode 100644 ios_mcp/source/fsa.h create mode 100644 ios_mcp/source/imports.c create mode 100644 ios_mcp/source/imports.h create mode 100644 ios_mcp/source/ipc.c create mode 100644 ios_mcp/source/ipc.h create mode 100644 ios_mcp/source/ipc_types.h create mode 100644 ios_mcp/source/logger.c create mode 100644 ios_mcp/source/logger.h create mode 100644 ios_mcp/source/main.c create mode 100644 ios_mcp/source/net_ifmgr_ncl.c create mode 100644 ios_mcp/source/net_ifmgr_ncl.h create mode 100644 ios_mcp/source/socket.c create mode 100644 ios_mcp/source/socket.h create mode 100644 ios_mcp/source/svc.h create mode 100644 ios_mcp/source/svc.s create mode 100644 ios_mcp/source/text.c create mode 100644 ios_mcp/source/text.h create mode 100644 ios_mcp/source/types.h create mode 100644 ios_mcp/wupclient.py create mode 100644 ios_usb/Makefile create mode 100644 ios_usb/link.ld create mode 100644 ios_usb/source/crt0.s create mode 100644 ios_usb/source/main.c create mode 100644 libs/libc.a create mode 100644 libs/libgcc.a create mode 100644 src/cfw_config.c create mode 100644 src/cfw_config.h create mode 100644 src/common/common.h create mode 100644 src/common/fs_defs.h create mode 100644 src/common/os_defs.h create mode 100644 src/common/types.h create mode 100644 src/dynamic_libs/.gitattributes create mode 100644 src/dynamic_libs/.gitignore create mode 100644 src/dynamic_libs/README.md create mode 100644 src/dynamic_libs/fs_defs.h create mode 100644 src/dynamic_libs/fs_functions.c create mode 100644 src/dynamic_libs/fs_functions.h create mode 100644 src/dynamic_libs/gx2_functions.c create mode 100644 src/dynamic_libs/gx2_functions.h create mode 100644 src/dynamic_libs/gx2_types.h create mode 100644 src/dynamic_libs/os_functions.c create mode 100644 src/dynamic_libs/os_functions.h create mode 100644 src/dynamic_libs/os_types.h create mode 100644 src/dynamic_libs/socket_functions.c create mode 100644 src/dynamic_libs/socket_functions.h create mode 100644 src/dynamic_libs/sys_functions.c create mode 100644 src/dynamic_libs/sys_functions.h create mode 100644 src/dynamic_libs/vpad_functions.c create mode 100644 src/dynamic_libs/vpad_functions.h create mode 100644 src/entry.c create mode 100644 src/fs/fs_utils.c create mode 100644 src/fs/fs_utils.h create mode 100644 src/fs/sd_fat_devoptab.c create mode 100644 src/fs/sd_fat_devoptab.h create mode 100644 src/link.ld create mode 100644 src/main.c create mode 100644 src/main.h create mode 100644 src/menu.c create mode 100644 src/menu.h create mode 100644 src/system/exception_handler.c create mode 100644 src/system/exception_handler.h create mode 100644 src/system/memory.c create mode 100644 src/system/memory.h create mode 100644 src/utils/logger.c create mode 100644 src/utils/logger.h create mode 100644 src/utils/utils.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fc4a5a8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,27 @@ +/*.elf +/build +/ios_bsp/build +/ios_bsp/ios_bsp.bin.h +/ios_bsp/ios_bsp_syms.h +/ios_bsp/*.elf +/ios_bsp/*.bin +/ios_fs/build +/ios_mcp/build +/ios_mcp/*.elf +/ios_mcp/ios_mcp_syms.h +/ios_mcp/ios_mcp.bin.h +/ios_mcp/*.bin +/ios_fs/ios_fs_syms.h +/ios_fs/ios_fs.bin.h +/ios_fs/*.elf +/ios_fs/*.bin +/ios_kernel/*.bin +/ios_kernel/ios_kernel.bin.h +/ios_kernel/*.elf +/ios_kernel/ios_kernel_syms.h +/ios_kernel/build +/ios_usb/*.bin +/ios_usb/ios_usb.bin.h +/ios_usb/*.elf +/ios_usb/ios_usb_syms.h +/ios_usb/build \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..75eb747 --- /dev/null +++ b/Makefile @@ -0,0 +1,238 @@ +#--------------------------------------------------------------------------------- +# Clear the implicit built in rules +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- +ifeq ($(strip $(DEVKITPPC)),) +$(error "Please set DEVKITPPC in your environment. export DEVKITPPC=devkitPPC") +endif +ifeq ($(strip $(DEVKITPRO)),) +$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=devkitPRO") +endif +export PATH := $(DEVKITPPC)/bin:$(PORTLIBS)/bin:$(PATH) +export LIBOGC_INC := $(DEVKITPRO)/libogc/include +export LIBOGC_LIB := $(DEVKITPRO)/libogc/lib/wii +export PORTLIBS := $(DEVKITPRO)/portlibs/ppc + +PREFIX := powerpc-eabi- + +export AS := $(PREFIX)as +export CC := $(PREFIX)gcc +export CXX := $(PREFIX)g++ +export AR := $(PREFIX)ar +export OBJCOPY := $(PREFIX)objcopy + +#--------------------------------------------------------------------------------- +# 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 +# INCLUDES is a list of directories containing extra header files +#--------------------------------------------------------------------------------- +TARGET := mocha +BUILD := build +BUILD_DBG := $(TARGET)_dbg +SOURCES := src \ + src/dynamic_libs \ + src/fs \ + src/system \ + src/utils +DATA := data + +INCLUDES := src + +#--------------------------------------------------------------------------------- +# options for code generation +#--------------------------------------------------------------------------------- +CFLAGS := -std=gnu11 -mrvl -mcpu=750 -meabi -mhard-float -ffast-math \ + -O3 -Wall -Wextra -Wno-unused-parameter -Wno-strict-aliasing $(INCLUDE) +CXXFLAGS := -std=gnu++11 -mrvl -mcpu=750 -meabi -mhard-float -ffast-math \ + -O3 -Wall -Wextra -Wno-unused-parameter -Wno-strict-aliasing $(INCLUDE) +ASFLAGS := -mregnames +LDFLAGS := -nostartfiles -Wl,-Map,$(notdir $@).map,-wrap,malloc,-wrap,free,-wrap,memalign,-wrap,calloc,-wrap,realloc,-wrap,malloc_usable_size,-wrap,_malloc_r,-wrap,_free_r,-wrap,_realloc_r,-wrap,_calloc_r,-wrap,_memalign_r,-wrap,_malloc_usable_size_r,-wrap,valloc,-wrap,_valloc_r,-wrap,_pvalloc_r,--gc-sections + +#--------------------------------------------------------------------------------- +Q := @ +MAKEFLAGS += --no-print-directory +#--------------------------------------------------------------------------------- +# any extra libraries we wish to link with the project +#--------------------------------------------------------------------------------- +LIBS := + +#--------------------------------------------------------------------------------- +# list of directories containing libraries, this must be the top level containing +# include and lib +#--------------------------------------------------------------------------------- +LIBDIRS := $(CURDIR) \ + $(DEVKITPPC)/lib \ + $(DEVKITPPC)/lib/gcc/powerpc-eabi/4.8.2 + + +#--------------------------------------------------------------------------------- +# 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 PROJECTDIR := $(CURDIR) +export OUTPUT := $(CURDIR)/$(TARGETDIR)/$(TARGET) +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) +export DEPSDIR := $(CURDIR)/$(BUILD) + +#--------------------------------------------------------------------------------- +# automatically build a list of object files for our project +#--------------------------------------------------------------------------------- +CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) +CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) +sFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) +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 := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) \ + $(sFILES:.s=.o) $(SFILES:.S=.o) \ + $(PNGFILES:.png=.png.o) $(addsuffix .o,$(BINFILES)) + +#--------------------------------------------------------------------------------- +# build a list of include paths +#--------------------------------------------------------------------------------- +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(BUILD) -I$(LIBOGC_INC) \ + -I$(PORTLIBS)/include -I$(PORTLIBS)/include/freetype2 + +#--------------------------------------------------------------------------------- +# build a list of library paths +#--------------------------------------------------------------------------------- +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) \ + -L$(LIBOGC_LIB) -L$(PORTLIBS)/lib + +export OUTPUT := $(CURDIR)/$(TARGET) +.PHONY: $(BUILD) clean install + +#--------------------------------------------------------------------------------- +$(BUILD): $(CURDIR)/ios_kernel/ios_kernel.bin.h + @[ -d $@ ] || mkdir -p $@ + @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile + +$(CURDIR)/ios_kernel/ios_kernel.bin.h: $(CURDIR)/ios_usb/ios_usb.bin.h $(CURDIR)/ios_mcp/ios_mcp.bin.h $(CURDIR)/ios_fs/ios_fs.bin.h $(CURDIR)/ios_bsp/ios_bsp.bin.h + @$(MAKE) --no-print-directory -C $(CURDIR)/ios_kernel -f $(CURDIR)/ios_kernel/Makefile + +$(CURDIR)/ios_usb/ios_usb.bin.h: + @$(MAKE) --no-print-directory -C $(CURDIR)/ios_usb -f $(CURDIR)/ios_usb/Makefile + +$(CURDIR)/ios_fs/ios_fs.bin.h: + @$(MAKE) --no-print-directory -C $(CURDIR)/ios_fs -f $(CURDIR)/ios_fs/Makefile + +$(CURDIR)/ios_bsp/ios_bsp.bin.h: + @$(MAKE) --no-print-directory -C $(CURDIR)/ios_bsp -f $(CURDIR)/ios_bsp/Makefile + +$(CURDIR)/ios_mcp/ios_mcp.bin.h: + @$(MAKE) --no-print-directory -C $(CURDIR)/ios_mcp -f $(CURDIR)/ios_mcp/Makefile + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(BUILD) $(OUTPUT).elf $(OUTPUT).bin $(BUILD_DBG).elf + @$(MAKE) --no-print-directory -C $(CURDIR)/ios_kernel -f $(CURDIR)/ios_kernel/Makefile clean + @$(MAKE) --no-print-directory -C $(CURDIR)/ios_usb -f $(CURDIR)/ios_usb/Makefile clean + @$(MAKE) --no-print-directory -C $(CURDIR)/ios_fs -f $(CURDIR)/ios_fs/Makefile clean + @$(MAKE) --no-print-directory -C $(CURDIR)/ios_bsp -f $(CURDIR)/ios_bsp/Makefile clean + @$(MAKE) --no-print-directory -C $(CURDIR)/ios_mcp -f $(CURDIR)/ios_mcp/Makefile clean + + +#--------------------------------------------------------------------------------- +else + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +$(OUTPUT).elf: $(OFILES) + +#--------------------------------------------------------------------------------- +# This rule links in binary data with the .jpg extension +#--------------------------------------------------------------------------------- +%.elf: link.ld $(OFILES) + @echo "linking ... $(TARGET).elf" + $(Q)$(LD) -n -T $^ $(LDFLAGS) -o ../$(BUILD_DBG).elf $(LIBPATHS) $(LIBS) + $(Q)$(OBJCOPY) -S -R .comment -R .gnu.attributes ../$(BUILD_DBG).elf $@ + +../data/loader.bin: + $(MAKE) -C ../loader clean + $(MAKE) -C ../loader +#--------------------------------------------------------------------------------- +%.a: +#--------------------------------------------------------------------------------- + @echo $(notdir $@) + @rm -f $@ + @$(AR) -rc $@ $^ + +#--------------------------------------------------------------------------------- +%.o: %.cpp + @echo $(notdir $<) + @$(CXX) -MMD -MP -MF $(DEPSDIR)/$*.d $(CXXFLAGS) -c $< -o $@ $(ERROR_FILTER) + +#--------------------------------------------------------------------------------- +%.o: %.c + @echo $(notdir $<) + @$(CC) -MMD -MP -MF $(DEPSDIR)/$*.d $(CFLAGS) -c $< -o $@ $(ERROR_FILTER) + +#--------------------------------------------------------------------------------- +%.o: %.S + @echo $(notdir $<) + @$(CC) -MMD -MP -MF $(DEPSDIR)/$*.d -x assembler-with-cpp $(ASFLAGS) -c $< -o $@ $(ERROR_FILTER) + +#--------------------------------------------------------------------------------- +%.png.o : %.png + @echo $(notdir $<) + @bin2s -a 32 $< | $(AS) -o $(@) + +#--------------------------------------------------------------------------------- +%.jpg.o : %.jpg + @echo $(notdir $<) + @bin2s -a 32 $< | $(AS) -o $(@) + +#--------------------------------------------------------------------------------- +%.ttf.o : %.ttf + @echo $(notdir $<) + @bin2s -a 32 $< | $(AS) -o $(@) + +#--------------------------------------------------------------------------------- +%.bin.o : %.bin + @echo $(notdir $<) + @bin2s -a 32 $< | $(AS) -o $(@) + +#--------------------------------------------------------------------------------- +%.wav.o : %.wav + @echo $(notdir $<) + @bin2s -a 32 $< | $(AS) -o $(@) + +#--------------------------------------------------------------------------------- +%.mp3.o : %.mp3 + @echo $(notdir $<) + @bin2s -a 32 $< | $(AS) -o $(@) + +#--------------------------------------------------------------------------------- +%.ogg.o : %.ogg + @echo $(notdir $<) + @bin2s -a 32 $< | $(AS) -o $(@) +#--------------------------------------------------------------------------------- +%.tga.o : %.tga + @echo $(notdir $<) + @bin2s -a 32 $< | $(AS) -o $(@) + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- diff --git a/data/launch_image.tga b/data/launch_image.tga new file mode 100644 index 0000000000000000000000000000000000000000..42bbad07e5f75333a53e27746fd0c4b4ce027324 GIT binary patch literal 903212 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 h^8ftT|Ml~K|KdevkitARM") +endif + +ifeq ($(filter $(DEVKITARM)/bin,$(PATH)),) +export PATH:=$(DEVKITARM)/bin:$(PATH) +endif + +CC = arm-none-eabi-gcc +LINK = arm-none-eabi-gcc +AS = arm-none-eabi-as +OBJCOPY = arm-none-eabi-objcopy +OBJDUMP = arm-none-eabi-objdump +CFLAGS += -Wall -mbig-endian -std=gnu11 -mcpu=arm926ej-s -msoft-float -mfloat-abi=soft -Os +LDFLAGS += -nostartfiles -nodefaultlibs -mbig-endian -Wl,-T,link.ld +LIBDIRS += -L$(CURDIR)/../libs +LIBS += -lgcc + +CFILES = $(wildcard source/*.c) +BINFILES = $(wildcard data/*.bin) +OFILES = $(BINFILES:data/%.bin=build/%.bin.o) +OFILES += $(CFILES:source/%.c=build/%.o) +DFILES = $(CFILES:source/%.c=build/%.d) +SFILES = $(wildcard source/*.s) +OFILES += $(SFILES:source/%.s=build/%.o) +PROJECTNAME = ${shell basename "$(CURDIR)"} +CWD = "$(CURDIR)"" + +#--------------------------------------------------------------------------------- +# canned command sequence for binary data, taken from devkitARM +#--------------------------------------------------------------------------------- +define bin2o + bin2s $< | $(AS) -EB -o $(@) +endef + +.PHONY:=all dirs + +all: dirs $(PROJECTNAME).bin $(PROJECTNAME)_syms.h $(PROJECTNAME).bin $(PROJECTNAME).bin.h + +dirs: + @mkdir -p build + +$(PROJECTNAME).elf: $(OFILES) + @echo "LD $@" + @$(LINK) $(LDFLAGS) -o $(PROJECTNAME).elf $(sort $(filter-out build/crt0.o, $(OFILES))) $(LIBDIRS) $(LIBS) + +$(PROJECTNAME).bin: $(PROJECTNAME).elf + @echo "OBJCOPY $@\n" + @$(OBJCOPY) -j .text -j .rodata -j .data -O binary $(PROJECTNAME).elf $@ + +$(PROJECTNAME).bin.h: $(PROJECTNAME).bin + @xxd -i $< | sed "s/unsigned/static const unsigned/g;s/$(PROJECTNAME)$*/$(PROJECTNAME)/g" > $@ + +$(PROJECTNAME)_syms.h: + @echo "#ifndef $(PROJECTNAME)_SYMS_H" > $@ + @echo "#define $(PROJECTNAME)_SYMS_H" >> $@ + @$(OBJDUMP) -EB -t -marm $(PROJECTNAME).elf | grep 'g F .text' | grep -v '.hidden' | awk '{print "#define " $$6 " 0x" $$1}' >> $@ + @$(OBJDUMP) -EB -t -marm $(PROJECTNAME).elf | grep -e 'g .text' -e '_bss_' -e "_seeprom_buffer_start" | awk '{print "#define " $$5 " 0x" $$1}' >> $@ + @echo "#endif" >> $@ + +clean: + @rm -f build/*.o build/*.d + @rm -f $(PROJECTNAME).elf $(PROJECTNAME).bin $(PROJECTNAME)_syms.h $(PROJECTNAME).bin $(PROJECTNAME).bin.h + @echo "all cleaned up !" + +-include $(DFILES) + +build/%.o: source/%.c + @echo "CC $(notdir $<)" + @$(CC) $(CFLAGS) -c $< -o $@ + @$(CC) -MM $< > build/$*.d + +build/%.o: source/%.s + @echo "CC $(notdir $<)" + @$(CC) $(CFLAGS) -xassembler-with-cpp -c $< -o $@ + @$(CC) -MM $< > build/$*.d + +build/%.bin.o: data/%.bin + @echo "BIN $(notdir $<)" + @$(bin2o) diff --git a/ios_bsp/link.ld b/ios_bsp/link.ld new file mode 100644 index 0000000..161d815 --- /dev/null +++ b/ios_bsp/link.ld @@ -0,0 +1,27 @@ +OUTPUT_ARCH(arm) + +SECTIONS +{ + .text 0xE6010A80 : { + _text_start = .; + *(.text*); + *(.rodata*); + } + _text_end = .; + + .bss 0xE60481F0 : { + _bss_start = .; + *(.bss*); + *(COMMON); + } + .seeprom_buffer : { + _seeprom_buffer_start = .; + *(.seeprom_buffer*); + } + _bss_end = .; + + /DISCARD/ : { + *(*); + } +} + diff --git a/ios_bsp/source/fsa.c b/ios_bsp/source/fsa.c new file mode 100644 index 0000000..b092ba0 --- /dev/null +++ b/ios_bsp/source/fsa.c @@ -0,0 +1,81 @@ +#include +#include +#include "svc.h" +#include "fsa.h" + +#define BSP_memcpy ((void *(*)(void*, void*, unsigned int))0xE600EA18) +#define BSP_memset ((void *(*)(void*, int, unsigned int))0xE600EAB4) +#define BSP_strncpy ((char *(*)(char*, const char*, unsigned int))0xE600F4AC) + +static void* allocIobuf() +{ + void* ptr = svcAlloc(0xCAFF, 0x828); + BSP_memset(ptr, 0x00, 0x828); + + return ptr; +} + +static void freeIobuf(void* ptr) +{ + svcFree(0xCAFF, ptr); +} + +int FSA_RawOpen(int fd, const char* device_path, int* outHandle) +{ + u8* iobuf = allocIobuf(); + u32* inbuf = (u32*)iobuf; + u32* outbuf = (u32*)&iobuf[0x520]; + + BSP_strncpy((char*)&inbuf[0x01], device_path, 0x27F); + + int ret = svcIoctl(fd, 0x6A, inbuf, 0x520, outbuf, 0x293); + + if(outHandle) *outHandle = outbuf[1]; + + freeIobuf(iobuf); + return ret; +} + +int FSA_RawClose(int fd, int device_handle) +{ + u8* iobuf = allocIobuf(); + u32* inbuf = (u32*)iobuf; + u32* outbuf = (u32*)&iobuf[0x520]; + + inbuf[1] = device_handle; + + int ret = svcIoctl(fd, 0x6D, inbuf, 0x520, outbuf, 0x293); + + freeIobuf(iobuf); + return ret; +} + +int FSA_RawWrite(int fd, void* data, u32 size_bytes, u32 cnt, u64 blocks_offset, int device_handle) +{ + u8* iobuf = allocIobuf(); + u8* inbuf8 = iobuf; + u8* outbuf8 = &iobuf[0x520]; + iovec_s* iovec = (iovec_s*)&iobuf[0x7C0]; + u32* inbuf = (u32*)inbuf8; + u32* outbuf = (u32*)outbuf8; + + inbuf[0x08 / 4] = (blocks_offset >> 32); + inbuf[0x0C / 4] = (blocks_offset & 0xFFFFFFFF); + inbuf[0x10 / 4] = cnt; + inbuf[0x14 / 4] = size_bytes; + inbuf[0x18 / 4] = device_handle; + + iovec[0].ptr = inbuf; + iovec[0].len = 0x520; + + iovec[1].ptr = data; + iovec[1].len = size_bytes * cnt; + + iovec[2].ptr = outbuf; + iovec[2].len = 0x293; + + int ret = svcIoctlv(fd, 0x6C, 2, 1, iovec); + + freeIobuf(iobuf); + return ret; +} diff --git a/ios_bsp/source/fsa.h b/ios_bsp/source/fsa.h new file mode 100644 index 0000000..4faf6b7 --- /dev/null +++ b/ios_bsp/source/fsa.h @@ -0,0 +1,10 @@ +#ifndef FSA_H +#define FSA_H + +#include "types.h" + +int FSA_RawOpen(int fd, const char* device_path, int* outHandle); +int FSA_RawWrite(int fd, void* data, u32 size_bytes, u32 cnt, u64 sector_offset, int device_handle); +int FSA_RawClose(int fd, int device_handle); + +#endif diff --git a/ios_bsp/source/seeprom.c b/ios_bsp/source/seeprom.c new file mode 100644 index 0000000..57a6433 --- /dev/null +++ b/ios_bsp/source/seeprom.c @@ -0,0 +1,156 @@ +/*************************************************************************** + * Copyright (C) 2016 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include "svc.h" +#include "fsa.h" + +#define SD_SEEPROM_SECTOR 0x4FF + +#define BSP_MEMCPY ((void * (*)(void *, void *, unsigned int size))0xE600EA18) + +static int writeEnabled = 0; +static int dirty = 0; + +unsigned char seeprom_buffer[512] __attribute__((section(".seeprom_buffer"))); + +extern int orig_EEPROM_SPI_ReadWord(int handle_index, unsigned char index, unsigned short *outbuf); + +static int SD_EEPROM_WriteAll(void) +{ + int fsa = svcOpen("/dev/fsa", 0); + if(fsa < 0) + return fsa; + + int fd; + int res = FSA_RawOpen(fsa, "/dev/sdcard01", &fd); + if(res >= 0) + { + void *buffer = svcAllocAlign(0xCAFF, 0x200, 0x40); + if(buffer) + { + // user global buffer for FSA to be able to access it + BSP_MEMCPY(buffer, seeprom_buffer, 0x200); + res = FSA_RawWrite(fsa, buffer, 0x200, 1, SD_SEEPROM_SECTOR, fd); + svcFree(0xCAFF, buffer); + } + else + res = -1; + + FSA_RawClose(fsa, fd); + } + svcClose(fsa); + return res; +} + +static void EEPROM_InitializeCache(int handle_index) +{ + int i; + for(i = 0; i < 0x100; i++) + { + orig_EEPROM_SPI_ReadWord(handle_index, i, (unsigned short*)(seeprom_buffer + (i << 1))); + } +} + +int EEPROM_SPI_ReadWord(int handle_index, unsigned char index, unsigned short *outbuf) +{ + unsigned int offset = ((unsigned int)index) << 1; + + // check for valid eeprom dump and initialize if none was on sd card + if(*(u32*)(seeprom_buffer + 0x20) != 0x70010201) // PPC PVR + { + EEPROM_InitializeCache(handle_index); // could actually just use 0 for handle index + dirty = 1; + } + + // don't redirect the drive key as it is specific for the drive on the wii u + // the seeprom key is the same for all wiiu's it seems so nothing to re-encrypt here + if(offset >= 0x80 && offset < 0x90) + { + return orig_EEPROM_SPI_ReadWord(handle_index, index, outbuf); + } + + if(!outbuf || (offset >= 512)) + { + return -5; + } + + *outbuf = *(unsigned short*)(seeprom_buffer + offset); + + if(dirty && SD_EEPROM_WriteAll() == 0) + { + dirty = 0; + } + return 0; +} + +int EEPROM_SPI_WriteWord(int handle_index, unsigned char index, unsigned short data) +{ + if(writeEnabled == 0) + { + return -5; + } + + // check for valid eeprom dump and initialize if none was on sd card + if(*(u32*)(seeprom_buffer + 0x20) != 0x70010201) // PPC PVR + { + EEPROM_InitializeCache(handle_index); // could actually just use 0 for handle index + } + + unsigned int offset = ((unsigned int)index) << 1; + + if(offset >= 512) + { + return -5; + } + + *(unsigned short*)(seeprom_buffer + offset) = data; + dirty = 1; + + if(SD_EEPROM_WriteAll() == 0) + { + dirty = 0; + } + + return 0; +} + +int EEPROM_WriteControl(int handle_index, int type) +{ + if(type == 1) + { + writeEnabled = 0; + } + else if(type == 2) + { + writeEnabled = 1; + } + else if(type == 3) + { + // erase all -> skip that part...its actually never used but would be only a memset with 0xFF + } + else + { + return -4; + } + return 0; +} diff --git a/ios_bsp/source/seeprom_asm.s b/ios_bsp/source/seeprom_asm.s new file mode 100644 index 0000000..311a34b --- /dev/null +++ b/ios_bsp/source/seeprom_asm.s @@ -0,0 +1,9 @@ +.section ".text" +.arm + +.globl orig_EEPROM_SPI_ReadWord +orig_EEPROM_SPI_ReadWord: + cmp r0, #0 + ldr r3, [pc] + bx r3 + .word 0xE600D090 diff --git a/ios_bsp/source/svc.h b/ios_bsp/source/svc.h new file mode 100644 index 0000000..98b5cc8 --- /dev/null +++ b/ios_bsp/source/svc.h @@ -0,0 +1,21 @@ +#ifndef SVC_H +#define SVC_H + +#include "types.h" + +typedef struct +{ + void* ptr; + u32 len; + u32 unk; +}iovec_s; + +void* svcAlloc(u32 heapid, u32 size); +void* svcAllocAlign(u32 heapid, u32 size, u32 align); +void svcFree(u32 heapid, void* ptr); +int svcOpen(char* name, int mode); +int svcClose(int fd); +int svcIoctl(int fd, u32 request, void* input_buffer, u32 input_buffer_len, void* output_buffer, u32 output_buffer_len); +int svcIoctlv(int fd, u32 request, u32 vector_count_in, u32 vector_count_out, iovec_s* vector); + +#endif diff --git a/ios_bsp/source/svc.s b/ios_bsp/source/svc.s new file mode 100644 index 0000000..f391001 --- /dev/null +++ b/ios_bsp/source/svc.s @@ -0,0 +1,45 @@ +.section ".text" +.arm +.align 4 + +.global svcAlloc +.type svcAlloc, %function +svcAlloc: + .word 0xE7F027F0 + bx lr + +.global svcAllocAlign +.type svcAllocAlign, %function +svcAllocAlign: + .word 0xE7F028F0 + bx lr + +.global svcFree +.type svcFree, %function +svcFree: + .word 0xE7F029F0 + bx lr + +.global svcOpen +.type svcOpen, %function +svcOpen: + .word 0xE7F033F0 + bx lr + +.global svcClose +.type svcClose, %function +svcClose: + .word 0xE7F034F0 + bx lr + +.global svcIoctl +.type svcIoctl, %function +svcIoctl: + .word 0xE7F038F0 + bx lr + +.global svcIoctlv +.type svcIoctlv, %function +svcIoctlv: + .word 0xE7F039F0 + bx lr diff --git a/ios_bsp/source/types.h b/ios_bsp/source/types.h new file mode 100644 index 0000000..832bc29 --- /dev/null +++ b/ios_bsp/source/types.h @@ -0,0 +1,29 @@ +#ifndef TYPES_H +#define TYPES_H + + #include + #include + + #define U64_MAX UINT64_MAX + + typedef uint8_t u8; + typedef uint16_t u16; + typedef uint32_t u32; + typedef uint64_t u64; + + typedef int8_t s8; + typedef int16_t s16; + typedef int32_t s32; + typedef int64_t s64; + + typedef volatile u8 vu8; + typedef volatile u16 vu16; + typedef volatile u32 vu32; + typedef volatile u64 vu64; + + typedef volatile s8 vs8; + typedef volatile s16 vs16; + typedef volatile s32 vs32; + typedef volatile s64 vs64; + +#endif diff --git a/ios_fs/Makefile b/ios_fs/Makefile new file mode 100644 index 0000000..083d180 --- /dev/null +++ b/ios_fs/Makefile @@ -0,0 +1,80 @@ +ifeq ($(strip $(DEVKITARM)),) +$(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") +endif + +ifeq ($(filter $(DEVKITARM)/bin,$(PATH)),) +export PATH:=$(DEVKITARM)/bin:$(PATH) +endif + +CC = arm-none-eabi-gcc +LINK = arm-none-eabi-gcc +AS = arm-none-eabi-as +OBJCOPY = arm-none-eabi-objcopy +OBJDUMP = arm-none-eabi-objdump +CFLAGS += -Wall -mbig-endian -std=gnu11 -mcpu=arm926ej-s -msoft-float -mfloat-abi=soft -Os +LDFLAGS += -nostartfiles -nodefaultlibs -mbig-endian -Wl,-T,link.ld +LIBDIRS += -L$(CURDIR)/../libs +LIBS += -lgcc + +CFILES = $(wildcard source/*.c) +BINFILES = $(wildcard data/*.bin) +OFILES = $(BINFILES:data/%.bin=build/%.bin.o) +OFILES += $(CFILES:source/%.c=build/%.o) +DFILES = $(CFILES:source/%.c=build/%.d) +SFILES = $(wildcard source/*.s) +OFILES += $(SFILES:source/%.s=build/%.o) +PROJECTNAME = ${shell basename "$(CURDIR)"} +CWD = "$(CURDIR)"" + +#--------------------------------------------------------------------------------- +# canned command sequence for binary data, taken from devkitARM +#--------------------------------------------------------------------------------- +define bin2o + bin2s $< | $(AS) -EB -o $(@) +endef + +.PHONY:=all dirs + +all: dirs $(PROJECTNAME).bin $(PROJECTNAME)_syms.h $(PROJECTNAME).bin $(PROJECTNAME).bin.h + +dirs: + @mkdir -p build + +$(PROJECTNAME).elf: $(OFILES) + @echo "LD $@" + @$(LINK) $(LDFLAGS) -o $(PROJECTNAME).elf $(sort $(filter-out build/crt0.o, $(OFILES))) $(LIBDIRS) $(LIBS) + +$(PROJECTNAME).bin: $(PROJECTNAME).elf + @echo "OBJCOPY $@\n" + @$(OBJCOPY) -j .text -j .rodata -j .data -O binary $(PROJECTNAME).elf $@ + +$(PROJECTNAME).bin.h: $(PROJECTNAME).bin + @xxd -i $< | sed "s/unsigned/static const unsigned/g;s/$(PROJECTNAME)$*/$(PROJECTNAME)/g" > $@ + +$(PROJECTNAME)_syms.h: + @echo "#ifndef $(PROJECTNAME)_SYMS_H" > $@ + @echo "#define $(PROJECTNAME)_SYMS_H" >> $@ + @$(OBJDUMP) -EB -t -marm $(PROJECTNAME).elf | grep 'g F .text' | grep -v '.hidden' | awk '{print "#define " $$6 " 0x" $$1}' >> $@ + @$(OBJDUMP) -EB -t -marm $(PROJECTNAME).elf | grep -e 'g .text' -e '_bss_' | awk '{print "#define " $$5 " 0x" $$1}' >> $@ + @echo "#endif" >> $@ + +clean: + @rm -f build/*.o build/*.d + @rm -f $(PROJECTNAME).elf $(PROJECTNAME).bin $(PROJECTNAME)_syms.h $(PROJECTNAME).bin $(PROJECTNAME).bin.h + @echo "all cleaned up !" + +-include $(DFILES) + +build/%.o: source/%.c + @echo "CC $(notdir $<)" + @$(CC) $(CFLAGS) -c $< -o $@ + @$(CC) -MM $< > build/$*.d + +build/%.o: source/%.s + @echo "CC $(notdir $<)" + @$(CC) $(CFLAGS) -xassembler-with-cpp -c $< -o $@ + @$(CC) -MM $< > build/$*.d + +build/%.bin.o: data/%.bin + @echo "BIN $(notdir $<)" + @$(bin2o) diff --git a/ios_fs/link.ld b/ios_fs/link.ld new file mode 100644 index 0000000..6028580 --- /dev/null +++ b/ios_fs/link.ld @@ -0,0 +1,26 @@ +OUTPUT_ARCH(arm) + +SECTIONS +{ + .text (0x10700000 + 0x000F8200) : { + _text_start = .; + *(.text*); + *(.rodata*); + } + _text_end = .; + + .bss (0x10835000 + 0x1406554) : { + _bss_start = .; + *(.bss*); + *(COMMON); + } + .io_buffer : ALIGN(0x40) { + *(.io_buffer*); + } + _bss_end = .; + + /DISCARD/ : { + *(*); + } +} + diff --git a/ios_fs/source/devices.c b/ios_fs/source/devices.c new file mode 100644 index 0000000..993279d --- /dev/null +++ b/ios_fs/source/devices.c @@ -0,0 +1,150 @@ +#include +#include "types.h" +#include "devices.h" +#include "imports.h" +#include "sdio.h" +#include "text.h" + +void * getMdDeviceById(int deviceId) +{ + if(deviceId == DEVICE_ID_SDCARD_PATCHED) + { + return (void*)FS_MMC_SDCARD_STRUCT; + } + else if(deviceId == DEVICE_ID_MLC) + { + return (void*)FS_MMC_MLC_STRUCT; + } + return NULL; +} + +int registerMdDevice_hook(void * md, int arg2, int arg3) +{ + u32 *mdStruct = (u32*)md; + + if((md != 0) && (mdStruct[2] == (u32)FS_MMC_SDCARD_STRUCT)) + { + sdcard_lock_mutex(); + FS_MMC_SDCARD_STRUCT[0x24/4] = FS_MMC_SDCARD_STRUCT[0x24/4] & (~0x20); + + int result = FS_REGISTERMDPHYSICALDEVICE(md, arg2, arg3); + + sdcard_unlock_mutex(); + + return result; + } + + return FS_REGISTERMDPHYSICALDEVICE(md, arg2, arg3); +} + +int getPhysicalDeviceHandle(u32 device) +{ + u32 handleSize = 0x204; + u8 *handleBase = (u8*)(0x1091C2EC + device * handleSize); + u16 adrLow = (*(u16*)&handleBase[6]); + return ((device << 16) | adrLow); +} + +//! read1(void *physical_device_info, int offset_high, int offset_low, int cnt, int block_size, void *data_outptr, void *callback, int callback_parameter) +int readWriteCallback_patch(int is_read, int offset_offset, int offset_low, int cnt, int block_size, void *data_outptr, read_write_callback_t callback, int callback_parameter) +{ + int result_arg = 0; + int result = sdcard_readwrite(is_read, data_outptr, cnt, block_size, offset_offset + offset_low, &result_arg, DEVICE_ID_SDCARD_PATCHED); + + if((result == 0) && (callback != 0)) + { + callback(result_arg, callback_parameter); + } + return result; +} + +//!------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//! USB redirection +//!------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +static int usbReadWrite_patch(int is_read, u32 offset_high, u32 offset_low, u32 cnt, u32 block_size, void *data_outptr, read_write_callback_t callback, int callback_parameter) +{ + return readWriteCallback_patch(is_read, USB_BASE_SECTORS, offset_low, cnt, block_size, data_outptr, callback, callback_parameter); +} + +int usbRead_patch(void *physical_device_info, u32 offset_high, u32 offset_low, u32 cnt, u32 block_size, void *data_outptr, read_write_callback_t callback, int callback_parameter) +{ + return usbReadWrite_patch(SDIO_READ, offset_high, offset_low, cnt, block_size, data_outptr, callback, callback_parameter); +} + +int usbWrite_patch(void *physical_device_info, u32 offset_high, u32 offset_low, u32 cnt, u32 block_size, void *data_outptr, read_write_callback_t callback, int callback_parameter) +{ + return usbReadWrite_patch(SDIO_WRITE, offset_high, offset_low, cnt, block_size, data_outptr, callback, callback_parameter); +} + +//!------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//! SDIO redirection +//!------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +static int sdcardReadWrite_patch(void *physical_device_info, int is_read, u32 offset_low, u32 cnt, u32 block_size, void *data_outptr, read_write_callback_t callback, int callback_parameter) +{ + u32 offset_offset; + u32 *phys_dev = (u32*)physical_device_info; + + if(phys_dev[0x14/4] != DEVICE_TYPE_SDCARD) + { + offset_offset = MLC_BASE_SECTORS; + } + else + { + offset_offset = 0; + } + + return readWriteCallback_patch(is_read, offset_offset, offset_low, cnt, block_size, data_outptr, callback, callback_parameter); +} + +int sdcardRead_patch(void *physical_device_info, u32 offset_high, u32 offset_low, u32 cnt, u32 block_size, void *data_outptr, read_write_callback_t callback, int callback_parameter) +{ + return sdcardReadWrite_patch(physical_device_info, SDIO_READ, offset_low, cnt, block_size, data_outptr, callback, callback_parameter); +} + +int sdcardWrite_patch(void *physical_device_info, u32 offset_high, u32 offset_low, u32 cnt, u32 block_size, void *data_outptr, read_write_callback_t callback, int callback_parameter) +{ + return sdcardReadWrite_patch(physical_device_info, SDIO_WRITE, offset_low, cnt, block_size, data_outptr, callback, callback_parameter); +} + +//!------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//! SLC redirection +//!------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +static int slcReadWrite_patch(void *physical_device_info, int is_read, u32 offset_low, u32 cnt, u32 block_size, void *data_outptr, read_write_callback_t callback, int callback_parameter) +{ + u32 offset_offset; + u32 *phys_dev = (u32*)physical_device_info; + + if(phys_dev[1] != 0) + { + // physical_device_info = 0x11C381CC + offset_offset = (u32)(((u64)SLC_BASE_SECTORS * (u64)SDIO_BYTES_PER_SECTOR) / SLC_BYTES_PER_SECTOR); + } + else + { + // physical_device_info = 0x11C37668 + offset_offset = (u32)(((u64)SLCCMPT_BASE_SECTORS * (u64)SDIO_BYTES_PER_SECTOR) / SLC_BYTES_PER_SECTOR); + } + + return readWriteCallback_patch(is_read, offset_offset, offset_low, cnt, block_size, data_outptr, callback, callback_parameter); +} + +int slcRead1_patch(void *physical_device_info, u32 offset_high, u32 offset_low, u32 cnt, u32 block_size, void *data_outptr, read_write_callback_t callback, int callback_parameter) +{ + return slcReadWrite_patch(physical_device_info, SDIO_READ, offset_low, cnt, block_size, data_outptr, callback, callback_parameter); +} + +int slcWrite1_patch(void *physical_device_info, u32 offset_high, u32 offset_low, u32 cnt, u32 block_size, void *data_outptr, read_write_callback_t callback, int callback_parameter) +{ + return slcReadWrite_patch(physical_device_info, SDIO_WRITE, offset_low, cnt, block_size, data_outptr, callback, callback_parameter); +} + +int slcRead2_patch(void *physical_device_info, u32 offset_high, u32 offset_low, u32 cnt, u32 block_size, int ukn1, void *data_outptr, int ukn2, read_write_callback_t callback, int callback_parameter) +{ + return slcReadWrite_patch(physical_device_info, SDIO_READ, offset_low, cnt, block_size, data_outptr, callback, callback_parameter); +} + +int slcWrite2_patch(void *physical_device_info, u32 offset_high, u32 offset_low, u32 cnt, u32 block_size, int ukn1, void *data_outptr, int ukn2, read_write_callback_t callback, int callback_parameter) +{ + return slcReadWrite_patch(physical_device_info, SDIO_WRITE, offset_low, cnt, block_size, data_outptr, callback, callback_parameter); +} + diff --git a/ios_fs/source/devices.h b/ios_fs/source/devices.h new file mode 100644 index 0000000..4c172ca --- /dev/null +++ b/ios_fs/source/devices.h @@ -0,0 +1,58 @@ +#ifndef DEVICES_H_ +#define DEVICES_H_ + +#define DEVICE_TYPE_SDCARD 0x06 + +#define DEVICE_ID_SDCARD_REAL 0x43 +#define DEVICE_ID_SDCARD_PATCHED 0xDA + +#define DEVICE_ID_MLC 0xAB + +#define SDIO_BYTES_PER_SECTOR 512 +#define MLC_BYTES_PER_SECTOR 512 +#define SLC_BYTES_PER_SECTOR 2048 + +#define SLC_BASE_SECTORS (0x000500) +#define SLCCMPT_BASE_SECTORS (0x100500) +#define MLC_BASE_SECTORS (0x200500) + +#define USB_BASE_SECTORS (0x2720000) +#define SYSLOG_BASE_SECTORS (0x6D00000) +#define DUMPDATA_BASE_SECTORS (SYSLOG_BASE_SECTORS + (0x40000 / SDIO_BYTES_PER_SECTOR)) + +#define SLC_SECTOR_COUNT 0x40000 +#define MLC_8GB_SECTOR_COUNT 0xE90000 +#define MLC_32GB_SECTOR_COUNT 0x3A3E000 //0x3A20000 + +#define MLC_NAND_TYPE_32GB 0 +#define MLC_NAND_TYPE_8GB 1 + +#define NAND_DUMP_SIGNATURE_SECTOR 0x01 +#define NAND_DUMP_SIGNATURE 0x4841585844554d50ULL // HAXXDUMP + +#define NAND_DESC_TYPE_SLC 0x534c4320 // 'SLC ' +#define NAND_DESC_TYPE_SLCCMPT 0x534c4332 // 'SLC2' +#define NAND_DESC_TYPE_MLC 0x4d4c4320 // 'MLC ' + +typedef struct _stdio_nand_desc_t +{ + u32 nand_type; // nand type + u32 base_sector; // base sector of dump + u32 sector_count; // sector count in SDIO sectors +} __attribute__((packed))stdio_nand_desc_t; + +typedef struct _sdio_nand_signature_sector_t +{ + u64 signature; // HAXXDUMP + stdio_nand_desc_t nand_descriptions[3]; +} __attribute__((packed)) sdio_nand_signature_sector_t; + + +typedef void (*read_write_callback_t)(int, int); + +int getPhysicalDeviceHandle(u32 device); + +int slcRead1_original(void *physical_device_info, u32 offset_high, u32 offset_low, u32 cnt, u32 block_size, void *data_outptr, read_write_callback_t callback, int callback_parameter); +int sdcardRead_original(void *physical_device_info, u32 offset_high, u32 offset_low, u32 cnt, u32 block_size, void *data_outptr, read_write_callback_t callback, int callback_parameter); + +#endif // DEVICES_H_ diff --git a/ios_fs/source/dumper.c b/ios_fs/source/dumper.c new file mode 100644 index 0000000..65820ce --- /dev/null +++ b/ios_fs/source/dumper.c @@ -0,0 +1,321 @@ +#include +#include "types.h" +#include "imports.h" +#include "devices.h" +#include "sdio.h" +#include "mlcio.h" +#include "fat32_format.h" +#include "text.h" +#include "hardware_registers.h" +#include "svc.h" + +// the IO buffer is put behind everything else because there is no access to this region from IOS-FS it seems +unsigned char io_buffer[0x40000] __attribute__((aligned(0x40))) __attribute__((section(".io_buffer"))); + +//! this one is required for the read function +static void slc_read_callback(int result, int priv) +{ + int *private_data = (int*)priv; + private_data[1] = result; + FS_SVC_RELEASEMUTEX(private_data[0]); +} + +static int srcRead(void* deviceHandle, void *data_ptr, u32 offset, u32 sectors, int * result_array) +{ + int readResult = slcRead1_original(deviceHandle, 0, offset, sectors, SLC_BYTES_PER_SECTOR, data_ptr, slc_read_callback, (int)result_array); + if(readResult == 0) + { + // wait for process to finish + FS_SVC_ACQUIREMUTEX(result_array[0], 0); + readResult = result_array[1]; + } + return readResult; +} + +void slc_dump(void *deviceHandle, const char* device, u32 base_sectors, int y_offset) +{ + //also create a mutex for synchronization with end of operation... + int sync_mutex = FS_SVC_CREATEMUTEX(1, 1); + FS_SVC_ACQUIREMUTEX(sync_mutex, 0); + + int result_array[2]; + result_array[0] = sync_mutex; + + u32 offset = 0; + int readResult = 0; + int writeResult = 0; + int retry = 0; + u32 readSize = sizeof(io_buffer) / SLC_BYTES_PER_SECTOR; + + FS_SLEEP(1000); + + do + { + // don't print single steps in between, just if they have an error or every 0x80 sectors + if((readSize == (sizeof(io_buffer) / SLC_BYTES_PER_SECTOR)) || (retry > 0)) + { + _printf(20, y_offset, "%s = %08X / 40000, read code %08X, write code %08X, retry %d", device, offset, readResult, writeResult, retry); + } + + //! set flash erased byte to buffer + FS_MEMSET(io_buffer, 0xff, sizeof(io_buffer)); + //readResult = readSlc(io_buffer, offset, (sizeof(io_buffer) / SLC_BYTES_PER_SECTOR), deviceHandle); + readResult = srcRead(deviceHandle, io_buffer, offset, readSize, result_array); + + //! retry 2 times as there are read failures in several places + if((readResult != 0) && (retry < 2)) + { + readSize = 1; + FS_SLEEP(10); + retry++; + } + else + { + retry = 0; + + while(1) + { + FS_SLEEP(10); + + writeResult = sdcard_readwrite(SDIO_WRITE, io_buffer, (readSize * (SLC_BYTES_PER_SECTOR / SDIO_BYTES_PER_SECTOR)), SDIO_BYTES_PER_SECTOR, base_sectors, NULL, DEVICE_ID_SDCARD_PATCHED); + if((writeResult == 0) || (retry >= 2)) + { + retry = 0; + base_sectors += (readSize * (SLC_BYTES_PER_SECTOR / SDIO_BYTES_PER_SECTOR)); + offset += readSize; + + // if we did single sector reads and got to a point where we can do multiple reads -> switch to multiple sector reads + if((offset % (sizeof(io_buffer) / SLC_BYTES_PER_SECTOR)) == 0) + { + readSize = sizeof(io_buffer) / SLC_BYTES_PER_SECTOR; + } + break; + } + else + { + retry++; + } + } + } + } + while (offset < SLC_SECTOR_COUNT); + + FS_SVC_DESTROYMUTEX(sync_mutex); + + // last print to show "done" + _printf(20, y_offset, "%s = %08X / 40000, read code %08X, write code %08X, retry %d", device, offset, readResult, writeResult, retry); +} + +void mlc_dump(u32 base_sector, u32 mlc_end) +{ + u32 offset = 0; + + int retry = 0; + int mlc_result = 0; + int callback_result = 0; + int write_result = 0; + int print_counter = 0; + + do + { + //! print only every 4th time + if(print_counter == 0) + { + print_counter = 4; + _printf(20, 70, "mlc = %08X / %08X, mlc res %08X, sd res %08X, retry %d", offset, mlc_end, mlc_result, write_result, retry); + } + else + { + --print_counter; + } + + //! set flash erased byte to buffer + FS_MEMSET(io_buffer, 0xff, sizeof(io_buffer)); + mlc_result = sdcard_readwrite(SDIO_READ, io_buffer, (sizeof(io_buffer) / MLC_BYTES_PER_SECTOR), MLC_BYTES_PER_SECTOR, offset, &callback_result, DEVICE_ID_MLC); + + if((mlc_result == 0) && (callback_result != 0)) + { + mlc_result = callback_result; + } + + //! retry 5 times as there are read failures in several places + if((mlc_result != 0) && (retry < 5)) + { + FS_SLEEP(100); + retry++; + print_counter = 0; // print errors directly + } + else + { + write_result = sdcard_readwrite(SDIO_WRITE, io_buffer, (sizeof(io_buffer) / MLC_BYTES_PER_SECTOR), SDIO_BYTES_PER_SECTOR, base_sector + offset, NULL, DEVICE_ID_SDCARD_PATCHED); + if((write_result == 0) || (retry >= 5)) + { + retry = 0; + offset += (sizeof(io_buffer) / MLC_BYTES_PER_SECTOR); + } + else + { + FS_SLEEP(100); + retry++; + print_counter = 0; // print errors directly + } + } + } + while(offset < mlc_end); //! TODO: make define MLC32_SECTOR_COUNT + + // last print to show "done" + _printf(20, 70, "mlc = %08X / %08X, mlc res %08X, sd res %08X, retry %d", offset, mlc_end, mlc_result, write_result, retry); +} + +int check_nand_type(void) +{ + //! check if MLC size is > 8GB + if( FS_MMC_MLC_STRUCT[0x30/4] > 0x1000000) + { + return MLC_NAND_TYPE_32GB; + } + else + { + return MLC_NAND_TYPE_8GB; + } +} + +int check_nand_dump(void) +{ + u32 mlc_sector_count = FS_MMC_MLC_STRUCT[0x30/4]; + + int signature_correct = 0; + sdio_nand_signature_sector_t * sign_sect = (sdio_nand_signature_sector_t*)io_buffer; + memset(sign_sect, 0, SDIO_BYTES_PER_SECTOR); + sdcard_readwrite(SDIO_READ, sign_sect, 1, SDIO_BYTES_PER_SECTOR, NAND_DUMP_SIGNATURE_SECTOR, NULL, DEVICE_ID_SDCARD_PATCHED); + + signature_correct = (sign_sect->signature == NAND_DUMP_SIGNATURE); + + memset(io_buffer, 0, SDIO_BYTES_PER_SECTOR); + sdcard_readwrite(SDIO_READ, io_buffer, 1, SDIO_BYTES_PER_SECTOR, 0, NULL, DEVICE_ID_SDCARD_PATCHED); + + return signature_correct && CheckFAT32PartitionOffset(io_buffer, MLC_BASE_SECTORS + mlc_sector_count); +} + +static void wait_format_confirmation(void) +{ + int timeout = 600; + //"Press the POWER button SD then , else the console will reboot in %u seconds." + while(1) + { + _printf(20, 30, "No NAND dump detected. SD Format and complete NAND dump required."); + _printf(20, 40, "Press the POWER button to format SD card otherwise the console will reboot in %d seconds.", timeout/10); + + if(svcRead32(LT_GPIO_IN) & GPIO_IN_POWER_BUTTON) + { + break; + } + + if(--timeout == 0) + { + FS_SLEEP(1000); + svcShutdown(SHUTDOWN_TYPE_REBOOT); + } + + FS_SLEEP(100); + } + + // clear the lines + clearLine(30, 0x000000FF); + clearLine(40, 0x000000FF); +} + +void dump_nand_complete() +{ + wait_format_confirmation(); + + mlc_init(); + FS_SLEEP(1000); + + int nand_type = check_nand_type(); + u32 sdio_sector_count = FS_MMC_SDCARD_STRUCT[0x30/4]; + u32 mlc_sector_count = FS_MMC_MLC_STRUCT[0x30/4]; + u32 fat32_partition_offset = (MLC_BASE_SECTORS + mlc_sector_count); + + _printf(20, 30, "Detected %d GB MLC NAND type.", (nand_type == MLC_NAND_TYPE_8GB) ? 8 : 32); + + if(sdio_sector_count < fat32_partition_offset) + { + _printf(20, 40, "SD card too small! Required sectors %u > available %u.", fat32_partition_offset, sdio_sector_count); + FS_SLEEP(3000); + svcShutdown(SHUTDOWN_TYPE_REBOOT); + } + + if( FormatSDCard(fat32_partition_offset, sdio_sector_count) < 0 ) + { + FS_SLEEP(3000); + svcShutdown(SHUTDOWN_TYPE_REBOOT); + } + + slc_dump(FS_SLC_PHYS_DEV_STRUCT, "slc ", SLC_BASE_SECTORS, 50); + slc_dump(FS_SLCCMPT_PHYS_DEV_STRUCT, "slccmpt", SLCCMPT_BASE_SECTORS, 60); + mlc_dump(MLC_BASE_SECTORS, mlc_sector_count); + + //! write marker to SD card from which we can auto detect NAND dump + //! we can actually use that for settings + sdio_nand_signature_sector_t * sign_sect = (sdio_nand_signature_sector_t*)io_buffer; + memset(sign_sect, 0, SDIO_BYTES_PER_SECTOR); + sign_sect->signature = NAND_DUMP_SIGNATURE; + sign_sect->nand_descriptions[0].nand_type = NAND_DESC_TYPE_SLC; + sign_sect->nand_descriptions[0].base_sector = SLC_BASE_SECTORS; + sign_sect->nand_descriptions[0].sector_count = SLC_SECTOR_COUNT * (SLC_BYTES_PER_SECTOR / SDIO_BYTES_PER_SECTOR); + sign_sect->nand_descriptions[1].nand_type = NAND_DESC_TYPE_SLCCMPT; + sign_sect->nand_descriptions[1].base_sector = SLCCMPT_BASE_SECTORS; + sign_sect->nand_descriptions[1].sector_count = SLC_SECTOR_COUNT * (SLC_BYTES_PER_SECTOR / SDIO_BYTES_PER_SECTOR); + sign_sect->nand_descriptions[2].nand_type = NAND_DESC_TYPE_MLC; + sign_sect->nand_descriptions[2].base_sector = MLC_BASE_SECTORS; + sign_sect->nand_descriptions[2].sector_count = mlc_sector_count * (MLC_BYTES_PER_SECTOR / SDIO_BYTES_PER_SECTOR); + + sdcard_readwrite(SDIO_WRITE, io_buffer, 1, SDIO_BYTES_PER_SECTOR, NAND_DUMP_SIGNATURE_SECTOR, NULL, DEVICE_ID_SDCARD_PATCHED); + + _printf(20, 80, "Complete! -> rebooting into sysNAND..."); + + FS_SLEEP(3000); + svcShutdown(SHUTDOWN_TYPE_REBOOT); +} + +#if 0 +// debug and not used at the moment +void dump_data(void* data_ptr, u32 size) +{ + static u32 dumpdata_offset = 0; + + u32 num_sectors = size >> 9; // size / SDIO_BYTES_PER_SECTOR but faster ;) + if (num_sectors == 0) + num_sectors = 1; + + sdcard_readwrite(SDIO_WRITE, data_ptr, num_sectors, SDIO_BYTES_PER_SECTOR, DUMPDATA_BASE_SECTORS + dumpdata_offset, NULL, DEVICE_ID_SDCARD_PATCHED); + dumpdata_offset += num_sectors; +} + +void dump_lots_data(u8* addr, u32 size) +{ + u32 cur_size; + u32 size_remaining = size; + u8* cur_addr = addr; + do + { + cur_size = sizeof(io_buffer); + if (cur_size > size_remaining) + cur_size = size_remaining; + + FS_MEMCPY(io_buffer, cur_addr, cur_size); + dump_data(io_buffer, cur_size); + + cur_addr += cur_size; + size_remaining -= cur_size; + } + while (cur_size != 0); +} + +void dump_syslog() +{ + FS_MEMCPY(io_buffer, *(void**)0x05095ECC, sizeof(io_buffer)); + sdcard_readwrite(SDIO_WRITE, io_buffer, sizeof(io_buffer) / SDIO_BYTES_PER_SECTOR, SDIO_BYTES_PER_SECTOR, SYSLOG_BASE_SECTORS, NULL, DEVICE_ID_SDCARD_PATCHED); +} +#endif diff --git a/ios_fs/source/dumper.h b/ios_fs/source/dumper.h new file mode 100644 index 0000000..6bd80ff --- /dev/null +++ b/ios_fs/source/dumper.h @@ -0,0 +1,15 @@ +#ifndef _DUMPER_H_ +#define _DUMPER_H_ + +//! debug dumps +void dump_syslog(); +void dump_data(void* data_ptr, u32 size); +void dump_lots_data(u8* addr, u32 size); + +int check_nand_type(void); +int check_nand_dump(void); +void slc_dump(int deviceId, const char* format, u32 base_sectors); +void mlc_dump(u32 base_sector, u32 mlc_end); +void dump_nand_complete(); + +#endif // _DUMPER_H_ diff --git a/ios_fs/source/fat32_format.c b/ios_fs/source/fat32_format.c new file mode 100644 index 0000000..b78ff31 --- /dev/null +++ b/ios_fs/source/fat32_format.c @@ -0,0 +1,326 @@ +#include +#include "types.h" +#include "imports.h" +#include "devices.h" +#include "sdio.h" +#include "text.h" + +extern unsigned char io_buffer[0x40000]; + +#define PARTITION_TYPE_FAT32 0x0c +#define MAX_PARTITIONS 32 /* Maximum number of partitions that can be found */ +#define MAX_MOUNTS 10 /* Maximum number of mounts available at one time */ +#define MAX_SYMLINK_DEPTH 10 /* Maximum search depth when resolving symbolic links */ + +#define MBR_SIGNATURE 0x55AA +#define EBR_SIGNATURE MBR_SIGNATURE + +#define PARTITION_BOOTABLE 0x80 /* Bootable (active) */ +#define PARTITION_NONBOOTABLE 0x00 /* Non-bootable */ +#define PARTITION_TYPE_GPT 0xEE /* Indicates that a GPT header is available */ + +typedef struct _PARTITION_RECORD { + u8 status; /* Partition status; see above */ + u8 chs_start[3]; /* Cylinder-head-sector address to first block of partition */ + u8 type; /* Partition type; see above */ + u8 chs_end[3]; /* Cylinder-head-sector address to last block of partition */ + u32 lba_start; /* Local block address to first sector of partition */ + u32 block_count; /* Number of blocks in partition */ +} __attribute__((__packed__)) PARTITION_RECORD; + + +typedef struct _MASTER_BOOT_RECORD { + u8 code_area[446]; /* Code area; normally empty */ + PARTITION_RECORD partitions[4]; /* 4 primary partitions */ + u16 signature; /* MBR signature; 0xAA55 */ +} __attribute__((__packed__)) MASTER_BOOT_RECORD; + +typedef struct tagFAT_BOOTSECTOR32 +{ + // Common fields. + u8 sJmpBoot[3]; + u8 sOEMName[8]; + u16 wBytsPerSec; + u8 bSecPerClus; + u16 wRsvdSecCnt; + u8 bNumFATs; + u16 wRootEntCnt; + u16 wTotSec16; + u8 bMedia; + u16 wFATSz16; + u16 wSecPerTrk; + u16 wNumHeads; + u32 dHiddSec; + u32 dTotSec32; + // Fat 32/16 only + u32 dFATSz32; + u16 wExtFlags; + u16 wFSVer; + u32 dRootClus; + u16 wFSInfo; + u16 wBkBootSec; + u8 Reserved[12]; + u8 bDrvNum; + u8 Reserved1; + u8 bBootSig; // == 0x29 if next three fields are ok + u32 dBS_VolID; + u8 sVolLab[11]; + u8 sBS_FilSysType[8]; + +} __attribute__((__packed__)) FAT_BOOTSECTOR32; + +typedef struct { + u32 dLeadSig; + u8 sReserved1[480]; + u32 dStrucSig; + u32 dFree_Count; + u32 dNxt_Free; + u8 sReserved2[12]; + u32 dTrailSig; +} __attribute__((__packed__)) FAT_FSINFO; + +static inline u8 get_sectors_per_cluster (u64 DiskSizeBytes) +{ + u8 ret = 0x01; // 1 sector per cluster + u32 DiskSizeMB = DiskSizeBytes/(1024*1024); + + // 512 MB to 8,191 MB 4 KB + if (DiskSizeMB > 512) + ret = 0x8; + + // 8,192 MB to 16,383 MB 8 KB + if (DiskSizeMB > 8192) + ret = 0x10; + + // 16,384 MB to 32,767 MB 16 KB + if (DiskSizeMB > 16384) + ret = 0x20; // ret = 0x20; + + // Larger than 32,768 MB 32 KB + if (DiskSizeMB > 32768) + ret = 0x40; // ret = 0x40; + + return ret; +} + +static inline u32 MakeVolumeID() +{ + // we dont have time yet so for now its fixed + //time_t rawtime = time(0); + //struct tm * timeinfo = localtime(&rawtime); + + //u16 hi = le16(timeinfo->tm_mday + (timeinfo->tm_mon << 8) + (timeinfo->tm_sec << 8)); + //u16 lo = le16((timeinfo->tm_hour << 8) + timeinfo->tm_min + timeinfo->tm_year + 1900); + u16 hi = 0x0BAD; + u16 lo = 0xBABE; + + return (lo + (hi << 16)); +} + + +int FormatToFAT32(u32 lba, u32 sec_count) +{ + if(sec_count < 0xFFFF) + { + _printf(20, 40, "Not enough sectors for FAT32"); + return -1; + } + + int BytesPerSect = SDIO_BYTES_PER_SECTOR; + u16 ReservedSectCount = 32; + u8 NumFATs = 2; + + memset(io_buffer, 0, BytesPerSect*18); + + FAT_BOOTSECTOR32 * FAT32BootSect = (FAT_BOOTSECTOR32 *) (io_buffer+16*BytesPerSect); + FAT_FSINFO * FAT32FsInfo = (FAT_FSINFO*) (io_buffer+17*BytesPerSect); + + // fill out the boot sector and fs info + FAT32BootSect->sJmpBoot[0] = 0xEB; + FAT32BootSect->sJmpBoot[1] = 0x5A; + FAT32BootSect->sJmpBoot[2] = 0x90; + memcpy(FAT32BootSect->sOEMName, "MSWIN4.1", 8); + + FAT32BootSect->wBytsPerSec = le16(BytesPerSect); + + u8 SectorsPerCluster = get_sectors_per_cluster((u64) sec_count * (u64) BytesPerSect); + + FAT32BootSect->bSecPerClus = SectorsPerCluster; + FAT32BootSect->wRsvdSecCnt = le16(ReservedSectCount); + FAT32BootSect->bNumFATs = NumFATs; + FAT32BootSect->wRootEntCnt = 0; + FAT32BootSect->wTotSec16 = 0; + FAT32BootSect->bMedia = 0xF8; + FAT32BootSect->wFATSz16 = 0; + FAT32BootSect->wSecPerTrk = le16(63); //SectorsPerTrack; + FAT32BootSect->wNumHeads = le16(255); //TracksPerCylinder; + FAT32BootSect->dHiddSec = le32(lba); //HiddenSectors; + FAT32BootSect->dTotSec32 = le32(sec_count); + + // This is based on + // http://hjem.get2net.dk/rune_moeller_barnkob/filesystems/fat.html + u32 FatSize = (4*(sec_count-ReservedSectCount)/((SectorsPerCluster*BytesPerSect)+(4*NumFATs)))+1; + + FAT32BootSect->dFATSz32 = le32(FatSize); + FAT32BootSect->wExtFlags = 0; + FAT32BootSect->wFSVer = 0; + FAT32BootSect->dRootClus = le32(2); + FAT32BootSect->wFSInfo = le16(1); + FAT32BootSect->wBkBootSec = le16(6); //BackupBootSect + FAT32BootSect->bDrvNum = 0x80; + FAT32BootSect->Reserved1 = 0; + FAT32BootSect->bBootSig = 0x29; + + FAT32BootSect->dBS_VolID = MakeVolumeID(); + memcpy(FAT32BootSect->sVolLab, "NO NAME ", 11); + memcpy(FAT32BootSect->sBS_FilSysType, "FAT32 ", 8); + ((u8 *)FAT32BootSect)[510] = 0x55; //Boot Record Signature + ((u8 *)FAT32BootSect)[511] = 0xAA; //Boot Record Signature + + // FSInfo sect signatures + FAT32FsInfo->dLeadSig = le32(0x41615252); + FAT32FsInfo->dStrucSig = le32(0x61417272); + FAT32FsInfo->dTrailSig = le32(0xaa550000); + ((u8 *)FAT32FsInfo)[510] = 0x55; //Boot Record Signature + ((u8 *)FAT32FsInfo)[511] = 0xAA; //Boot Record Signature + + // First FAT Sector + u32 FirstSectOfFat[3]; + FirstSectOfFat[0] = le32(0x0ffffff8); // Reserved cluster 1 media id in low byte + FirstSectOfFat[1] = le32(0x0fffffff); // Reserved cluster 2 EOC + FirstSectOfFat[2] = le32(0x0fffffff); // end of cluster chain for root dir + + u32 UserAreaSize = sec_count - ReservedSectCount - (NumFATs*FatSize); + u32 ClusterCount = UserAreaSize/SectorsPerCluster; + + if (ClusterCount > 0x0FFFFFFF) + { + _printf(20, 40, "This drive has more than 2^28 clusters. Partition might be too small."); + return -1; + } + + if (ClusterCount < 65536) + { + _printf(20, 40, "FAT32 must have at least 65536 clusters"); + return -1; + } + + u32 FatNeeded = (ClusterCount * 4 + (BytesPerSect-1))/BytesPerSect; + if (FatNeeded > FatSize) + { + _printf(20, 40, "This drive is too big, %u > %u", FatNeeded, FatSize); + return -1; + } + + // fix up the FSInfo sector + FAT32FsInfo->dFree_Count = le32((UserAreaSize/SectorsPerCluster)-1); + FAT32FsInfo->dNxt_Free = le32(3); // clusters 0-1 resered, we used cluster 2 for the root dir + + /** Now all is done and we start writting **/ + + // First zero out ReservedSect + FatSize * NumFats + SectorsPerCluster + u32 SystemAreaSize = (ReservedSectCount+(NumFATs*FatSize) + SectorsPerCluster); + u32 done = 0; + // Read the first sector on the device + while(SystemAreaSize > 0) + { + int write = SystemAreaSize < 16 ? SystemAreaSize : 16; + + int result = sdcard_readwrite(SDIO_WRITE, io_buffer, write, SDIO_BYTES_PER_SECTOR, lba+done, NULL, DEVICE_ID_SDCARD_PATCHED); + if(result != 0) + { + _printf(20, 40, "Cannot write to the drive."); + return -1; + } + SystemAreaSize -= write; + done += write; + } + + for (int i = 0; i < 2; i++) + { + u32 SectorStart = (i == 0) ? lba : lba+6; //BackupBootSect + + int result = sdcard_readwrite(SDIO_WRITE, FAT32BootSect, 1, SDIO_BYTES_PER_SECTOR, SectorStart, NULL, DEVICE_ID_SDCARD_PATCHED); + if(result != 0) + { + _printf(20, 40, "Cannot write to the drive."); + return -1; + } + result = sdcard_readwrite(SDIO_WRITE, FAT32FsInfo, 1, SDIO_BYTES_PER_SECTOR, SectorStart+1, NULL, DEVICE_ID_SDCARD_PATCHED); + if(result != 0) + { + _printf(20, 40, "Cannot write to the drive."); + return -1; + } + } + + memcpy(io_buffer, FirstSectOfFat, sizeof(FirstSectOfFat)); + + // Write the first fat sector in the right places + for (int i = 0; i < NumFATs; i++) + { + u32 SectorStart = lba + ReservedSectCount + (i * FatSize); + + int result = sdcard_readwrite(SDIO_WRITE, io_buffer, 1, SDIO_BYTES_PER_SECTOR, SectorStart, NULL, DEVICE_ID_SDCARD_PATCHED); + if(result != 0) + { + _printf(20, 40, "Cannot write to the drive."); + return -1; + } + } + + return 0; +} + + +int CheckFAT32PartitionOffset(u8 * mbr_buf, u32 partition_offset) +{ + MASTER_BOOT_RECORD *mbr = (MASTER_BOOT_RECORD*)mbr_buf; + return (mbr->signature == MBR_SIGNATURE) && (le32(mbr->partitions[0].lba_start) >= partition_offset); +} + +int FormatSDCard(u32 partition_offset, u32 total_sectors) +{ + _printf(20, 40, "Formatting SD card...."); + + MASTER_BOOT_RECORD *mbr = (MASTER_BOOT_RECORD*)io_buffer; + memset(mbr, 0, SDIO_BYTES_PER_SECTOR); + + int result = sdcard_readwrite(SDIO_READ, mbr, 1, SDIO_BYTES_PER_SECTOR, 0, NULL, DEVICE_ID_SDCARD_PATCHED); + if(result != 0) + { + _printf(20, 40, "SD card read failed %i", result); + return result; + } + + u32 lba_start = partition_offset; + + result = FormatToFAT32(lba_start, total_sectors - partition_offset); + if(result != 0) + return result; + + memset(mbr, 0, sizeof(MASTER_BOOT_RECORD)); + mbr->signature = MBR_SIGNATURE; + + // setup primary FAT32 partition + mbr->partitions[0].status = PARTITION_BOOTABLE; // set activate + mbr->partitions[0].chs_start[0] = mbr->partitions[0].chs_end[0] = 0xFE; + mbr->partitions[0].chs_start[1] = mbr->partitions[0].chs_end[1] = 0xFF; + mbr->partitions[0].chs_start[2] = mbr->partitions[0].chs_end[2] = 0xFF; + mbr->partitions[0].type = PARTITION_TYPE_FAT32; + mbr->partitions[0].lba_start = le32(lba_start); + mbr->partitions[0].block_count = le32((total_sectors - partition_offset)); + + + result = sdcard_readwrite(SDIO_WRITE, mbr, 1, SDIO_BYTES_PER_SECTOR, 0, NULL, DEVICE_ID_SDCARD_PATCHED); + if(result != 0) + { + _printf(20, 40, "SD card write failed %i", result); + } + else + { + _printf(20, 40, "Format of SD card finished successfully", result); + } + + return result; +} diff --git a/ios_fs/source/fat32_format.h b/ios_fs/source/fat32_format.h new file mode 100644 index 0000000..1a008ac --- /dev/null +++ b/ios_fs/source/fat32_format.h @@ -0,0 +1,7 @@ +#ifndef _FAT32_FORMAT_H_ +#define _FAT32_FORMAT_H_ + +int CheckFAT32PartitionOffset(u8 * mbr, u32 partition_offset); +int FormatSDCard(u32 partition_offset, u32 total_sectors); + +#endif // _FAT32_FORMAT_H_ diff --git a/ios_fs/source/font.c b/ios_fs/source/font.c new file mode 100644 index 0000000..91aef28 --- /dev/null +++ b/ios_fs/source/font.c @@ -0,0 +1,49 @@ +const unsigned char font_bin[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x18, 0x18, 0x00, 0x0C, 0x00, + 0x00, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0xFF, 0x66, 0xFF, 0x66, 0x66, + 0x00, 0x18, 0x7C, 0x06, 0x3C, 0x60, 0x3E, 0x18, 0x10, 0x46, 0x66, 0x30, 0x18, 0x0C, 0x66, 0x62, + 0x00, 0x3C, 0x66, 0x3C, 0x1C, 0xE6, 0x66, 0xFC, 0x00, 0x18, 0x0C, 0x06, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x30, 0x18, 0x0C, 0x0C, 0x18, 0x30, 0x00, 0x00, 0x0C, 0x18, 0x30, 0x30, 0x18, 0x0C, 0x00, + 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x40, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x00, + 0x00, 0x3C, 0x66, 0x76, 0x6E, 0x66, 0x3C, 0x00, 0x00, 0x18, 0x1C, 0x18, 0x18, 0x18, 0x7E, 0x00, + 0x00, 0x3C, 0x62, 0x30, 0x0C, 0x06, 0x7E, 0x00, 0x00, 0x3C, 0x62, 0x38, 0x60, 0x66, 0x3C, 0x00, + 0x00, 0x6C, 0x6C, 0x66, 0xFE, 0x60, 0x60, 0x00, 0x00, 0x7E, 0x06, 0x7E, 0x60, 0x66, 0x3C, 0x00, + 0x00, 0x3C, 0x06, 0x3E, 0x66, 0x66, 0x3C, 0x00, 0x00, 0x7E, 0x30, 0x30, 0x18, 0x18, 0x18, 0x00, + 0x00, 0x3C, 0x66, 0x3C, 0x66, 0x66, 0x3C, 0x00, 0x00, 0x3C, 0x66, 0x7C, 0x60, 0x66, 0x3C, 0x00, + 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x18, 0x18, 0x0C, 0x00, + 0x00, 0x70, 0x1C, 0x06, 0x06, 0x1C, 0x70, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x3E, 0x00, 0x00, 0x00, + 0x00, 0x0E, 0x38, 0x60, 0x60, 0x38, 0x0E, 0x00, 0x00, 0x3C, 0x66, 0x30, 0x18, 0x00, 0x18, 0x00, + 0x00, 0x3C, 0x66, 0x76, 0x76, 0x06, 0x46, 0x3C, 0x00, 0x3C, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00, + 0x00, 0x3E, 0x66, 0x3E, 0x66, 0x66, 0x3E, 0x00, 0x00, 0x3C, 0x66, 0x06, 0x06, 0x66, 0x3C, 0x00, + 0x00, 0x1E, 0x36, 0x66, 0x66, 0x36, 0x1E, 0x00, 0x00, 0x7E, 0x06, 0x1E, 0x06, 0x06, 0x7E, 0x00, + 0x00, 0x3E, 0x06, 0x1E, 0x06, 0x06, 0x06, 0x00, 0x00, 0x3C, 0x66, 0x06, 0x76, 0x66, 0x3C, 0x00, + 0x00, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00, 0x00, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, + 0x00, 0x78, 0x30, 0x30, 0x30, 0x36, 0x1C, 0x00, 0x00, 0x66, 0x36, 0x1E, 0x1E, 0x36, 0x66, 0x00, + 0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x7E, 0x00, 0x00, 0x46, 0x6E, 0x7E, 0x56, 0x46, 0x46, 0x00, + 0x00, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x66, 0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00, + 0x00, 0x3E, 0x66, 0x3E, 0x06, 0x06, 0x06, 0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x70, 0x00, + 0x00, 0x3E, 0x66, 0x3E, 0x1E, 0x36, 0x66, 0x00, 0x00, 0x3C, 0x66, 0x0C, 0x30, 0x66, 0x3C, 0x00, + 0x00, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00, + 0x00, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00, 0x00, 0x46, 0x46, 0x56, 0x7E, 0x6E, 0x46, 0x00, + 0x00, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x66, 0x00, 0x00, 0x66, 0x66, 0x3C, 0x18, 0x18, 0x18, 0x00, + 0x00, 0x7E, 0x30, 0x18, 0x0C, 0x06, 0x7E, 0x00, 0x00, 0x3C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x3C, + 0x00, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x40, 0x00, 0x00, 0x3C, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3C, + 0x00, 0x18, 0x3C, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, + 0x00, 0x0C, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x60, 0x7C, 0x66, 0x7C, 0x00, + 0x00, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x3E, 0x00, 0x00, 0x00, 0x3C, 0x06, 0x06, 0x06, 0x3C, 0x00, + 0x00, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00, 0x00, 0x00, 0x3C, 0x66, 0x7E, 0x06, 0x3C, 0x00, + 0x00, 0x38, 0x0C, 0x3E, 0x0C, 0x0C, 0x0C, 0x00, 0x00, 0x00, 0x7C, 0x66, 0x7C, 0x40, 0x3C, 0x00, + 0x00, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x66, 0x00, 0x00, 0x18, 0x00, 0x1C, 0x18, 0x18, 0x3C, 0x00, + 0x00, 0x30, 0x00, 0x30, 0x30, 0x30, 0x1E, 0x00, 0x00, 0x06, 0x06, 0x36, 0x1E, 0x36, 0x66, 0x00, + 0x00, 0x1C, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x66, 0xFE, 0xFE, 0xD6, 0xC6, 0x00, + 0x00, 0x00, 0x3E, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00, + 0x00, 0x00, 0x3E, 0x66, 0x66, 0x3E, 0x06, 0x00, 0x00, 0x00, 0x7C, 0x66, 0x66, 0x7C, 0x60, 0x00, + 0x00, 0x00, 0x3E, 0x66, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x7C, 0x06, 0x3C, 0x60, 0x3E, 0x00, + 0x00, 0x18, 0x7E, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x00, + 0x00, 0x00, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00, 0x00, 0x00, 0xC6, 0xD6, 0xFE, 0x7C, 0x6C, 0x00, + 0x00, 0x00, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x00, 0x00, 0x00, 0x66, 0x66, 0x7C, 0x60, 0x3C, 0x00, + 0x00, 0x00, 0x7E, 0x30, 0x18, 0x0C, 0x7E, 0x00, 0x00, 0x00, 0x18, 0x08, 0x08, 0x04, 0x08, 0x08, + 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x0C, 0x08, 0x08, 0x10, 0x08, 0x08, +}; diff --git a/ios_fs/source/font_bin.h b/ios_fs/source/font_bin.h new file mode 100644 index 0000000..949de6c --- /dev/null +++ b/ios_fs/source/font_bin.h @@ -0,0 +1 @@ +extern const u8 font_bin[]; \ No newline at end of file diff --git a/ios_fs/source/function_hooks.s b/ios_fs/source/function_hooks.s new file mode 100644 index 0000000..db64a94 --- /dev/null +++ b/ios_fs/source/function_hooks.s @@ -0,0 +1,92 @@ + +############################################################################################# +# FS main thread hook +############################################################################################# +.extern createDevThread_entry + .globl createDevThread_hook +createDevThread_hook: + push {r0,lr} + ldr r0, [r4, #0x8] + bl createDevThread_entry + pop {r0,lr} +# restore original instruction + pop {r4-r8,pc} + +############################################################################################# +# devices handle hooks +############################################################################################# +.extern getMdDeviceById + .globl getMdDeviceById_hook +getMdDeviceById_hook: + mov r4, r0 + push {lr} + bl getMdDeviceById + pop {lr} + cmp r0, #0 + moveq r0, r4 + bxeq lr + pop {r4,r5,pc} + + +############################################################################################# +# syslog hook +############################################################################################# + .globl syslogOutput_hook +syslogOutput_hook: +# push {r0,lr} +# bl dump_syslog +# pop {r0,lr} +# restore original instruction + pop {r4-r8,r10,pc} + +############################################################################################# +# Original NAND read functions +############################################################################################# + .globl slcRead1_original +slcRead1_original: + push {r4-r8,lr} + ldr r4, [pc] + bx r4 + .word 0x107B9990 + + .globl sdcardRead_original +sdcardRead_original: + push {r4,lr} + ldr r4, [pc] + bx r4 + .word 0x107BDDD4 + +############################################################################################# +# DEBUG STUFF +############################################################################################# +# # # # # # # # # # +# DEBUG STUFF # +# # # # # # # # # # +#mlcRead1_dbg: +# mlcRead1_dbg_stackframe equ (4*6) +# mov r12, r0 +# push {r0-r3,r12,lr} +# adr r0, mlcRead1_dbg_format +# ldr r1, [sp, #mlcRead1_dbg_stackframe+9*4] +# bl FS_SYSLOG_OUTPUT +# pop {r0-r3,lr,pc} # replaces mov lr, r0 +# mlcRead1_dbg_format: +# .ascii "mlcRead1 : %08X %08X %08X" +# .byte 0x0a +# .byte 0x00 +# .align 0x4 +# +#mlcRead1_end_hook: +# mlcRead1_end_hook_stackframe equ (4*10) +# push {r0} +# mov r0, #50 +# bl FS_SLEEP +# ldr r0, =sdcard_read_buffer +# ldr r1, [sp, #mlcRead1_end_hook_stackframe+4*1] +# mov r2, #0x200 +# bl FS_MEMCPY +# ldr r0, =sdcard_read_buffer +# str r6, [r0] +# mov r1, #0x200 +# bl dump_data +# pop {r0,r4-r11,pc} diff --git a/ios_fs/source/hardware_registers.h b/ios_fs/source/hardware_registers.h new file mode 100644 index 0000000..95950c4 --- /dev/null +++ b/ios_fs/source/hardware_registers.h @@ -0,0 +1,9 @@ +#ifndef HARDWARE_REGISTERS_H_ +#define HARDWARE_REGISTERS_H_ + +#define LT_GPIO_IN 0x0d8000e8 + + +#define GPIO_IN_POWER_BUTTON 0x01 + +#endif // HARDWARE_REGISTERS_H_ diff --git a/ios_fs/source/imports.h b/ios_fs/source/imports.h new file mode 100644 index 0000000..03023a7 --- /dev/null +++ b/ios_fs/source/imports.h @@ -0,0 +1,36 @@ +#ifndef IMPORTS_H_ +#define IMPORTS_H_ + +#define FS_IOS_SHUTDOWN ((void (*)(int))0x107F6C94) + +#define FS_SVC_CREATEMUTEX ((int (*)(int, int))0x107F6BBC) +#define FS_SVC_ACQUIREMUTEX ((int (*)(int, int))0x107F6BC4) +#define FS_SVC_RELEASEMUTEX ((int (*)(int))0x107F6BCC) +#define FS_SVC_DESTROYMUTEX ((int (*)(int))0x107F6BD4) + +#define FS_SLEEP ((void (*)(int))0x1071D668) +#define FS_MEMCPY ((void* (*)(void*, const void*, u32))0x107F4F7C) +#define FS_MEMSET ((void* (*)(void*, int, u32))0x107F5018) +#define FS_VSNPRINTF ((int (*)(char * s, size_t n, const char * format, va_list arg))0x107F5F68) +#define FS_SNPRINTF ((int (*)(char * s, size_t n, const char * format, ...))0x107F5FB4) + +#define FS_RAW_READ1 ((int (*)(int handle, u32 offset_high, u32 offset_low, u32 size, void* buf, void *callback, int callback_arg))0x10732BC0) +#define FS_SDIO_DOREADWRITECOMMAND ((int (*)(int, void*, u32, void*, void*))0x10718A8C) + +#define FS_REGISTERMDPHYSICALDEVICE ((int (*)(void*, int, int))0x10718860) + +#define memcpy FS_MEMCPY +#define memset FS_MEMSET + +#define FS_MMC_SDCARD_STRUCT ((vu32*)0x1089B9F8) +#define FS_MMC_MLC_STRUCT ((vu32*)0x1089B948) + +#define FS_MLC_PHYS_DEV_STRUCT ((void*)0x11C3A14C) +#define FS_SLC_PHYS_DEV_STRUCT ((void*)0x11C381CC) +#define FS_SLCCMPT_PHYS_DEV_STRUCT ((void*)0x11C37668) + +#define le16(i) ((((u16) ((i) & 0xFF)) << 8) | ((u16) (((i) & 0xFF00) >> 8))) +#define le32(i) ((((u32)le16((i) & 0xFFFF)) << 16) | ((u32)le16(((i) & 0xFFFF0000) >> 16))) +#define le64(i) ((((u64)le32((i) & 0xFFFFFFFFLL)) << 32) | ((u64)le32(((i) & 0xFFFFFFFF00000000LL) >> 32))) + +#endif // IMPORTS_H_ diff --git a/ios_fs/source/main.c b/ios_fs/source/main.c new file mode 100644 index 0000000..ef4a3d0 --- /dev/null +++ b/ios_fs/source/main.c @@ -0,0 +1,34 @@ +#include "text.h" +#include "sdio.h" +#include "dumper.h" +#include "imports.h" + +#define INITIALIZING_FLA 0x07 +#define INITIALIZING_MMC 0x0D + + +int getPhysicalDeviceHandle(u32 device); + +void createDevThread_entry(int initialization_type) +{ + if(initialization_type == INITIALIZING_MMC) + { + sdcard_init(); + } + + //if(initialization_type == INITIALIZING_FLA) + //{ + //dump_nand_complete(); + //} + + if(initialization_type == 0x01) // unknown but after SLC init no read/write done at this point yet + { + if(check_nand_dump() == 0) + { + clearScreen(0x000000FF); + _printf(20, 20, "welcome to redNAND!"); + + dump_nand_complete(); + } + } +} diff --git a/ios_fs/source/mlcio.c b/ios_fs/source/mlcio.c new file mode 100644 index 0000000..dc1b0b3 --- /dev/null +++ b/ios_fs/source/mlcio.c @@ -0,0 +1,11 @@ +#include "types.h" +#include "imports.h" + +void mlc_init(void) +{ + FS_MMC_MLC_STRUCT[0x24/4] = FS_MMC_MLC_STRUCT[0x24/4] | 0x20; + FS_MMC_MLC_STRUCT[0x28/4] = FS_MMC_MLC_STRUCT[0x28/4] & (~0x04); +} + + + diff --git a/ios_fs/source/mlcio.h b/ios_fs/source/mlcio.h new file mode 100644 index 0000000..e9edd3f --- /dev/null +++ b/ios_fs/source/mlcio.h @@ -0,0 +1,6 @@ +#ifndef _MLCIO_H_ +#define _MLCIO_H_ + +void mlc_init(void); + +#endif // _MLCIO_H_ diff --git a/ios_fs/source/sdio.c b/ios_fs/source/sdio.c new file mode 100644 index 0000000..a841598 --- /dev/null +++ b/ios_fs/source/sdio.c @@ -0,0 +1,107 @@ +#include "types.h" +#include "imports.h" + +static int sdcard_access_mutex = 0; +static u32 dumpdata_offset = 0; + +typedef struct _sd_command_block_t +{ + u32 cnt; + u32 block_size; + u32 command_type; + void * data_ptr; + u64 offset; + void *callback; + void *callback_arg; + int minus_one; +} __attribute__((packed)) sd_command_block_t; + +void sdcard_init(void) +{ + // this should run *after* /dev/mmc thread is created + // first we create our synchronization stuff + sdcard_access_mutex = FS_SVC_CREATEMUTEX(1, 1); + + dumpdata_offset = 0; + + // then we sleep until /dev/mmc is done initializing sdcard (TODO : better synchronization here) + FS_SLEEP(1000); + + // finally we set some flags to indicate sdcard is ready for use + FS_MMC_SDCARD_STRUCT[0x24/4] = FS_MMC_SDCARD_STRUCT[0x24/4] | 0x20; + FS_MMC_SDCARD_STRUCT[0x28/4] = FS_MMC_SDCARD_STRUCT[0x28/4] & (~0x04); +} + +static void sdcard_readwrite_callback(void *priv_data, int result) +{ + int *private_data = (int*)priv_data; + + private_data[1] = result; + + FS_SVC_RELEASEMUTEX(private_data[0]); +} + +void sdcard_lock_mutex(void) +{ + FS_SVC_ACQUIREMUTEX(sdcard_access_mutex, 0); +} + +void sdcard_unlock_mutex(void) +{ + FS_SVC_RELEASEMUTEX(sdcard_access_mutex); +} + +int sdcard_readwrite(int is_read, void *data, u32 cnt, u32 block_size, u32 offset_blocks, int * out_callback_arg, int device_id) +{ + // first of all, grab sdcard mutex + sdcard_lock_mutex(); + + //also create a mutex for synchronization with end of operation... + int sync_mutex = FS_SVC_CREATEMUTEX(1, 1); + + // ...and acquire it + FS_SVC_ACQUIREMUTEX(sync_mutex, 0); + + // block_size needs to be equal to sector_size (0x200) + while(block_size > 0x200) + { + block_size >>= 1; + cnt <<= 1; + offset_blocks <<= 1; + } + + // build rw command paramstruct + sd_command_block_t command; + command.cnt = cnt; + command.block_size = block_size; + command.command_type = (is_read ? 0x03 : 0x00); + command.data_ptr = data; + command.offset = offset_blocks; + command.callback = 0x00; + command.callback_arg = 0x00; + command.minus_one = (u32)-1; + + // setup parameters + int private_data[2]; + private_data[0] = sync_mutex; + private_data[1] = 0; + + // call readwrite function + int result = FS_SDIO_DOREADWRITECOMMAND(device_id, &command, offset_blocks, sdcard_readwrite_callback, (void*)private_data); + if(result == 0) + { + // wait for callback to give the go-ahead + FS_SVC_ACQUIREMUTEX(sync_mutex, 0); + + if(out_callback_arg) + { + *out_callback_arg = private_data[1]; + } + } + + // finally, release sdcard mutexes + FS_SVC_DESTROYMUTEX(sync_mutex); + sdcard_unlock_mutex(); + + return result; +} diff --git a/ios_fs/source/sdio.h b/ios_fs/source/sdio.h new file mode 100644 index 0000000..ce7686b --- /dev/null +++ b/ios_fs/source/sdio.h @@ -0,0 +1,12 @@ +#ifndef _SDIO_H_ +#define _SDIO_H_ + +#define SDIO_WRITE 0 +#define SDIO_READ 1 + +void sdcard_init(void); +void sdcard_lock_mutex(void); +void sdcard_unlock_mutex(void); +int sdcard_readwrite(int is_read, void *data, u32 cnt, u32 block_size, u32 offset_blocks, int * out_callback_arg, int device_id); + +#endif // _SDIO_H_ diff --git a/ios_fs/source/svc.h b/ios_fs/source/svc.h new file mode 100644 index 0000000..ce959a0 --- /dev/null +++ b/ios_fs/source/svc.h @@ -0,0 +1,29 @@ +#ifndef SVC_H +#define SVC_H + +#include "types.h" + +#define SHUTDOWN_TYPE_POWER_OFF 0 +#define SHUTDOWN_TYPE_REBOOT 1 + +typedef struct +{ + void* ptr; + u32 len; + u32 unk; +}iovec_s; + +void* svcAlloc(u32 heapid, u32 size); +void* svcAllocAlign(u32 heapid, u32 size, u32 align); +void svcFree(u32 heapid, void* ptr); +int svcOpen(char* name, int mode); +int svcClose(int fd); +int svcIoctl(int fd, u32 request, void* input_buffer, u32 input_buffer_len, void* output_buffer, u32 output_buffer_len); +int svcIoctlv(int fd, u32 request, u32 vector_count_in, u32 vector_count_out, iovec_s* vector); +int svcInvalidateDCache(void* address, u32 size); +int svcFlushDCache(void* address, u32 size); + +void svcShutdown(int shutdown_type); +u32 svcRead32(u32 addr); + +#endif diff --git a/ios_fs/source/svc.s b/ios_fs/source/svc.s new file mode 100644 index 0000000..638ff3c --- /dev/null +++ b/ios_fs/source/svc.s @@ -0,0 +1,68 @@ +.arm +.align 4 + +.global svcAlloc +.type svcAlloc, %function +svcAlloc: + .word 0xE7F027F0 + bx lr + +.global svcAllocAlign +.type svcAllocAlign, %function +svcAllocAlign: + .word 0xE7F028F0 + bx lr + +.global svcFree +.type svcFree, %function +svcFree: + .word 0xE7F029F0 + bx lr + +.global svcOpen +.type svcOpen, %function +svcOpen: + .word 0xE7F033F0 + bx lr + +.global svcClose +.type svcClose, %function +svcClose: + .word 0xE7F034F0 + bx lr + +.global svcIoctl +.type svcIoctl, %function +svcIoctl: + .word 0xE7F038F0 + bx lr + +.global svcIoctlv +.type svcIoctlv, %function +svcIoctlv: + .word 0xE7F039F0 + bx lr + +.global svcInvalidateDCache +.type svcInvalidateDCache, %function +svcInvalidateDCache: + .word 0xE7F051F0 + bx lr + +.global svcFlushDCache +.type svcFlushDCache, %function +svcFlushDCache: + .word 0xE7F052F0 + bx lr + +.global svcShutdown +.type svcShutdown, %function +svcShutdown: + .word 0xE7F072F0 + bx lr + +.global svcRead32 +.type svcRead32, %function +svcRead32: + .word 0xE7F081F0 + bx lr diff --git a/ios_fs/source/text.c b/ios_fs/source/text.c new file mode 100644 index 0000000..dd0c4a1 --- /dev/null +++ b/ios_fs/source/text.c @@ -0,0 +1,90 @@ +#include +#include +#include +#include +#include "imports.h" +#include "types.h" +#include "font_bin.h" + +#define FRAMEBUFFER_ADDRESS (0x14000000+0x38C0000) +#define FRAMEBUFFER_STRIDE (0xE00) +#define FRAMEBUFFER_STRIDE_WORDS (FRAMEBUFFER_STRIDE >> 2) + +#define CHAR_SIZE_X (8) +#define CHAR_SIZE_Y (8) + +u32* const framebuffer = (u32*)FRAMEBUFFER_ADDRESS; + +void clearScreen(u32 color) +{ + int i; + for(i = 0; i < ((FRAMEBUFFER_STRIDE * 504)/4); i++) + { + framebuffer[i] = color; + } +} + +void clearLine(int y, u32 color) +{ + u32* fb = &framebuffer[y * FRAMEBUFFER_STRIDE_WORDS]; + u32* fb_end = &framebuffer[(y+CHAR_SIZE_Y) * FRAMEBUFFER_STRIDE_WORDS]; + + while(fb < fb_end) + { + *fb = color; + fb++; + } +} + +void drawCharacter(char c, int x, int y) +{ + if(c < 32)return; + c -= 32; + u8* charData = (u8*)&font_bin[(CHAR_SIZE_X * CHAR_SIZE_Y * c) / 8]; + u32* fb = &framebuffer[x + y * FRAMEBUFFER_STRIDE_WORDS]; + int i, j; + for(i = 0; i < CHAR_SIZE_Y; i++) + { + u8 v= *(charData++); + for(j = 0; j < CHAR_SIZE_X; j++) + { + if(v & 1) *fb = 0x00000000; + else *fb = 0xFFFFFFFF; + v >>= 1; + fb++; + } + fb += FRAMEBUFFER_STRIDE_WORDS - CHAR_SIZE_X; + } +} + +void drawString(char* str, int x, int y) +{ + if(!str) return; + int k; + int dx = 0, dy = 0; + for(k = 0; str[k]; k++) + { + if(str[k] >= 32 && str[k] < 128) drawCharacter(str[k], x + dx, y + dy); + + dx += 8; + + if(str[k] == '\n') + { + dx = 0; + dy -= 8; + } + } +} + +void _printf(int x, int y, const char *format, ...) +{ + va_list args; + va_start(args, format); + + char buffer[0x100]; + + FS_VSNPRINTF(buffer, sizeof(buffer), format, args); + drawString(buffer, x, y); + + va_end(args); +} diff --git a/ios_fs/source/text.h b/ios_fs/source/text.h new file mode 100644 index 0000000..008cfce --- /dev/null +++ b/ios_fs/source/text.h @@ -0,0 +1,11 @@ +#ifndef TEXT_H +#define TEXT_H + +#include "types.h" + +void clearScreen(u32 color); +void clearLine(int y, u32 color); +void drawString(char* str, int x, int y); +void _printf(int x, int y, const char *format, ...); + +#endif diff --git a/ios_fs/source/types.h b/ios_fs/source/types.h new file mode 100644 index 0000000..832bc29 --- /dev/null +++ b/ios_fs/source/types.h @@ -0,0 +1,29 @@ +#ifndef TYPES_H +#define TYPES_H + + #include + #include + + #define U64_MAX UINT64_MAX + + typedef uint8_t u8; + typedef uint16_t u16; + typedef uint32_t u32; + typedef uint64_t u64; + + typedef int8_t s8; + typedef int16_t s16; + typedef int32_t s32; + typedef int64_t s64; + + typedef volatile u8 vu8; + typedef volatile u16 vu16; + typedef volatile u32 vu32; + typedef volatile u64 vu64; + + typedef volatile s8 vs8; + typedef volatile s16 vs16; + typedef volatile s32 vs32; + typedef volatile s64 vs64; + +#endif diff --git a/ios_kernel/Makefile b/ios_kernel/Makefile new file mode 100644 index 0000000..083d180 --- /dev/null +++ b/ios_kernel/Makefile @@ -0,0 +1,80 @@ +ifeq ($(strip $(DEVKITARM)),) +$(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") +endif + +ifeq ($(filter $(DEVKITARM)/bin,$(PATH)),) +export PATH:=$(DEVKITARM)/bin:$(PATH) +endif + +CC = arm-none-eabi-gcc +LINK = arm-none-eabi-gcc +AS = arm-none-eabi-as +OBJCOPY = arm-none-eabi-objcopy +OBJDUMP = arm-none-eabi-objdump +CFLAGS += -Wall -mbig-endian -std=gnu11 -mcpu=arm926ej-s -msoft-float -mfloat-abi=soft -Os +LDFLAGS += -nostartfiles -nodefaultlibs -mbig-endian -Wl,-T,link.ld +LIBDIRS += -L$(CURDIR)/../libs +LIBS += -lgcc + +CFILES = $(wildcard source/*.c) +BINFILES = $(wildcard data/*.bin) +OFILES = $(BINFILES:data/%.bin=build/%.bin.o) +OFILES += $(CFILES:source/%.c=build/%.o) +DFILES = $(CFILES:source/%.c=build/%.d) +SFILES = $(wildcard source/*.s) +OFILES += $(SFILES:source/%.s=build/%.o) +PROJECTNAME = ${shell basename "$(CURDIR)"} +CWD = "$(CURDIR)"" + +#--------------------------------------------------------------------------------- +# canned command sequence for binary data, taken from devkitARM +#--------------------------------------------------------------------------------- +define bin2o + bin2s $< | $(AS) -EB -o $(@) +endef + +.PHONY:=all dirs + +all: dirs $(PROJECTNAME).bin $(PROJECTNAME)_syms.h $(PROJECTNAME).bin $(PROJECTNAME).bin.h + +dirs: + @mkdir -p build + +$(PROJECTNAME).elf: $(OFILES) + @echo "LD $@" + @$(LINK) $(LDFLAGS) -o $(PROJECTNAME).elf $(sort $(filter-out build/crt0.o, $(OFILES))) $(LIBDIRS) $(LIBS) + +$(PROJECTNAME).bin: $(PROJECTNAME).elf + @echo "OBJCOPY $@\n" + @$(OBJCOPY) -j .text -j .rodata -j .data -O binary $(PROJECTNAME).elf $@ + +$(PROJECTNAME).bin.h: $(PROJECTNAME).bin + @xxd -i $< | sed "s/unsigned/static const unsigned/g;s/$(PROJECTNAME)$*/$(PROJECTNAME)/g" > $@ + +$(PROJECTNAME)_syms.h: + @echo "#ifndef $(PROJECTNAME)_SYMS_H" > $@ + @echo "#define $(PROJECTNAME)_SYMS_H" >> $@ + @$(OBJDUMP) -EB -t -marm $(PROJECTNAME).elf | grep 'g F .text' | grep -v '.hidden' | awk '{print "#define " $$6 " 0x" $$1}' >> $@ + @$(OBJDUMP) -EB -t -marm $(PROJECTNAME).elf | grep -e 'g .text' -e '_bss_' | awk '{print "#define " $$5 " 0x" $$1}' >> $@ + @echo "#endif" >> $@ + +clean: + @rm -f build/*.o build/*.d + @rm -f $(PROJECTNAME).elf $(PROJECTNAME).bin $(PROJECTNAME)_syms.h $(PROJECTNAME).bin $(PROJECTNAME).bin.h + @echo "all cleaned up !" + +-include $(DFILES) + +build/%.o: source/%.c + @echo "CC $(notdir $<)" + @$(CC) $(CFLAGS) -c $< -o $@ + @$(CC) -MM $< > build/$*.d + +build/%.o: source/%.s + @echo "CC $(notdir $<)" + @$(CC) $(CFLAGS) -xassembler-with-cpp -c $< -o $@ + @$(CC) -MM $< > build/$*.d + +build/%.bin.o: data/%.bin + @echo "BIN $(notdir $<)" + @$(bin2o) diff --git a/ios_kernel/link.ld b/ios_kernel/link.ld new file mode 100644 index 0000000..7371f7d --- /dev/null +++ b/ios_kernel/link.ld @@ -0,0 +1,28 @@ +OUTPUT_ARCH(arm) + +SECTIONS +{ + . = (0x08135000); + + __KERNEL_CODE_START = .; + .text : { + build/crt0.o(.init) + *(.text*); + } + .rodata : { + *(.rodata*) + } + .data : { + *(.data*) + } + .bss : { + *(.bss*) + *(COMMON*) + } + __KERNEL_CODE_END = .; + + /DISCARD/ : { + *(*); + } +} + diff --git a/ios_kernel/source/config.h b/ios_kernel/source/config.h new file mode 100644 index 0000000..791a2b2 --- /dev/null +++ b/ios_kernel/source/config.h @@ -0,0 +1,31 @@ +/*************************************************************************** + * Copyright (C) 2016 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef __CONFIG_H_ +#define __CONFIG_H_ + +#include "../../src/cfw_config.h" + +extern cfw_config_t cfw_config; + +#endif diff --git a/ios_kernel/source/crt0.s b/ios_kernel/source/crt0.s new file mode 100644 index 0000000..83d7bb6 --- /dev/null +++ b/ios_kernel/source/crt0.s @@ -0,0 +1,9 @@ +.section ".init" +.arm +.align 4 + +.extern _main +.type _main, %function + +_start: + b _main diff --git a/ios_kernel/source/elf_abi.h b/ios_kernel/source/elf_abi.h new file mode 100644 index 0000000..4d9c796 --- /dev/null +++ b/ios_kernel/source/elf_abi.h @@ -0,0 +1,591 @@ +/* + * Copyright (c) 1995, 1996, 2001, 2002 + * Erik Theisen. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 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 AUTHOR 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. + */ + +/* + * This is the ELF ABI header file + * formerly known as "elf_abi.h". + */ + +#ifndef _ELF_ABI_H +#define _ELF_ABI_H + +/* + * This version doesn't work for 64-bit ABIs - Erik. + */ + +/* + * These typedefs need to be handled better. + */ +typedef unsigned int Elf32_Addr; /* Unsigned program address */ +typedef unsigned int Elf32_Off; /* Unsigned file offset */ +typedef signed int Elf32_Sword; /* Signed large integer */ +typedef unsigned int Elf32_Word; /* Unsigned large integer */ +typedef unsigned short Elf32_Half; /* Unsigned medium integer */ + +/* e_ident[] identification indexes */ +#define EI_MAG0 0 /* file ID */ +#define EI_MAG1 1 /* file ID */ +#define EI_MAG2 2 /* file ID */ +#define EI_MAG3 3 /* file ID */ +#define EI_CLASS 4 /* file class */ +#define EI_DATA 5 /* data encoding */ +#define EI_VERSION 6 /* ELF header version */ +#define EI_OSABI 7 /* OS/ABI specific ELF extensions */ +#define EI_ABIVERSION 8 /* ABI target version */ +#define EI_PAD 9 /* start of pad bytes */ +#define EI_NIDENT 16 /* Size of e_ident[] */ + +/* e_ident[] magic number */ +#define ELFMAG0 0x7f /* e_ident[EI_MAG0] */ +#define ELFMAG1 'E' /* e_ident[EI_MAG1] */ +#define ELFMAG2 'L' /* e_ident[EI_MAG2] */ +#define ELFMAG3 'F' /* e_ident[EI_MAG3] */ +#define ELFMAG "\177ELF" /* magic */ +#define SELFMAG 4 /* size of magic */ + +/* e_ident[] file class */ +#define ELFCLASSNONE 0 /* invalid */ +#define ELFCLASsigned int 1 /* 32-bit objs */ +#define ELFCLASS64 2 /* 64-bit objs */ +#define ELFCLASSNUM 3 /* number of classes */ + +/* e_ident[] data encoding */ +#define ELFDATANONE 0 /* invalid */ +#define ELFDATA2LSB 1 /* Little-Endian */ +#define ELFDATA2MSB 2 /* Big-Endian */ +#define ELFDATANUM 3 /* number of data encode defines */ + +/* e_ident[] OS/ABI specific ELF extensions */ +#define ELFOSABI_NONE 0 /* No extension specified */ +#define ELFOSABI_HPUX 1 /* Hewlett-Packard HP-UX */ +#define ELFOSABI_NETBSD 2 /* NetBSD */ +#define ELFOSABI_LINUX 3 /* Linux */ +#define ELFOSABI_SOLARIS 6 /* Sun Solaris */ +#define ELFOSABI_AIX 7 /* AIX */ +#define ELFOSABI_IRIX 8 /* IRIX */ +#define ELFOSABI_FREEBSD 9 /* FreeBSD */ +#define ELFOSABI_TRU64 10 /* Compaq TRU64 UNIX */ +#define ELFOSABI_MODESTO 11 /* Novell Modesto */ +#define ELFOSABI_OPENBSD 12 /* OpenBSD */ +/* 64-255 Architecture-specific value range */ + +/* e_ident[] ABI Version */ +#define ELFABIVERSION 0 + +/* e_ident */ +#define IS_ELF(ehdr) ((ehdr).e_ident[EI_MAG0] == ELFMAG0 && \ + (ehdr).e_ident[EI_MAG1] == ELFMAG1 && \ + (ehdr).e_ident[EI_MAG2] == ELFMAG2 && \ + (ehdr).e_ident[EI_MAG3] == ELFMAG3) + +/* ELF Header */ +typedef struct elfhdr{ + unsigned char e_ident[EI_NIDENT]; /* ELF Identification */ + Elf32_Half e_type; /* object file type */ + Elf32_Half e_machine; /* machine */ + Elf32_Word e_version; /* object file version */ + Elf32_Addr e_entry; /* virtual entry point */ + Elf32_Off e_phoff; /* program header table offset */ + Elf32_Off e_shoff; /* section header table offset */ + Elf32_Word e_flags; /* processor-specific flags */ + Elf32_Half e_ehsize; /* ELF header size */ + Elf32_Half e_phentsize; /* program header entry size */ + Elf32_Half e_phnum; /* number of program header entries */ + Elf32_Half e_shentsize; /* section header entry size */ + Elf32_Half e_shnum; /* number of section header entries */ + Elf32_Half e_shstrndx; /* section header table's "section + header string table" entry offset */ +} Elf32_Ehdr; + +/* e_type */ +#define ET_NONE 0 /* No file type */ +#define ET_REL 1 /* relocatable file */ +#define ET_EXEC 2 /* executable file */ +#define ET_DYN 3 /* shared object file */ +#define ET_CORE 4 /* core file */ +#define ET_NUM 5 /* number of types */ +#define ET_LOOS 0xfe00 /* reserved range for operating */ +#define ET_HIOS 0xfeff /* system specific e_type */ +#define ET_LOPROC 0xff00 /* reserved range for processor */ +#define ET_HIPROC 0xffff /* specific e_type */ + +/* e_machine */ +#define EM_NONE 0 /* No Machine */ +#define EM_M32 1 /* AT&T WE 32100 */ +#define EM_SPARC 2 /* SPARC */ +#define EM_386 3 /* Intel 80386 */ +#define EM_68K 4 /* Motorola 68000 */ +#define EM_88K 5 /* Motorola 88000 */ +#if 0 +#define EM_486 6 /* RESERVED - was Intel 80486 */ +#endif +#define EM_860 7 /* Intel 80860 */ +#define EM_MIPS 8 /* MIPS R3000 Big-Endian only */ +#define EM_S370 9 /* IBM System/370 Processor */ +#define EM_MIPS_RS4_BE 10 /* MIPS R4000 Big-Endian */ +#if 0 +#define EM_SPARC64 11 /* RESERVED - was SPARC v9 + 64-bit unoffical */ +#endif +/* RESERVED 11-14 for future use */ +#define EM_PARISC 15 /* HPPA */ +/* RESERVED 16 for future use */ +#define EM_VPP500 17 /* Fujitsu VPP500 */ +#define EM_SPARC32PLUS 18 /* Enhanced instruction set SPARC */ +#define EM_960 19 /* Intel 80960 */ +#define EM_PPC 20 /* PowerPC */ +#define EM_PPC64 21 /* 64-bit PowerPC */ +#define EM_S390 22 /* IBM System/390 Processor */ +/* RESERVED 23-35 for future use */ +#define EM_V800 36 /* NEC V800 */ +#define EM_FR20 37 /* Fujitsu FR20 */ +#define EM_RH32 38 /* TRW RH-32 */ +#define EM_RCE 39 /* Motorola RCE */ +#define EM_ARM 40 /* Advanced Risc Machines ARM */ +#define EM_ALPHA 41 /* Digital Alpha */ +#define EM_SH 42 /* Hitachi SH */ +#define EM_SPARCV9 43 /* SPARC Version 9 */ +#define EM_TRICORE 44 /* Siemens TriCore embedded processor */ +#define EM_ARC 45 /* Argonaut RISC Core */ +#define EM_H8_300 46 /* Hitachi H8/300 */ +#define EM_H8_300H 47 /* Hitachi H8/300H */ +#define EM_H8S 48 /* Hitachi H8S */ +#define EM_H8_500 49 /* Hitachi H8/500 */ +#define EM_IA_64 50 /* Intel Merced */ +#define EM_MIPS_X 51 /* Stanford MIPS-X */ +#define EM_COLDFIRE 52 /* Motorola Coldfire */ +#define EM_68HC12 53 /* Motorola M68HC12 */ +#define EM_MMA 54 /* Fujitsu MMA Multimedia Accelerator*/ +#define EM_PCP 55 /* Siemens PCP */ +#define EM_NCPU 56 /* Sony nCPU embeeded RISC */ +#define EM_NDR1 57 /* Denso NDR1 microprocessor */ +#define EM_STARCORE 58 /* Motorola Start*Core processor */ +#define EM_ME16 59 /* Toyota ME16 processor */ +#define EM_ST100 60 /* STMicroelectronic ST100 processor */ +#define EM_TINYJ 61 /* Advanced Logic Corp. Tinyj emb.fam*/ +#define EM_X86_64 62 /* AMD x86-64 */ +#define EM_PDSP 63 /* Sony DSP Processor */ +/* RESERVED 64,65 for future use */ +#define EM_FX66 66 /* Siemens FX66 microcontroller */ +#define EM_ST9PLUS 67 /* STMicroelectronics ST9+ 8/16 mc */ +#define EM_ST7 68 /* STmicroelectronics ST7 8 bit mc */ +#define EM_68HC16 69 /* Motorola MC68HC16 microcontroller */ +#define EM_68HC11 70 /* Motorola MC68HC11 microcontroller */ +#define EM_68HC08 71 /* Motorola MC68HC08 microcontroller */ +#define EM_68HC05 72 /* Motorola MC68HC05 microcontroller */ +#define EM_SVX 73 /* Silicon Graphics SVx */ +#define EM_ST19 74 /* STMicroelectronics ST19 8 bit mc */ +#define EM_VAX 75 /* Digital VAX */ +#define EM_CHRIS 76 /* Axis Communications embedded proc. */ +#define EM_JAVELIN 77 /* Infineon Technologies emb. proc. */ +#define EM_FIREPATH 78 /* Element 14 64-bit DSP Processor */ +#define EM_ZSP 79 /* LSI Logic 16-bit DSP Processor */ +#define EM_MMIX 80 /* Donald Knuth's edu 64-bit proc. */ +#define EM_HUANY 81 /* Harvard University mach-indep objs */ +#define EM_PRISM 82 /* SiTera Prism */ +#define EM_AVR 83 /* Atmel AVR 8-bit microcontroller */ +#define EM_FR30 84 /* Fujitsu FR30 */ +#define EM_D10V 85 /* Mitsubishi DV10V */ +#define EM_D30V 86 /* Mitsubishi DV30V */ +#define EM_V850 87 /* NEC v850 */ +#define EM_M32R 88 /* Mitsubishi M32R */ +#define EM_MN10300 89 /* Matsushita MN10200 */ +#define EM_MN10200 90 /* Matsushita MN10200 */ +#define EM_PJ 91 /* picoJava */ +#define EM_NUM 92 /* number of machine types */ + +/* Version */ +#define EV_NONE 0 /* Invalid */ +#define EV_CURRENT 1 /* Current */ +#define EV_NUM 2 /* number of versions */ + +/* Section Header */ +typedef struct { + Elf32_Word sh_name; /* name - index into section header + string table section */ + Elf32_Word sh_type; /* type */ + Elf32_Word sh_flags; /* flags */ + Elf32_Addr sh_addr; /* address */ + Elf32_Off sh_offset; /* file offset */ + Elf32_Word sh_size; /* section size */ + Elf32_Word sh_link; /* section header table index link */ + Elf32_Word sh_info; /* extra information */ + Elf32_Word sh_addralign; /* address alignment */ + Elf32_Word sh_entsize; /* section entry size */ +} Elf32_Shdr; + +/* Special Section Indexes */ +#define SHN_UNDEF 0 /* undefined */ +#define SHN_LORESERVE 0xff00 /* lower bounds of reserved indexes */ +#define SHN_LOPROC 0xff00 /* reserved range for processor */ +#define SHN_HIPROC 0xff1f /* specific section indexes */ +#define SHN_LOOS 0xff20 /* reserved range for operating */ +#define SHN_HIOS 0xff3f /* specific semantics */ +#define SHN_ABS 0xfff1 /* absolute value */ +#define SHN_COMMON 0xfff2 /* common symbol */ +#define SHN_XINDEX 0xffff /* Index is an extra table */ +#define SHN_HIRESERVE 0xffff /* upper bounds of reserved indexes */ + +/* sh_type */ +#define SHT_NULL 0 /* inactive */ +#define SHT_PROGBITS 1 /* program defined information */ +#define SHT_SYMTAB 2 /* symbol table section */ +#define SHT_STRTAB 3 /* string table section */ +#define SHT_RELA 4 /* relocation section with addends*/ +#define SHT_HASH 5 /* symbol hash table section */ +#define SHT_DYNAMIC 6 /* dynamic section */ +#define SHT_NOTE 7 /* note section */ +#define SHT_NOBITS 8 /* no space section */ +#define SHT_REL 9 /* relation section without addends */ +#define SHT_SHLIB 10 /* reserved - purpose unknown */ +#define SHT_DYNSYM 11 /* dynamic symbol table section */ +#define SHT_INIT_ARRAY 14 /* Array of constructors */ +#define SHT_FINI_ARRAY 15 /* Array of destructors */ +#define SHT_PREINIT_ARRAY 16 /* Array of pre-constructors */ +#define SHT_GROUP 17 /* Section group */ +#define SHT_SYMTAB_SHNDX 18 /* Extended section indeces */ +#define SHT_NUM 19 /* number of section types */ +#define SHT_LOOS 0x60000000 /* Start OS-specific */ +#define SHT_HIOS 0x6fffffff /* End OS-specific */ +#define SHT_LOPROC 0x70000000 /* reserved range for processor */ +#define SHT_HIPROC 0x7fffffff /* specific section header types */ +#define SHT_LOUSER 0x80000000 /* reserved range for application */ +#define SHT_HIUSER 0xffffffff /* specific indexes */ + +/* Section names */ +#define ELF_BSS ".bss" /* uninitialized data */ +#define ELF_COMMENT ".comment" /* version control information */ +#define ELF_DATA ".data" /* initialized data */ +#define ELF_DATA1 ".data1" /* initialized data */ +#define ELF_DEBUG ".debug" /* debug */ +#define ELF_DYNAMIC ".dynamic" /* dynamic linking information */ +#define ELF_DYNSTR ".dynstr" /* dynamic string table */ +#define ELF_DYNSYM ".dynsym" /* dynamic symbol table */ +#define ELF_FINI ".fini" /* termination code */ +#define ELF_FINI_ARRAY ".fini_array" /* Array of destructors */ +#define ELF_GOT ".got" /* global offset table */ +#define ELF_HASH ".hash" /* symbol hash table */ +#define ELF_INIT ".init" /* initialization code */ +#define ELF_INIT_ARRAY ".init_array" /* Array of constuctors */ +#define ELF_INTERP ".interp" /* Pathname of program interpreter */ +#define ELF_LINE ".line" /* Symbolic line numnber information */ +#define ELF_NOTE ".note" /* Contains note section */ +#define ELF_PLT ".plt" /* Procedure linkage table */ +#define ELF_PREINIT_ARRAY ".preinit_array" /* Array of pre-constructors */ +#define ELF_REL_DATA ".rel.data" /* relocation data */ +#define ELF_REL_FINI ".rel.fini" /* relocation termination code */ +#define ELF_REL_INIT ".rel.init" /* relocation initialization code */ +#define ELF_REL_DYN ".rel.dyn" /* relocaltion dynamic link info */ +#define ELF_REL_RODATA ".rel.rodata" /* relocation read-only data */ +#define ELF_REL_TEXT ".rel.text" /* relocation code */ +#define ELF_RODATA ".rodata" /* read-only data */ +#define ELF_RODATA1 ".rodata1" /* read-only data */ +#define ELF_SHSTRTAB ".shstrtab" /* section header string table */ +#define ELF_STRTAB ".strtab" /* string table */ +#define ELF_SYMTAB ".symtab" /* symbol table */ +#define ELF_SYMTAB_SHNDX ".symtab_shndx"/* symbol table section index */ +#define ELF_TBSS ".tbss" /* thread local uninit data */ +#define ELF_TDATA ".tdata" /* thread local init data */ +#define ELF_TDATA1 ".tdata1" /* thread local init data */ +#define ELF_TEXT ".text" /* code */ + +/* Section Attribute Flags - sh_flags */ +#define SHF_WRITE 0x1 /* Writable */ +#define SHF_ALLOC 0x2 /* occupies memory */ +#define SHF_EXECINSTR 0x4 /* executable */ +#define SHF_MERGE 0x10 /* Might be merged */ +#define SHF_STRINGS 0x20 /* Contains NULL terminated strings */ +#define SHF_INFO_LINK 0x40 /* sh_info contains SHT index */ +#define SHF_LINK_ORDER 0x80 /* Preserve order after combining*/ +#define SHF_OS_NONCONFORMING 0x100 /* Non-standard OS specific handling */ +#define SHF_GROUP 0x200 /* Member of section group */ +#define SHF_TLS 0x400 /* Thread local storage */ +#define SHF_MASKOS 0x0ff00000 /* OS specific */ +#define SHF_MASKPROC 0xf0000000 /* reserved bits for processor */ + /* specific section attributes */ + +/* Section Group Flags */ +#define GRP_COMDAT 0x1 /* COMDAT group */ +#define GRP_MASKOS 0x0ff00000 /* Mask OS specific flags */ +#define GRP_MASKPROC 0xf0000000 /* Mask processor specific flags */ + +/* Symbol Table Entry */ +typedef struct elf32_sym { + Elf32_Word st_name; /* name - index into string table */ + Elf32_Addr st_value; /* symbol value */ + Elf32_Word st_size; /* symbol size */ + unsigned char st_info; /* type and binding */ + unsigned char st_other; /* 0 - no defined meaning */ + Elf32_Half st_shndx; /* section header index */ +} Elf32_Sym; + +/* Symbol table index */ +#define STN_UNDEF 0 /* undefined */ + +/* Extract symbol info - st_info */ +#define ELF32_ST_BIND(x) ((x) >> 4) +#define ELF32_ST_TYPE(x) (((unsigned int) x) & 0xf) +#define ELF32_ST_INFO(b,t) (((b) << 4) + ((t) & 0xf)) +#define ELF32_ST_VISIBILITY(x) ((x) & 0x3) + +/* Symbol Binding - ELF32_ST_BIND - st_info */ +#define STB_LOCAL 0 /* Local symbol */ +#define STB_GLOBAL 1 /* Global symbol */ +#define STB_WEAK 2 /* like global - lower precedence */ +#define STB_NUM 3 /* number of symbol bindings */ +#define STB_LOOS 10 /* reserved range for operating */ +#define STB_HIOS 12 /* system specific symbol bindings */ +#define STB_LOPROC 13 /* reserved range for processor */ +#define STB_HIPROC 15 /* specific symbol bindings */ + +/* Symbol type - ELF32_ST_TYPE - st_info */ +#define STT_NOTYPE 0 /* not specified */ +#define STT_OBJECT 1 /* data object */ +#define STT_FUNC 2 /* function */ +#define STT_SECTION 3 /* section */ +#define STT_FILE 4 /* file */ +#define STT_NUM 5 /* number of symbol types */ +#define STT_TLS 6 /* Thread local storage symbol */ +#define STT_LOOS 10 /* reserved range for operating */ +#define STT_HIOS 12 /* system specific symbol types */ +#define STT_LOPROC 13 /* reserved range for processor */ +#define STT_HIPROC 15 /* specific symbol types */ + +/* Symbol visibility - ELF32_ST_VISIBILITY - st_other */ +#define STV_DEFAULT 0 /* Normal visibility rules */ +#define STV_INTERNAL 1 /* Processor specific hidden class */ +#define STV_HIDDEN 2 /* Symbol unavailable in other mods */ +#define STV_PROTECTED 3 /* Not preemptible, not exported */ + + +/* Relocation entry with implicit addend */ +typedef struct +{ + Elf32_Addr r_offset; /* offset of relocation */ + Elf32_Word r_info; /* symbol table index and type */ +} Elf32_Rel; + +/* Relocation entry with explicit addend */ +typedef struct +{ + Elf32_Addr r_offset; /* offset of relocation */ + Elf32_Word r_info; /* symbol table index and type */ + Elf32_Sword r_addend; +} Elf32_Rela; + +/* Extract relocation info - r_info */ +#define ELF32_R_SYM(i) ((i) >> 8) +#define ELF32_R_TYPE(i) ((unsigned char) (i)) +#define ELF32_R_INFO(s,t) (((s) << 8) + (unsigned char)(t)) + +/* Program Header */ +typedef struct { + Elf32_Word p_type; /* segment type */ + Elf32_Off p_offset; /* segment offset */ + Elf32_Addr p_vaddr; /* virtual address of segment */ + Elf32_Addr p_paddr; /* physical address - ignored? */ + Elf32_Word p_filesz; /* number of bytes in file for seg. */ + Elf32_Word p_memsz; /* number of bytes in mem. for seg. */ + Elf32_Word p_flags; /* flags */ + Elf32_Word p_align; /* memory alignment */ +} Elf32_Phdr; + +/* Segment types - p_type */ +#define PT_NULL 0 /* unused */ +#define PT_LOAD 1 /* loadable segment */ +#define PT_DYNAMIC 2 /* dynamic linking section */ +#define PT_INTERP 3 /* the RTLD */ +#define PT_NOTE 4 /* auxiliary information */ +#define PT_SHLIB 5 /* reserved - purpose undefined */ +#define PT_PHDR 6 /* program header */ +#define PT_TLS 7 /* Thread local storage template */ +#define PT_NUM 8 /* Number of segment types */ +#define PT_LOOS 0x60000000 /* reserved range for operating */ +#define PT_HIOS 0x6fffffff /* system specific segment types */ +#define PT_LOPROC 0x70000000 /* reserved range for processor */ +#define PT_HIPROC 0x7fffffff /* specific segment types */ + +/* Segment flags - p_flags */ +#define PF_X 0x1 /* Executable */ +#define PF_W 0x2 /* Writable */ +#define PF_R 0x4 /* Readable */ +#define PF_MASKOS 0x0ff00000 /* OS specific segment flags */ +#define PF_MASKPROC 0xf0000000 /* reserved bits for processor */ + /* specific segment flags */ +/* Dynamic structure */ +typedef struct +{ + Elf32_Sword d_tag; /* controls meaning of d_val */ + union + { + Elf32_Word d_val; /* Multiple meanings - see d_tag */ + Elf32_Addr d_ptr; /* program virtual address */ + } d_un; +} Elf32_Dyn; + +extern Elf32_Dyn _DYNAMIC[]; + +/* Dynamic Array Tags - d_tag */ +#define DT_NULL 0 /* marks end of _DYNAMIC array */ +#define DT_NEEDED 1 /* string table offset of needed lib */ +#define DT_PLTRELSZ 2 /* size of relocation entries in PLT */ +#define DT_PLTGOT 3 /* address PLT/GOT */ +#define DT_HASH 4 /* address of symbol hash table */ +#define DT_STRTAB 5 /* address of string table */ +#define DT_SYMTAB 6 /* address of symbol table */ +#define DT_RELA 7 /* address of relocation table */ +#define DT_RELASZ 8 /* size of relocation table */ +#define DT_RELAENT 9 /* size of relocation entry */ +#define DT_STRSZ 10 /* size of string table */ +#define DT_SYMENT 11 /* size of symbol table entry */ +#define DT_INIT 12 /* address of initialization func. */ +#define DT_FINI 13 /* address of termination function */ +#define DT_SONAME 14 /* string table offset of shared obj */ +#define DT_RPATH 15 /* string table offset of library + search path */ +#define DT_SYMBOLIC 16 /* start sym search in shared obj. */ +#define DT_REL 17 /* address of rel. tbl. w addends */ +#define DT_RELSZ 18 /* size of DT_REL relocation table */ +#define DT_RELENT 19 /* size of DT_REL relocation entry */ +#define DT_PLTREL 20 /* PLT referenced relocation entry */ +#define DT_DEBUG 21 /* bugger */ +#define DT_TEXTREL 22 /* Allow rel. mod. to unwritable seg */ +#define DT_JMPREL 23 /* add. of PLT's relocation entries */ +#define DT_BIND_NOW 24 /* Process relocations of object */ +#define DT_INIT_ARRAY 25 /* Array with addresses of init fct */ +#define DT_FINI_ARRAY 26 /* Array with addresses of fini fct */ +#define DT_INIT_ARRAYSZ 27 /* Size in bytes of DT_INIT_ARRAY */ +#define DT_FINI_ARRAYSZ 28 /* Size in bytes of DT_FINI_ARRAY */ +#define DT_RUNPATH 29 /* Library search path */ +#define DT_FLAGS 30 /* Flags for the object being loaded */ +#define DT_ENCODING 32 /* Start of encoded range */ +#define DT_PREINIT_ARRAY 32 /* Array with addresses of preinit fct*/ +#define DT_PREINIT_ARRAYSZ 33 /* size in bytes of DT_PREINIT_ARRAY */ +#define DT_NUM 34 /* Number used. */ +#define DT_LOOS 0x60000000 /* reserved range for OS */ +#define DT_HIOS 0x6fffffff /* specific dynamic array tags */ +#define DT_LOPROC 0x70000000 /* reserved range for processor */ +#define DT_HIPROC 0x7fffffff /* specific dynamic array tags */ + +/* Dynamic Tag Flags - d_un.d_val */ +#define DF_ORIGIN 0x01 /* Object may use DF_ORIGIN */ +#define DF_SYMBOLIC 0x02 /* Symbol resolutions starts here */ +#define DF_TEXTREL 0x04 /* Object contains text relocations */ +#define DF_BIND_NOW 0x08 /* No lazy binding for this object */ +#define DF_STATIC_TLS 0x10 /* Static thread local storage */ + +/* Standard ELF hashing function */ +unsigned long elf_hash(const unsigned char *name); + +#define ELF_TARG_VER 1 /* The ver for which this code is intended */ + +/* + * XXX - PowerPC defines really don't belong in here, + * but we'll put them in for simplicity. + */ + +/* Values for Elf32/64_Ehdr.e_flags. */ +#define EF_PPC_EMB 0x80000000 /* PowerPC embedded flag */ + +/* Cygnus local bits below */ +#define EF_PPC_RELOCATABLE 0x00010000 /* PowerPC -mrelocatable flag*/ +#define EF_PPC_RELOCATABLE_LIB 0x00008000 /* PowerPC -mrelocatable-lib + flag */ + +/* PowerPC relocations defined by the ABIs */ +#define R_PPC_NONE 0 +#define R_PPC_ADDR32 1 /* 32bit absolute address */ +#define R_PPC_ADDR24 2 /* 26bit address, 2 bits ignored. */ +#define R_PPC_ADDR16 3 /* 16bit absolute address */ +#define R_PPC_ADDR16_LO 4 /* lower 16bit of absolute address */ +#define R_PPC_ADDR16_HI 5 /* high 16bit of absolute address */ +#define R_PPC_ADDR16_HA 6 /* adjusted high 16bit */ +#define R_PPC_ADDR14 7 /* 16bit address, 2 bits ignored */ +#define R_PPC_ADDR14_BRTAKEN 8 +#define R_PPC_ADDR14_BRNTAKEN 9 +#define R_PPC_REL24 10 /* PC relative 26 bit */ +#define R_PPC_REL14 11 /* PC relative 16 bit */ +#define R_PPC_REL14_BRTAKEN 12 +#define R_PPC_REL14_BRNTAKEN 13 +#define R_PPC_GOT16 14 +#define R_PPC_GOT16_LO 15 +#define R_PPC_GOT16_HI 16 +#define R_PPC_GOT16_HA 17 +#define R_PPC_PLTREL24 18 +#define R_PPC_COPY 19 +#define R_PPC_GLOB_DAT 20 +#define R_PPC_JMP_SLOT 21 +#define R_PPC_RELATIVE 22 +#define R_PPC_LOCAL24PC 23 +#define R_PPC_UADDR32 24 +#define R_PPC_UADDR16 25 +#define R_PPC_REL32 26 +#define R_PPC_PLT32 27 +#define R_PPC_PLTREL32 28 +#define R_PPC_PLT16_LO 29 +#define R_PPC_PLT16_HI 30 +#define R_PPC_PLT16_HA 31 +#define R_PPC_SDAREL16 32 +#define R_PPC_SECTOFF 33 +#define R_PPC_SECTOFF_LO 34 +#define R_PPC_SECTOFF_HI 35 +#define R_PPC_SECTOFF_HA 36 +/* Keep this the last entry. */ +#define R_PPC_NUM 37 + +/* The remaining relocs are from the Embedded ELF ABI, and are not + in the SVR4 ELF ABI. */ +#define R_PPC_EMB_NADDR32 101 +#define R_PPC_EMB_NADDR16 102 +#define R_PPC_EMB_NADDR16_LO 103 +#define R_PPC_EMB_NADDR16_HI 104 +#define R_PPC_EMB_NADDR16_HA 105 +#define R_PPC_EMB_SDAI16 106 +#define R_PPC_EMB_SDA2I16 107 +#define R_PPC_EMB_SDA2REL 108 +#define R_PPC_EMB_SDA21 109 /* 16 bit offset in SDA */ +#define R_PPC_EMB_MRKREF 110 +#define R_PPC_EMB_RELSEC16 111 +#define R_PPC_EMB_RELST_LO 112 +#define R_PPC_EMB_RELST_HI 113 +#define R_PPC_EMB_RELST_HA 114 +#define R_PPC_EMB_BIT_FLD 115 +#define R_PPC_EMB_RELSDA 116 /* 16 bit relative offset in SDA */ + +/* Diab tool relocations. */ +#define R_PPC_DIAB_SDA21_LO 180 /* like EMB_SDA21, but lower 16 bit */ +#define R_PPC_DIAB_SDA21_HI 181 /* like EMB_SDA21, but high 16 bit */ +#define R_PPC_DIAB_SDA21_HA 182 /* like EMB_SDA21, adjusted high 16 */ +#define R_PPC_DIAB_RELSDA_LO 183 /* like EMB_RELSDA, but lower 16 bit */ +#define R_PPC_DIAB_RELSDA_HI 184 /* like EMB_RELSDA, but high 16 bit */ +#define R_PPC_DIAB_RELSDA_HA 185 /* like EMB_RELSDA, adjusted high 16 */ + +/* This is a phony reloc to handle any old fashioned TOC16 references + that may still be in object files. */ +#define R_PPC_TOC16 255 + +#endif /* _ELF_H */ diff --git a/ios_kernel/source/elf_patcher.c b/ios_kernel/source/elf_patcher.c new file mode 100644 index 0000000..8310964 --- /dev/null +++ b/ios_kernel/source/elf_patcher.c @@ -0,0 +1,110 @@ +/*************************************************************************** + * Copyright (C) 2016 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include "types.h" +#include "elf_abi.h" +#include "utils.h" + +static Elf32_Phdr * get_section(u32 data, u32 vaddr) +{ + Elf32_Ehdr *ehdr = (Elf32_Ehdr *) data; + + if ( !IS_ELF (*ehdr) + || (ehdr->e_type != ET_EXEC) + || (ehdr->e_machine != EM_ARM)) + { + return 0; + } + + Elf32_Phdr *phdr = 0; + + u32 i; + for(i = 0; i < ehdr->e_phnum; i++) + { + phdr = (Elf32_Phdr *) (data + ehdr->e_phoff + ehdr->e_phentsize * i); + + if((vaddr >= phdr[0].p_vaddr) && ((i == ehdr->e_phnum) || (vaddr < phdr[1].p_vaddr))) + { + break; + } + } + return phdr; +} + +void section_write_bss(u32 ios_elf_start, u32 address, u32 size) +{ + Elf32_Phdr *phdr = get_section(ios_elf_start, address); + if(!phdr) + return; + + if((address - phdr->p_vaddr + size) > phdr->p_memsz) + { + phdr->p_memsz = (address - phdr->p_vaddr + size); + } +} + +void section_write(u32 ios_elf_start, u32 address, const void *data, u32 size) +{ + Elf32_Phdr *phdr = get_section(ios_elf_start, address); + if(!phdr) + return; + + u32 *addr = (u32*)(ios_elf_start + address - phdr->p_vaddr + phdr->p_offset); + + if((address - phdr->p_vaddr + size) > phdr->p_filesz) + { + u32 additionalSize = address - phdr->p_vaddr + size - phdr->p_filesz; + + Elf32_Ehdr *ehdr = (Elf32_Ehdr *) ios_elf_start; + Elf32_Phdr * tmpPhdr; + u32 i; + for(i = (ehdr->e_phnum-1); i >= 0; i--) + { + tmpPhdr = (Elf32_Phdr *) (ios_elf_start + ehdr->e_phoff + ehdr->e_phentsize * i); + + if(phdr->p_offset < tmpPhdr->p_offset) + { + reverse_memcpy((u8*)ios_elf_start + tmpPhdr->p_offset + additionalSize, (u8*)ios_elf_start + tmpPhdr->p_offset, tmpPhdr->p_filesz); + tmpPhdr->p_offset += additionalSize; + } + else { + break; + } + } + phdr->p_filesz += additionalSize; + if(phdr->p_memsz < phdr->p_filesz) + { + phdr->p_memsz = phdr->p_filesz; + } + } + + // in most cases only a word is copied to an aligned address so do a short cut for performance + if(size == 4 && !((unsigned int)addr & 3) && !((unsigned int)data & 3)) + { + *(u32*)addr = *(u32*)data; + } + else + { + kernel_memcpy(addr, data, size); + } +} diff --git a/ios_kernel/source/elf_patcher.h b/ios_kernel/source/elf_patcher.h new file mode 100644 index 0000000..3033ea8 --- /dev/null +++ b/ios_kernel/source/elf_patcher.h @@ -0,0 +1,58 @@ +/*************************************************************************** + * Copyright (C) 2016 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef _ELF_PATCHER_H +#define _ELF_PATCHER_H + +#include "types.h" + +#define ARM_B(addr, func) (0xEA000000 | ((((u32)(func) - (u32)(addr) - 8) >> 2) & 0x00FFFFFF)) +#define ARM_BL(addr, func) (0xEB000000 | ((((u32)(func) - (u32)(addr) - 8) >> 2) & 0x00FFFFFF)) + +typedef struct +{ + u32 address; + void* data; + u32 size; +} patch_table_t; + +void section_write(u32 ios_elf_start, u32 address, const void *data, u32 size); +void section_write_bss(u32 ios_elf_start, u32 address, u32 size); + +static inline void section_write_word(u32 ios_elf_start, u32 address, u32 word) +{ + section_write(ios_elf_start, address, &word, sizeof(word)); +} + + +static inline void patch_table_entries(u32 ios_elf_start, const patch_table_t * patch_table, u32 patch_count) +{ + u32 i; + for(i = 0; i < patch_count; i++) + { + section_write(ios_elf_start, patch_table[i].address, patch_table[i].data, patch_table[i].size); + } +} + + +#endif diff --git a/ios_kernel/source/exception_handler.c b/ios_kernel/source/exception_handler.c new file mode 100644 index 0000000..1ac771f --- /dev/null +++ b/ios_kernel/source/exception_handler.c @@ -0,0 +1,62 @@ +/*************************************************************************** + * Copyright (C) 2016 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include "text.h" +#include "types.h" + +void crash_handler(unsigned int *context, int type) +{ + clearScreen(0xFFFFFFFF); + + if(type == 0) + { + _printf(0, 0, "GURU MEDITATION ERROR (prefetch abort)"); + } + else if(type == 1) + { + _printf(0, 0, "GURU MEDITATION ERROR (data abort)"); + } + else + { + _printf(0, 0, "GURU MEDITATION ERROR (undefined instruction)"); + } + + int reg = 0; + while(reg < 16) + { + if(reg < 10) + { + _printf(20, 40 + reg * 20, "r%d = %08X", reg, context[1 + reg]); + } + else + { + _printf(20, 40 + reg * 20, "r%d = %08X", reg, context[1 + reg]); + } + + reg++; + } + + _printf(400, 20, "%08X", *(u32*)context[0x10]); + + for(;;); +} diff --git a/ios_kernel/source/exception_handler.h b/ios_kernel/source/exception_handler.h new file mode 100644 index 0000000..a3b7094 --- /dev/null +++ b/ios_kernel/source/exception_handler.h @@ -0,0 +1,44 @@ +/*************************************************************************** + * Copyright (C) 2016 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef _EXCEPTION_HANDLER_H +#define _EXCEPTION_HANDLER_H + +void crash_handler(unsigned int *context, int type); + +static inline void crash_handler_prefetch(unsigned int *context, int unused1, int unused2) +{ + crash_handler(context, 0); +} + +static inline void crash_handler_data(unsigned int *context, int unused1, int unused2) +{ + crash_handler(context, 1); +} + +static inline void crash_handler_undef_instr(unsigned int *context, int unused1, int unused2) +{ + crash_handler(context, 2); +} + +#endif diff --git a/ios_kernel/source/font_bin.h b/ios_kernel/source/font_bin.h new file mode 100644 index 0000000..dce9faa --- /dev/null +++ b/ios_kernel/source/font_bin.h @@ -0,0 +1,65 @@ +static const unsigned char font_bin[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x18, + 0x18, 0x00, 0x0c, 0x00, 0x00, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x66, 0x66, 0xff, 0x66, 0xff, 0x66, 0x66, 0x00, 0x18, 0x7c, 0x06, + 0x3c, 0x60, 0x3e, 0x18, 0x10, 0x46, 0x66, 0x30, 0x18, 0x0c, 0x66, 0x62, + 0x00, 0x3c, 0x66, 0x3c, 0x1c, 0xe6, 0x66, 0xfc, 0x00, 0x18, 0x0c, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x18, 0x0c, 0x0c, 0x18, 0x30, 0x00, + 0x00, 0x0c, 0x18, 0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x66, 0x3c, 0xff, + 0x3c, 0x66, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x3e, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, + 0x00, 0x40, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x00, 0x00, 0x3c, 0x66, 0x76, + 0x6e, 0x66, 0x3c, 0x00, 0x00, 0x18, 0x1c, 0x18, 0x18, 0x18, 0x7e, 0x00, + 0x00, 0x3c, 0x62, 0x30, 0x0c, 0x06, 0x7e, 0x00, 0x00, 0x3c, 0x62, 0x38, + 0x60, 0x66, 0x3c, 0x00, 0x00, 0x6c, 0x6c, 0x66, 0xfe, 0x60, 0x60, 0x00, + 0x00, 0x7e, 0x06, 0x7e, 0x60, 0x66, 0x3c, 0x00, 0x00, 0x3c, 0x06, 0x3e, + 0x66, 0x66, 0x3c, 0x00, 0x00, 0x7e, 0x30, 0x30, 0x18, 0x18, 0x18, 0x00, + 0x00, 0x3c, 0x66, 0x3c, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x3c, 0x66, 0x7c, + 0x60, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, + 0x00, 0x00, 0x18, 0x00, 0x18, 0x18, 0x0c, 0x00, 0x00, 0x70, 0x1c, 0x06, + 0x06, 0x1c, 0x70, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x3e, 0x00, 0x00, 0x00, + 0x00, 0x0e, 0x38, 0x60, 0x60, 0x38, 0x0e, 0x00, 0x00, 0x3c, 0x66, 0x30, + 0x18, 0x00, 0x18, 0x00, 0x00, 0x3c, 0x66, 0x76, 0x76, 0x06, 0x46, 0x3c, + 0x00, 0x3c, 0x66, 0x7e, 0x66, 0x66, 0x66, 0x00, 0x00, 0x3e, 0x66, 0x3e, + 0x66, 0x66, 0x3e, 0x00, 0x00, 0x3c, 0x66, 0x06, 0x06, 0x66, 0x3c, 0x00, + 0x00, 0x1e, 0x36, 0x66, 0x66, 0x36, 0x1e, 0x00, 0x00, 0x7e, 0x06, 0x1e, + 0x06, 0x06, 0x7e, 0x00, 0x00, 0x3e, 0x06, 0x1e, 0x06, 0x06, 0x06, 0x00, + 0x00, 0x3c, 0x66, 0x06, 0x76, 0x66, 0x3c, 0x00, 0x00, 0x66, 0x66, 0x7e, + 0x66, 0x66, 0x66, 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, + 0x00, 0x78, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x66, 0x36, 0x1e, + 0x1e, 0x36, 0x66, 0x00, 0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x7e, 0x00, + 0x00, 0x46, 0x6e, 0x7e, 0x56, 0x46, 0x46, 0x00, 0x00, 0x66, 0x6e, 0x7e, + 0x76, 0x66, 0x66, 0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x00, + 0x00, 0x3e, 0x66, 0x3e, 0x06, 0x06, 0x06, 0x00, 0x00, 0x3c, 0x66, 0x66, + 0x66, 0x3c, 0x70, 0x00, 0x00, 0x3e, 0x66, 0x3e, 0x1e, 0x36, 0x66, 0x00, + 0x00, 0x3c, 0x66, 0x0c, 0x30, 0x66, 0x3c, 0x00, 0x00, 0x7e, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x00, + 0x00, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x46, 0x46, 0x56, + 0x7e, 0x6e, 0x46, 0x00, 0x00, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0x66, 0x00, + 0x00, 0x66, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x00, 0x7e, 0x30, 0x18, + 0x0c, 0x06, 0x7e, 0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, + 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x40, 0x00, 0x00, 0x3c, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x3c, 0x00, 0x18, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x0c, 0x18, 0x30, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x60, 0x7c, 0x66, 0x7c, 0x00, + 0x00, 0x06, 0x06, 0x3e, 0x66, 0x66, 0x3e, 0x00, 0x00, 0x00, 0x3c, 0x06, + 0x06, 0x06, 0x3c, 0x00, 0x00, 0x60, 0x60, 0x7c, 0x66, 0x66, 0x7c, 0x00, + 0x00, 0x00, 0x3c, 0x66, 0x7e, 0x06, 0x3c, 0x00, 0x00, 0x38, 0x0c, 0x3e, + 0x0c, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x7c, 0x66, 0x7c, 0x40, 0x3c, 0x00, + 0x00, 0x06, 0x06, 0x3e, 0x66, 0x66, 0x66, 0x00, 0x00, 0x18, 0x00, 0x1c, + 0x18, 0x18, 0x3c, 0x00, 0x00, 0x30, 0x00, 0x30, 0x30, 0x30, 0x1e, 0x00, + 0x00, 0x06, 0x06, 0x36, 0x1e, 0x36, 0x66, 0x00, 0x00, 0x1c, 0x18, 0x18, + 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x66, 0xfe, 0xfe, 0xd6, 0xc6, 0x00, + 0x00, 0x00, 0x3e, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x3c, 0x66, + 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x3e, 0x66, 0x66, 0x3e, 0x06, 0x00, + 0x00, 0x00, 0x7c, 0x66, 0x66, 0x7c, 0x60, 0x00, 0x00, 0x00, 0x3e, 0x66, + 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x7c, 0x06, 0x3c, 0x60, 0x3e, 0x00, + 0x00, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x66, 0x66, + 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x00, + 0x00, 0x00, 0xc6, 0xd6, 0xfe, 0x7c, 0x6c, 0x00, 0x00, 0x00, 0x66, 0x3c, + 0x18, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x66, 0x66, 0x7c, 0x60, 0x3c, 0x00, + 0x00, 0x00, 0x7e, 0x30, 0x18, 0x0c, 0x7e, 0x00, 0x00, 0x00, 0x18, 0x08, + 0x08, 0x04, 0x08, 0x08, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x00, 0x00, 0x0c, 0x08, 0x08, 0x10, 0x08, 0x08 +}; diff --git a/ios_kernel/source/fsa.c b/ios_kernel/source/fsa.c new file mode 100644 index 0000000..9a28f06 --- /dev/null +++ b/ios_kernel/source/fsa.c @@ -0,0 +1,236 @@ +/*************************************************************************** + * Copyright (C) 2016 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include "types.h" +#include "utils.h" + +#define svcAlloc ((void *(*)(u32 heapid, u32 size))0x081234E4) +#define svcAllocAlign ((void *(*)(u32 heapid, u32 size, u32 align))0x08123464) +#define svcFree ((void *(*)(u32 heapid, void *ptr))0x08123830) +#define svcOpen ((int (*)(const char* name, int mode))0x0812940C) +#define svcClose ((int (*)(int fd))0x08129368) +#define svcIoctl ((int (*)(int fd, u32 request, void* input_buffer, u32 input_buffer_len, void* output_buffer, u32 output_buffer_len))0x081290E0) +#define svcIoctlv ((int (*)(int fd, u32 request, u32 vector_count_in, u32 vector_count_out, iovec_s* vector))0x0812903C) + +typedef struct +{ + void* ptr; + u32 len; + u32 unk; +}iovec_s; + +static void* allocIobuf() +{ + void* ptr = svcAlloc(0xCAFF, 0x828); + kernel_memset(ptr, 0x00, 0x828); + + return ptr; +} + +static void freeIobuf(void* ptr) +{ + svcFree(0xCAFF, ptr); +} + +static int IOS_Open(const char * dev, int mode) +{ + // put string into a good location + char* devStr = (char*)svcAlloc(0xCAFF, 0x20); + if(!devStr) + return -3; + + kernel_strncpy(devStr, dev, 0x20); + + int res = svcOpen(devStr, 0); + + svcFree(0xCAFF, devStr); + + return res; +} + +static int FSA_Open(void) +{ + return IOS_Open("/dev/fsa", 0); +} + +static int FSA_Close(int fd) +{ + return svcClose(fd); +} + +static int FSA_RawOpen(int fd, const char* device_path, int* outHandle) +{ + u8* iobuf = allocIobuf(); + u32* inbuf = (u32*)iobuf; + u32* outbuf = (u32*)&iobuf[0x520]; + + kernel_strncpy((char*)&inbuf[0x01], device_path, 0x27F); + + int ret = svcIoctl(fd, 0x6A, inbuf, 0x520, outbuf, 0x293); + + if(outHandle) *outHandle = outbuf[1]; + + freeIobuf(iobuf); + return ret; +} + +static int FSA_RawClose(int fd, int device_handle) +{ + u8* iobuf = allocIobuf(); + u32* inbuf = (u32*)iobuf; + u32* outbuf = (u32*)&iobuf[0x520]; + + inbuf[1] = device_handle; + + int ret = svcIoctl(fd, 0x6D, inbuf, 0x520, outbuf, 0x293); + + freeIobuf(iobuf); + return ret; +} + +static int FSA_RawRead(int fd, void* data, u32 size_bytes, u32 cnt, u64 blocks_offset, int device_handle) +{ + u8* iobuf = allocIobuf(); + u8* inbuf8 = iobuf; + u8* outbuf8 = &iobuf[0x520]; + iovec_s* iovec = (iovec_s*)&iobuf[0x7C0]; + u32* inbuf = (u32*)inbuf8; + u32* outbuf = (u32*)outbuf8; + + // note : offset_bytes = blocks_offset * size_bytes + inbuf[0x08 / 4] = (blocks_offset >> 32); + inbuf[0x0C / 4] = (blocks_offset & 0xFFFFFFFF); + inbuf[0x10 / 4] = cnt; + inbuf[0x14 / 4] = size_bytes; + inbuf[0x18 / 4] = device_handle; + + iovec[0].ptr = inbuf; + iovec[0].len = 0x520; + + iovec[1].ptr = data; + iovec[1].len = size_bytes * cnt; + + iovec[2].ptr = outbuf; + iovec[2].len = 0x293; + + int ret = svcIoctlv(fd, 0x6B, 1, 2, iovec); + + freeIobuf(iobuf); + return ret; +} + +static int FSA_RawWrite(int fd, void* data, u32 size_bytes, u32 cnt, u64 blocks_offset, int device_handle) +{ + u8* iobuf = allocIobuf(); + u8* inbuf8 = iobuf; + u8* outbuf8 = &iobuf[0x520]; + iovec_s* iovec = (iovec_s*)&iobuf[0x7C0]; + u32* inbuf = (u32*)inbuf8; + u32* outbuf = (u32*)outbuf8; + + inbuf[0x08 / 4] = (blocks_offset >> 32); + inbuf[0x0C / 4] = (blocks_offset & 0xFFFFFFFF); + inbuf[0x10 / 4] = cnt; + inbuf[0x14 / 4] = size_bytes; + inbuf[0x18 / 4] = device_handle; + + iovec[0].ptr = inbuf; + iovec[0].len = 0x520; + + iovec[1].ptr = data; + iovec[1].len = size_bytes * cnt; + + iovec[2].ptr = outbuf; + iovec[2].len = 0x293; + + int ret = svcIoctlv(fd, 0x6C, 2, 1, iovec); + + freeIobuf(iobuf); + return ret; +} + +int FSA_SDReadRawSectors(void *buffer, u32 sector, u32 num_sectors) +{ + int fsa = FSA_Open(); + if(fsa < 0) + return fsa; + + int fd; + int res = FSA_RawOpen(fsa, "/dev/sdcard01", &fd); + if(res < 0) + { + FSA_Close(fsa); + return res; + } + + void *buf = svcAllocAlign(0xCAFF, num_sectors << 9, 0x40); + if(!buf) + { + FSA_RawClose(fsa, fd); + FSA_Close(fsa); + return -2; + } + + res = FSA_RawRead(fsa, buf, 0x200, num_sectors, sector, fd); + + svcFree(0xCAFF, buf); + FSA_RawClose(fsa, fd); + FSA_Close(fsa); + + kernel_memcpy(buffer, buf, num_sectors << 9); + return res; +} + +int FSA_SDWriteRawSectors(const void *buffer, u32 sector, u32 num_sectors) +{ + int fsa = FSA_Open(); + if(fsa < 0) + return fsa; + + int fd; + int res = FSA_RawOpen(fsa, "/dev/sdcard01", &fd); + if(res < 0) + { + FSA_Close(fsa); + return res; + } + + void *buf = svcAllocAlign(0xCAFF, num_sectors << 9, 0x40); + if(!buf) + { + FSA_RawClose(fsa, fd); + FSA_Close(fsa); + return -2; + } + + kernel_memcpy(buf, buffer, num_sectors << 9); + + res = FSA_RawWrite(fsa, buf, 0x200, num_sectors, sector, fd); + + svcFree(0xCAFF, buf); + FSA_RawClose(fsa, fd); + FSA_Close(fsa); + + return res; +} + diff --git a/ios_kernel/source/fsa.h b/ios_kernel/source/fsa.h new file mode 100644 index 0000000..cec4af2 --- /dev/null +++ b/ios_kernel/source/fsa.h @@ -0,0 +1,55 @@ +/*************************************************************************** + * Copyright (C) 2016 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef FSA_H +#define FSA_H + +#include "types.h" + +#define NAND_DUMP_SIGNATURE_SECTOR 0x01 + +#define NAND_DUMP_SIGNATURE 0x4841585844554d50ULL // HAXXDUMP + +#define NAND_DESC_TYPE_SLC 0x534c4320 // 'SLC ' +#define NAND_DESC_TYPE_SLCCMPT 0x534c4332 // 'SLC2' +#define NAND_DESC_TYPE_MLC 0x4d4c4320 // 'MLC ' +#define NAND_DESC_TYPE_OTP 0x4f545020 // 'OTP ' +#define NAND_DESC_TYPE_SEEPROM 0x45455052 // 'EEPR' + +typedef struct _stdio_nand_desc_t +{ + u32 nand_type; // nand type + u32 base_sector; // base sector of dump + u32 sector_count; // sector count in SDIO sectors +} __attribute__((packed))stdio_nand_desc_t; + +typedef struct _sdio_nand_signature_sector_t +{ + u64 signature; // HAXXDUMP + stdio_nand_desc_t nand_descriptions[5]; +} __attribute__((packed)) sdio_nand_signature_sector_t; + +int FSA_SDReadRawSectors(void *buffer, u32 sector, u32 num_sectors); +int FSA_SDWriteRawSectors(const void *buffer, u32 sector, u32 num_sectors); + +#endif diff --git a/ios_kernel/source/ios_bsp_patches.c b/ios_kernel/source/ios_bsp_patches.c new file mode 100644 index 0000000..48a7fae --- /dev/null +++ b/ios_kernel/source/ios_bsp_patches.c @@ -0,0 +1,80 @@ +/*************************************************************************** + * Copyright (C) 2016 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include "types.h" +#include "elf_patcher.h" +#include "ios_bsp_patches.h" +#include "../../ios_bsp/ios_bsp_syms.h" +#include "fsa.h" +#include "utils.h" + +#define BSP_PHYS_DIFF (-0xE6000000 + 0x13CC0000) + +extern const patch_table_t fs_patches_table[]; +extern const patch_table_t fs_patches_table_end[]; + +u32 bsp_get_phys_code_base(void) +{ + return _text_start + BSP_PHYS_DIFF; +} + +int bsp_init_seeprom_buffer(u32 baseSector, int dumpFound) +{ + int(*disable_interrupts)() = (int(*)())0x0812E778; + int(*enable_interrupts)(int) = (int(*)(int))0x0812E78C; + + if(dumpFound) + { + int res = FSA_SDReadRawSectors((void*)0x00140000, baseSector, 1); + if(res < 0) + return res; + } + else + { + //! just clear out the seeprom and it will be re-initialized on BSP module + //! TODO: maybe read in the seeprom here from SPI or BSP module + kernel_memset((void*)0x00140000, 0, 0x200); + } + + int level = disable_interrupts(); + unsigned int control_register = disable_mmu(); + + kernel_memcpy((void*)(_seeprom_buffer_start - 0xE6047000 + 0x13D07000), (void*)0x00140000, 0x200); + + restore_mmu(control_register); + enable_interrupts(level); + + return 0; +} + +void bsp_run_patches(u32 ios_elf_start) +{ + section_write(ios_elf_start, _text_start, (void*)bsp_get_phys_code_base(), _text_end - _text_start); + section_write_bss(ios_elf_start, _bss_start, _bss_end - _bss_start); + + section_write(ios_elf_start, _seeprom_buffer_start, (void*)(_seeprom_buffer_start - 0xE6047000 + 0x13D07000), 0x200); + + section_write_word(ios_elf_start, 0xE600D08C, ARM_B(0xE600D08C, EEPROM_SPI_ReadWord)); + section_write_word(ios_elf_start, 0xE600D010, ARM_B(0xE600D010, EEPROM_SPI_WriteWord)); + section_write_word(ios_elf_start, 0xE600CF5C, ARM_B(0xE600CF5C, EEPROM_WriteControl)); +} diff --git a/ios_kernel/source/ios_bsp_patches.h b/ios_kernel/source/ios_bsp_patches.h new file mode 100644 index 0000000..02c2b0a --- /dev/null +++ b/ios_kernel/source/ios_bsp_patches.h @@ -0,0 +1,31 @@ +/*************************************************************************** + * Copyright (C) 2016 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef _BSP_PATCHES_H_ +#define _BSP_PATCHES_H_ + +u32 bsp_get_phys_code_base(void); +void bsp_run_patches(u32 ios_elf_start); +int bsp_init_seeprom_buffer(u32 baseSector, int dumpFound); + +#endif diff --git a/ios_kernel/source/ios_fs_patches.c b/ios_kernel/source/ios_fs_patches.c new file mode 100644 index 0000000..5576c65 --- /dev/null +++ b/ios_kernel/source/ios_fs_patches.c @@ -0,0 +1,84 @@ +/*************************************************************************** + * Copyright (C) 2016 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include "types.h" +#include "elf_patcher.h" +#include "ios_fs_patches.h" +#include "../../ios_fs/ios_fs_syms.h" + +#define FS_PHYS_DIFF 0 + +#define FS_SYSLOG_OUTPUT 0x107F0C84 +#define FS_PRINTF_SYSLOG 0x107F5720 +#define CALL_FS_REGISTERMDPHYSICALDEVICE 0x107BD81C +#define FS_GETMDDEVICEBYID 0x107187C4 +#define FS_CREATEDEVTHREAD_HOOK 0x10700294 +#define FS_USB_READ 0x1077F1C0 +#define FS_USB_WRITE 0x1077F35C +#define FS_SLC_READ1 0x107B998C +#define FS_SLC_READ2 0x107B98FC +#define FS_SLC_WRITE1 0x107B9870 +#define FS_SLC_WRITE2 0x107B97E4 +#define FS_MLC_READ1 0x107DC760 +#define FS_MLC_READ2 0x107DCDE4 +#define FS_MLC_WRITE1 0x107DC0C0 +#define FS_MLC_WRITE2 0x107DC73C +#define FS_SDCARD_READ1 0x107BDDD0 +#define FS_SDCARD_WRITE1 0x107BDD60 + +extern const patch_table_t fs_patches_table[]; +extern const patch_table_t fs_patches_table_end[]; + +u32 fs_get_phys_code_base(void) +{ + return _text_start + FS_PHYS_DIFF; +} + +void fs_run_patches(u32 ios_elf_start) +{ + // write wupserver code and bss + section_write(ios_elf_start, _text_start, (void*)fs_get_phys_code_base(), _text_end - _text_start); + section_write_bss(ios_elf_start, _bss_start, _bss_end - _bss_start); + + // patch FS logging + section_write_word(ios_elf_start, FS_PRINTF_SYSLOG, ARM_B(FS_PRINTF_SYSLOG, FS_SYSLOG_OUTPUT)); + + section_write_word(ios_elf_start, CALL_FS_REGISTERMDPHYSICALDEVICE, ARM_BL(CALL_FS_REGISTERMDPHYSICALDEVICE, registerMdDevice_hook)); + section_write_word(ios_elf_start, FS_GETMDDEVICEBYID + 8, ARM_BL((FS_GETMDDEVICEBYID + 8), getMdDeviceById_hook)); + + section_write_word(ios_elf_start, FS_SDCARD_READ1, ARM_B(FS_SDCARD_READ1, sdcardRead_patch)); + section_write_word(ios_elf_start, FS_SDCARD_WRITE1, ARM_B(FS_SDCARD_WRITE1, sdcardWrite_patch)); + + section_write_word(ios_elf_start, FS_SLC_READ1, ARM_B(FS_SLC_READ1, slcRead1_patch)); + section_write_word(ios_elf_start, FS_SLC_READ2, ARM_B(FS_SLC_READ2, slcRead2_patch)); + section_write_word(ios_elf_start, FS_SLC_WRITE1, ARM_B(FS_SLC_WRITE1, slcWrite1_patch)); + section_write_word(ios_elf_start, FS_SLC_WRITE2, ARM_B(FS_SLC_WRITE2, slcWrite2_patch)); + + //section_write_word(ios_elf_start, FS_USB_READ, ARM_B(FS_USB_READ, usbRead_patch)); + //section_write_word(ios_elf_start, FS_USB_WRITE, ARM_B(FS_USB_WRITE, usbWrite_patch)); + + section_write_word(ios_elf_start, FS_CREATEDEVTHREAD_HOOK, ARM_B(FS_CREATEDEVTHREAD_HOOK, createDevThread_hook)); + + u32 patch_count = (u32)(((u8*)fs_patches_table_end) - ((u8*)fs_patches_table)) / sizeof(patch_table_t); + patch_table_entries(ios_elf_start, fs_patches_table, patch_count); +} diff --git a/ios_kernel/source/ios_fs_patches.h b/ios_kernel/source/ios_fs_patches.h new file mode 100644 index 0000000..b3e71c6 --- /dev/null +++ b/ios_kernel/source/ios_fs_patches.h @@ -0,0 +1,30 @@ +/*************************************************************************** + * Copyright (C) 2016 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef _FS_PATCHES_H_ +#define _FS_PATCHES_H_ + +u32 fs_get_phys_code_base(void); +void fs_run_patches(u32 ios_elf_start); + +#endif diff --git a/ios_kernel/source/ios_fs_patches_asm.s b/ios_kernel/source/ios_fs_patches_asm.s new file mode 100644 index 0000000..83c2d0b --- /dev/null +++ b/ios_kernel/source/ios_fs_patches_asm.s @@ -0,0 +1,40 @@ +.arm + +# patch out sdcard deinitialization +patch_mdExit: + bx lr + +# patch out FSRawOpen access +patch_FSRawOpen: + streq r2, [r1, #0x70] + .word 0xEAFFFFF9 + +# nop out hmac memcmp +patch_hmac_check: + mov r0, #0 + +# null out references to slcSomething1 and slcSomething2 +# (nulling them out is apparently ok; more importantly, i'm not sure what they do and would rather get a crash than unwanted slc-writing) +slcSomething1: + .word 0x00000000 +slcSomething2: + .word 0x00000000 + +#syslogOutput_hook: +# push {r0,lr} +# bl dump_syslog +# pop {r0,lr} +# restore original instruction +# pop {r4-r8,r10,pc} + + +.globl fs_patches_table, fs_patches_table_end +fs_patches_table: +# origin data size + .word 0x107BD374, patch_mdExit, 4 + .word 0x1070FAE8, patch_FSRawOpen, 8 + .word 0x107B96B8, slcSomething1, 8 + .word 0x107206F0, patch_hmac_check, 4 +# .word 0x107F0B68, syslogOutput_hook, 4 +fs_patches_table_end: + diff --git a/ios_kernel/source/ios_mcp_patches.c b/ios_kernel/source/ios_mcp_patches.c new file mode 100644 index 0000000..b12e39e --- /dev/null +++ b/ios_kernel/source/ios_mcp_patches.c @@ -0,0 +1,57 @@ +/*************************************************************************** + * Copyright (C) 2016 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include "types.h" +#include "elf_patcher.h" +#include "config.h" +#include "ios_mcp_patches.h" +#include "../../ios_mcp/ios_mcp.bin.h" +#include "../../ios_mcp/ios_mcp_syms.h" + +#define MCP_CODE_BASE_PHYS_ADDR (-0x05100000 + 0x13D80000) + +extern const patch_table_t mcp_patches_table[]; +extern const patch_table_t mcp_patches_table_end[]; + +u32 mcp_get_phys_code_base(void) +{ + return _text_start + MCP_CODE_BASE_PHYS_ADDR; +} + +void mcp_run_patches(u32 ios_elf_start) +{ + // write ios_mcp code and bss + section_write_bss(ios_elf_start, _bss_start, _bss_end - _bss_start); + section_write(ios_elf_start, _text_start, (void*)mcp_get_phys_code_base(), _text_end - _text_start); + + section_write_word(ios_elf_start, 0x05056718, ARM_BL(0x05056718, _text_start)); + + if(cfw_config.syshaxXml) + { + section_write(ios_elf_start, 0x050600DC, "/vol/system/config/syshax.xml", 0x20); + section_write(ios_elf_start, 0x050600FC, "/vol/system_slc/config/syshax.xml", 0x24); + } + + u32 patch_count = (u32)(((u8*)mcp_patches_table_end) - ((u8*)mcp_patches_table)) / sizeof(patch_table_t); + patch_table_entries(ios_elf_start, mcp_patches_table, patch_count); +} diff --git a/ios_kernel/source/ios_mcp_patches.h b/ios_kernel/source/ios_mcp_patches.h new file mode 100644 index 0000000..803368d --- /dev/null +++ b/ios_kernel/source/ios_mcp_patches.h @@ -0,0 +1,32 @@ +/*************************************************************************** + * Copyright (C) 2016 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef _MCP_PATCHES_H_ +#define _MCP_PATCHES_H_ + +#define MCP_LAUNCH_IMG_PHYS_ADDR (0x27000000) + +u32 mcp_get_phys_code_base(void); +void mcp_run_patches(u32 ios_elf_start); + +#endif diff --git a/ios_kernel/source/ios_mcp_patches_asm.s b/ios_kernel/source/ios_mcp_patches_asm.s new file mode 100644 index 0000000..2b42c08 --- /dev/null +++ b/ios_kernel/source/ios_mcp_patches_asm.s @@ -0,0 +1,39 @@ +.arm + +#patch_os_launch_sig_check: +# .thumb +# mov r0, #0 +# mov r0, #0 + +patch_MCP_authentication_check: + .thumb + mov r0, #0 + bx lr + +patch_IOSC_VerifyPubkeySign: +patch_cert_verification: +patch_cached_cert_check: +patch_bootMovie_check: +patch_bootLogoTex_check: +patch_region_launch_check: + .arm + mov r0, #0 + bx lr + + +.globl mcp_patches_table, mcp_patches_table_end +mcp_patches_table: +# origin data size +# .word 0x0500A818, patch_os_launch_sig_check, 4 + .word 0x05014CAC, patch_MCP_authentication_check, 4 + .word 0x05052C44, patch_IOSC_VerifyPubkeySign, 8 + .word 0x05052A90, patch_cert_verification, 8 + .word 0x05054D6C, patch_cached_cert_check, 8 +# over an hour, MCP crash prevention + .word 0x05022474, 0xFFFFFFFF, 4 +# MCP patches end here actually but lets tread the ACP patches as MCP as there are only patches + .word 0xE0030D68, patch_bootMovie_check, 4 + .word 0xE0030D34, patch_bootLogoTex_check, 4 + .word 0xE0030498, patch_region_launch_check, 4 +mcp_patches_table_end: + diff --git a/ios_kernel/source/kernel_patches.c b/ios_kernel/source/kernel_patches.c new file mode 100644 index 0000000..ea49b64 --- /dev/null +++ b/ios_kernel/source/kernel_patches.c @@ -0,0 +1,108 @@ +/*************************************************************************** + * Copyright (C) 2016 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include "types.h" +#include "elf_patcher.h" +#include "kernel_patches.h" +#include "exception_handler.h" +#include "fsa.h" +#include "config.h" +#include "utils.h" + +extern void __KERNEL_CODE_START(void); +extern void __KERNEL_CODE_END(void); + +extern const patch_table_t kernel_patches_table[]; +extern const patch_table_t kernel_patches_table_end[]; + +static u8 otp_buffer[0x400]; + +static const u32 mcpIoMappings_patch[] = +{ + // vaddr paddr size ? ? ? + 0x0D000000, 0x0D000000, 0x001C0000, 0x00000000, 0x00000003, 0x00000000, // mapping 1 + 0x0D800000, 0x0D800000, 0x001C0000, 0x00000000, 0x00000003, 0x00000000, // mapping 2 + 0x0C200000, 0x0C200000, 0x00100000, 0x00000000, 0x00000003, 0x00000000 // mapping 3 +}; + +static const u32 KERNEL_MCP_IOMAPPINGS_STRUCT[] = +{ + (u32)mcpIoMappings_patch, // ptr to iomapping structs + 0x00000003, // number of iomappings + 0x00000001 // pid (MCP) +}; + +static u32 kernel_syscall_0x81(u32 address) +{ + return *(volatile u32*)address; +} + +static int kernel_read_otp_internal(int index, void* out_buf, u32 size) +{ + kernel_memcpy(out_buf, otp_buffer + (index << 2), size); + return 0; +} + +int kernel_init_otp_buffer(u32 sd_sector, int tagValid) +{ + int res; + + if(tagValid) + { + res = FSA_SDReadRawSectors(otp_buffer, sd_sector, 2); + } + else + { + int (*orig_kernel_read_otp_internal)(int index, void* out_buf, u32 size) = (void*)0x08120248; + res = orig_kernel_read_otp_internal(0, otp_buffer, 0x400); + } + + if((res == 0) && !tagValid) + { + FSA_SDWriteRawSectors(otp_buffer, sd_sector, 2); + } + return res; +} + +void kernel_run_patches(u32 ios_elf_start) +{ + section_write(ios_elf_start, (u32)__KERNEL_CODE_START, __KERNEL_CODE_START, __KERNEL_CODE_END - __KERNEL_CODE_START); + section_write_word(ios_elf_start, 0x0812A120, ARM_BL(0x0812A120, kernel_launch_ios)); + + section_write(ios_elf_start, 0x08140DE0, KERNEL_MCP_IOMAPPINGS_STRUCT, sizeof(KERNEL_MCP_IOMAPPINGS_STRUCT)); + + section_write_word(ios_elf_start, 0x0812A134, ARM_BL(0x0812A134, crash_handler_prefetch)); + section_write_word(ios_elf_start, 0x0812A1AC, ARM_BL(0x0812A1AC, crash_handler_data)); + section_write_word(ios_elf_start, 0x08129E50, ARM_BL(0x08129E50, crash_handler_undef_instr)); + + section_write_word(ios_elf_start, 0x0812CD2C, ARM_B(0x0812CD2C, kernel_syscall_0x81)); + + if(cfw_config.redNAND && cfw_config.otp_red) + { + section_write(ios_elf_start, (u32)otp_buffer, otp_buffer, 0x400); + section_write_word(ios_elf_start, 0x08120248, ARM_B(0x08120248, kernel_read_otp_internal)); + } + + u32 patch_count = (u32)(((u8*)kernel_patches_table_end) - ((u8*)kernel_patches_table)) / sizeof(patch_table_t); + patch_table_entries(ios_elf_start, kernel_patches_table, patch_count); +} diff --git a/ios_kernel/source/kernel_patches.h b/ios_kernel/source/kernel_patches.h new file mode 100644 index 0000000..c04e6aa --- /dev/null +++ b/ios_kernel/source/kernel_patches.h @@ -0,0 +1,31 @@ +/*************************************************************************** + * Copyright (C) 2016 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef _KERNEL_PATCHES_H +#define _KERNEL_PATCHES_H + +int kernel_init_otp_buffer(u32 sd_sector, int tagValid); +void kernel_launch_ios(u32 launch_address, u32 L, u32 C, u32 H); +void kernel_run_patches(u32 ios_elf_start); + +#endif diff --git a/ios_kernel/source/kernel_patches_asm.s b/ios_kernel/source/kernel_patches_asm.s new file mode 100644 index 0000000..85bd157 --- /dev/null +++ b/ios_kernel/source/kernel_patches_asm.s @@ -0,0 +1,17 @@ +.arm +.align 4 +patch_kernel_domains: + str r3, [r7,#0x10] + str r3, [r7,#0x0C] + str r3, [r7,#0x04] + str r3, [r7,#0x14] + str r3, [r7,#0x08] + str r3, [r7,#0x34] +patch_kernel_domains_end: + +.globl kernel_patches_table, kernel_patches_table_end +kernel_patches_table: +# origin data size + .word 0x081253C4, patch_kernel_domains, (kernel_patches_table_end - kernel_patches_table) +kernel_patches_table_end: + diff --git a/ios_kernel/source/main.c b/ios_kernel/source/main.c new file mode 100644 index 0000000..eb8a2d6 --- /dev/null +++ b/ios_kernel/source/main.c @@ -0,0 +1,246 @@ +/*************************************************************************** + * Copyright (C) 2016 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include "types.h" +#include "elf_abi.h" +#include "elf_patcher.h" +#include "kernel_patches.h" +#include "ios_mcp_patches.h" +#include "ios_fs_patches.h" +#include "ios_bsp_patches.h" +#include "config.h" +#include "fsa.h" +#include "utils.h" + +#define USB_PHYS_CODE_BASE 0x101312D0 + +cfw_config_t cfw_config; + +typedef struct +{ + u32 size; + u8 data[0]; +} payload_info_t; + +static const char repairData_set_fault_behavior[] = { + 0xE1,0x2F,0xFF,0x1E,0xE9,0x2D,0x40,0x30,0xE5,0x93,0x20,0x00,0xE1,0xA0,0x40,0x00, + 0xE5,0x92,0x30,0x54,0xE1,0xA0,0x50,0x01,0xE3,0x53,0x00,0x01,0x0A,0x00,0x00,0x02, + 0xE1,0x53,0x00,0x00,0xE3,0xE0,0x00,0x00,0x18,0xBD,0x80,0x30,0xE3,0x54,0x00,0x0D, +}; +static const char repairData_set_panic_behavior[] = { + 0x08,0x16,0x6C,0x00,0x00,0x00,0x18,0x0C,0x08,0x14,0x40,0x00,0x00,0x00,0x9D,0x70, + 0x08,0x16,0x84,0x0C,0x00,0x00,0xB4,0x0C,0x00,0x00,0x01,0x01,0x08,0x14,0x40,0x00, + 0x08,0x15,0x00,0x00,0x08,0x17,0x21,0x80,0x08,0x17,0x38,0x00,0x08,0x14,0x30,0xD4, + 0x08,0x14,0x12,0x50,0x08,0x14,0x12,0x94,0xE3,0xA0,0x35,0x36,0xE5,0x93,0x21,0x94, + 0xE3,0xC2,0x2E,0x21,0xE5,0x83,0x21,0x94,0xE5,0x93,0x11,0x94,0xE1,0x2F,0xFF,0x1E, + 0xE5,0x9F,0x30,0x1C,0xE5,0x9F,0xC0,0x1C,0xE5,0x93,0x20,0x00,0xE1,0xA0,0x10,0x00, + 0xE5,0x92,0x30,0x54,0xE5,0x9C,0x00,0x00, +}; +static const char repairData_usb_root_thread[] = { + 0xE5,0x8D,0xE0,0x04,0xE5,0x8D,0xC0,0x08,0xE5,0x8D,0x40,0x0C,0xE5,0x8D,0x60,0x10, + 0xEB,0x00,0xB2,0xFD,0xEA,0xFF,0xFF,0xC9,0x10,0x14,0x03,0xF8,0x10,0x62,0x4D,0xD3, + 0x10,0x14,0x50,0x00,0x10,0x14,0x50,0x20,0x10,0x14,0x00,0x00,0x10,0x14,0x00,0x90, + 0x10,0x14,0x00,0x70,0x10,0x14,0x00,0x98,0x10,0x14,0x00,0x84,0x10,0x14,0x03,0xE8, + 0x10,0x14,0x00,0x3C,0x00,0x00,0x01,0x73,0x00,0x00,0x01,0x76,0xE9,0x2D,0x4F,0xF0, + 0xE2,0x4D,0xDE,0x17,0xEB,0x00,0xB9,0x92,0xE3,0xA0,0x10,0x00,0xE3,0xA0,0x20,0x03, + 0xE5,0x9F,0x0E,0x68,0xEB,0x00,0xB3,0x20, +}; + +void kernel_launch_ios(u32 launch_address, u32 L, u32 C, u32 H) +{ + void (*kernel_launch_bootrom)(u32 launch_address, u32 L, u32 C, u32 H) = (void*)0x0812A050; + + if(*(u32*)(launch_address - 0x300 + 0x1AC) == 0x00DFD000) + { + int(*disable_interrupts)() = (int(*)())0x0812E778; + int(*enable_interrupts)(int) = (int(*)(int))0x0812E78C; + + int level = disable_interrupts(); + unsigned int control_register = disable_mmu(); + + u32 ios_elf_start = launch_address + 0x804 - 0x300; + + //! try to keep the order of virt. addresses to reduce the memmove amount + mcp_run_patches(ios_elf_start); + kernel_run_patches(ios_elf_start); + + if(cfw_config.redNAND) + { + fs_run_patches(ios_elf_start); + + if(cfw_config.seeprom_red) + bsp_run_patches(ios_elf_start); + } + + restore_mmu(control_register); + enable_interrupts(level); + } + + kernel_launch_bootrom(launch_address, L, C, H); +} + + +int BSP_EEPROM_ReadData(void *buffer, int offset, int size); + +int _main() +{ + int(*disable_interrupts)() = (int(*)())0x0812E778; + int(*enable_interrupts)(int) = (int(*)(int))0x0812E78C; + void(*invalidate_icache)() = (void(*)())0x0812DCF0; + void(*invalidate_dcache)(unsigned int, unsigned int) = (void(*)())0x08120164; + void(*flush_dcache)(unsigned int, unsigned int) = (void(*)())0x08120160; + + flush_dcache(0x081200F0, 0x4001); // giving a size >= 0x4000 flushes all cache + + int level = disable_interrupts(); + + unsigned int control_register = disable_mmu(); + + /* Save the request handle so we can reply later */ + *(volatile u32*)0x0012F000 = *(volatile u32*)0x1016AD18; + + /* Patch kernel_error_handler to BX LR immediately */ + *(volatile u32*)0x08129A24 = 0xE12FFF1E; + + void * pset_fault_behavior = (void*)0x081298BC; + kernel_memcpy(pset_fault_behavior, (void*)repairData_set_fault_behavior, sizeof(repairData_set_fault_behavior)); + + void * pset_panic_behavior = (void*)0x081296E4; + kernel_memcpy(pset_panic_behavior, (void*)repairData_set_panic_behavior, sizeof(repairData_set_panic_behavior)); + + void * pusb_root_thread = (void*)0x10100174; + kernel_memcpy(pusb_root_thread, (void*)repairData_usb_root_thread, sizeof(repairData_usb_root_thread)); + + payload_info_t *payloads = (payload_info_t*)0x00148000; + + kernel_memcpy((void*)&cfw_config, payloads->data, payloads->size); + payloads = (payload_info_t*)( ((char*)payloads) + ALIGN4(sizeof(payload_info_t) + payloads->size) ); + + kernel_memcpy((void*)USB_PHYS_CODE_BASE, payloads->data, payloads->size); + payloads = (payload_info_t*)( ((char*)payloads) + ALIGN4(sizeof(payload_info_t) + payloads->size) ); + + if(cfw_config.redNAND) + { + kernel_memcpy((void*)fs_get_phys_code_base(), payloads->data, payloads->size); + payloads = (payload_info_t*)( ((char*)payloads) + ALIGN4(sizeof(payload_info_t) + payloads->size) ); + + if(cfw_config.seeprom_red) + { + kernel_memcpy((void*)bsp_get_phys_code_base(), payloads->data, payloads->size); + payloads = (payload_info_t*)( ((char*)payloads) + ALIGN4(sizeof(payload_info_t) + payloads->size) ); + } + } + + kernel_memcpy((void*)mcp_get_phys_code_base(), payloads->data, payloads->size); + payloads = (payload_info_t*)( ((char*)payloads) + ALIGN4(sizeof(payload_info_t) + payloads->size) ); + + if(cfw_config.launchImage) + { + kernel_memcpy((void*)MCP_LAUNCH_IMG_PHYS_ADDR, payloads->data, payloads->size); + payloads = (payload_info_t*)( ((char*)payloads) + ALIGN4(sizeof(payload_info_t) + payloads->size) ); + } + else + { + *(u32*)MCP_LAUNCH_IMG_PHYS_ADDR = 0; + } + + // patch FSA raw access + *(volatile u32*)0x1070FAE8 = 0x05812070; + *(volatile u32*)0x1070FAEC = 0xEAFFFFF9; + + *(volatile u32*)0x0812A120 = ARM_BL(0x0812A120, kernel_launch_ios); + *(volatile u32*)(0x1555500) = 0; + + /* REENABLE MMU */ + restore_mmu(control_register); + + invalidate_dcache(0x081298BC, 0x4001); // giving a size >= 0x4000 invalidates all cache + invalidate_icache(); + + enable_interrupts(level); + + if(cfw_config.redNAND) + { + int seepromDumpFound = 0; + u32 seepromDumpBaseSector = 0x4FF; + int otpDumpFound = 0; + u32 otpDumpBaseSector = 0x4FD; + int writeInfoSector = 0; + sdio_nand_signature_sector_t *infoSector = (sdio_nand_signature_sector_t*)0x00141000; + kernel_memset(infoSector, 0x00, 0x200); + + FSA_SDReadRawSectors(infoSector, NAND_DUMP_SIGNATURE_SECTOR, 1); + + if(infoSector->signature == NAND_DUMP_SIGNATURE) + { + int i; + for(i = 0; i < 6; i++) + { + if(infoSector->nand_descriptions[i].nand_type == NAND_DESC_TYPE_SEEPROM) + { + seepromDumpFound = 1; + seepromDumpBaseSector = infoSector->nand_descriptions[i].base_sector; + } + if(infoSector->nand_descriptions[i].nand_type == NAND_DESC_TYPE_OTP) + { + otpDumpFound = 1; + otpDumpBaseSector = infoSector->nand_descriptions[i].base_sector; + } + } + } + + if(cfw_config.seeprom_red) + { + bsp_init_seeprom_buffer(seepromDumpBaseSector, seepromDumpFound); + + if(seepromDumpBaseSector == 0) + { + infoSector->nand_descriptions[3].nand_type = NAND_DESC_TYPE_SEEPROM; + infoSector->nand_descriptions[3].base_sector = seepromDumpBaseSector; + infoSector->nand_descriptions[3].sector_count = 1; + writeInfoSector++; + } + } + + if(cfw_config.otp_red) + { + kernel_init_otp_buffer(otpDumpBaseSector, otpDumpFound); + + if(otpDumpFound == 0) + { + infoSector->nand_descriptions[4].nand_type = NAND_DESC_TYPE_OTP; + infoSector->nand_descriptions[4].base_sector = otpDumpBaseSector; + infoSector->nand_descriptions[4].sector_count = 2; + writeInfoSector++; + } + } + + + if(writeInfoSector > 1) + { + FSA_SDWriteRawSectors(infoSector, NAND_DUMP_SIGNATURE_SECTOR, 1); + } + } + + return 0; +} diff --git a/ios_kernel/source/text.c b/ios_kernel/source/text.c new file mode 100644 index 0000000..0b7d99b --- /dev/null +++ b/ios_kernel/source/text.c @@ -0,0 +1,96 @@ +#include +#include +#include +#include + +#include "types.h" +#include "font_bin.h" + +#define FRAMEBUFFER_ADDRESS (0x14000000+0x38C0000) +#define FRAMEBUFFER_STRIDE (0xE00) +#define FRAMEBUFFER_STRIDE_WORDS (FRAMEBUFFER_STRIDE >> 2) + +#define CHAR_MULT 2 +#define CHAR_SIZE_X 8 +#define CHAR_SIZE_Y 8 + + +u32* const framebuffer = (u32*)FRAMEBUFFER_ADDRESS; + +void clearScreen(u32 color) +{ + int i; + for(i = 0; i < 896 * 504; i++) + { + framebuffer[i] = color; + } +} + +void drawCharacter(char c, int x, int y) +{ + if(c < 32)return; + c -= 32; + u8* charData = (u8*)&font_bin[(int)c << 3]; + u32* fb = &framebuffer[x + y * FRAMEBUFFER_STRIDE_WORDS]; + int i, j, n, k; + for(i = 0; i < CHAR_SIZE_Y; i++) + { + for(k = 0; k < CHAR_MULT; k++) + { + u8 v = *charData; + + for(j = 0; j < CHAR_SIZE_X; j++) + { + for(n = 0; n < CHAR_MULT; n++) + { + if(v & 1) + { + *fb = 0x00000000; + } + else + { + *fb = 0xFFFFFFFF; + } + fb++; + } + v >>= 1; + } + fb += FRAMEBUFFER_STRIDE_WORDS - CHAR_SIZE_X * CHAR_MULT; + } + charData++; + } +} + +void drawString(char* str, int x, int y) +{ + if(!str) return; + int k; + int dx = 0, dy = 0; + for(k = 0; str[k]; k++) + { + if(str[k] >= 32 && str[k] < 128) + drawCharacter(str[k], x + dx, y + dy); + + dx += CHAR_SIZE_X * CHAR_MULT; + + if(str[k] == '\n') + { + dx = 0; + dy -= CHAR_SIZE_Y * CHAR_MULT; + } + } +} + +void _printf(int x, int y, const char *format, ...) +{ + void (*kernel_vsnprintf)(char * s, size_t n, const char * format, va_list arg) = (void*)0x0813293C; + + va_list args; + va_start(args, format); + static char buffer[0x100]; + + kernel_vsnprintf(buffer, 0xFF, format, args); + drawString(buffer, x, y); + + va_end(args); +} diff --git a/ios_kernel/source/text.h b/ios_kernel/source/text.h new file mode 100644 index 0000000..816db49 --- /dev/null +++ b/ios_kernel/source/text.h @@ -0,0 +1,11 @@ +#ifndef TEXT_H +#define TEXT_H + +#include "types.h" + +void drawSplashScreen(void); +void clearScreen(u32 color); +void drawString(char* str, int x, int y); +void _printf(int x, int y, const char *format, ...); + +#endif diff --git a/ios_kernel/source/types.h b/ios_kernel/source/types.h new file mode 100644 index 0000000..5d8eced --- /dev/null +++ b/ios_kernel/source/types.h @@ -0,0 +1,16 @@ +#ifndef _TYPES_H +#define _TYPES_H + +#include + +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef uint64_t u64; + +typedef int8_t s8; +typedef int16_t s16; +typedef int32_t s32; +typedef int64_t s64; + +#endif diff --git a/ios_kernel/source/utils.c b/ios_kernel/source/utils.c new file mode 100644 index 0000000..8ce65ae --- /dev/null +++ b/ios_kernel/source/utils.c @@ -0,0 +1,92 @@ +/*************************************************************************** + * Copyright (C) 2016 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ + +// this memcpy is optimized for speed and to work with MEM1 32 bit access alignment requirement +void reverse_memcpy(void* dst, const void* src, unsigned int size) +{ + const unsigned char *src_p; + unsigned char *dst_p; + + if((size >= 4) && !((dst - src) & 3)) + { + const unsigned int *src_p32; + unsigned int *dst_p32; + unsigned int endDst = ((unsigned int)dst) + size; + unsigned int endRest = endDst & 3; + + if(endRest) + { + src_p = ((const unsigned char*)(src + size)) - 1; + dst_p = ((unsigned char*)endDst) - 1; + size -= endRest; + + while(endRest--) + *dst_p-- = *src_p--; + } + + src_p32 = ((const unsigned int*)(src + size)) - 1; + dst_p32 = ((unsigned int*)(dst + size)) - 1; + + unsigned int size32 = size >> 5; + if(size32) + { + size &= 0x1F; + + while(size32--) + { + src_p32 -= 8; + dst_p32 -= 8; + + dst_p32[8] = src_p32[8]; + dst_p32[7] = src_p32[7]; + dst_p32[6] = src_p32[6]; + dst_p32[5] = src_p32[5]; + dst_p32[4] = src_p32[4]; + dst_p32[3] = src_p32[3]; + dst_p32[2] = src_p32[2]; + dst_p32[1] = src_p32[1]; + } + } + + unsigned int size4 = size >> 2; + if(size4) + { + size &= 3; + + while(size4--) + *dst_p32-- = *src_p32--; + } + + dst_p = ((unsigned char*)dst_p32) + 3; + src_p = ((const unsigned char*)src_p32) + 3; + } + else + { + dst_p = ((unsigned char*)dst) + size - 1; + src_p = ((const unsigned char*)src) + size - 1; + } + + while(size--) + *dst_p-- = *src_p--; +} diff --git a/ios_kernel/source/utils.h b/ios_kernel/source/utils.h new file mode 100644 index 0000000..47a2a71 --- /dev/null +++ b/ios_kernel/source/utils.h @@ -0,0 +1,49 @@ +/*************************************************************************** + * Copyright (C) 2016 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef _UTILS_H +#define _UTILS_H + +#define ALIGN4(x) (((x) + 3) & ~3) + +#define kernel_memcpy ((void * (*)(void*, const void*, int))0x08131D04) +#define kernel_memset ((void *(*)(void*, int, unsigned int))0x08131DA0) +#define kernel_strncpy ((char *(*)(char*, const char*, unsigned int))0x081329B8) +#define kernel_bsp_command_5 ((int (*)(const char*, int offset, const char*, int size, void *buffer))0x0812EC40) + +void reverse_memcpy(void* dest, const void* src, unsigned int size); + +static inline unsigned int disable_mmu(void) +{ + unsigned int control_register = 0; + asm volatile("MRC p15, 0, %0, c1, c0, 0" : "=r" (control_register)); + asm volatile("MCR p15, 0, %0, c1, c0, 0" : : "r" (control_register & 0xFFFFEFFA)); + return control_register; +} + +static inline void restore_mmu(unsigned int control_register) +{ + asm volatile("MCR p15, 0, %0, c1, c0, 0" : : "r" (control_register)); +} + +#endif diff --git a/ios_mcp/Makefile b/ios_mcp/Makefile new file mode 100644 index 0000000..083d180 --- /dev/null +++ b/ios_mcp/Makefile @@ -0,0 +1,80 @@ +ifeq ($(strip $(DEVKITARM)),) +$(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") +endif + +ifeq ($(filter $(DEVKITARM)/bin,$(PATH)),) +export PATH:=$(DEVKITARM)/bin:$(PATH) +endif + +CC = arm-none-eabi-gcc +LINK = arm-none-eabi-gcc +AS = arm-none-eabi-as +OBJCOPY = arm-none-eabi-objcopy +OBJDUMP = arm-none-eabi-objdump +CFLAGS += -Wall -mbig-endian -std=gnu11 -mcpu=arm926ej-s -msoft-float -mfloat-abi=soft -Os +LDFLAGS += -nostartfiles -nodefaultlibs -mbig-endian -Wl,-T,link.ld +LIBDIRS += -L$(CURDIR)/../libs +LIBS += -lgcc + +CFILES = $(wildcard source/*.c) +BINFILES = $(wildcard data/*.bin) +OFILES = $(BINFILES:data/%.bin=build/%.bin.o) +OFILES += $(CFILES:source/%.c=build/%.o) +DFILES = $(CFILES:source/%.c=build/%.d) +SFILES = $(wildcard source/*.s) +OFILES += $(SFILES:source/%.s=build/%.o) +PROJECTNAME = ${shell basename "$(CURDIR)"} +CWD = "$(CURDIR)"" + +#--------------------------------------------------------------------------------- +# canned command sequence for binary data, taken from devkitARM +#--------------------------------------------------------------------------------- +define bin2o + bin2s $< | $(AS) -EB -o $(@) +endef + +.PHONY:=all dirs + +all: dirs $(PROJECTNAME).bin $(PROJECTNAME)_syms.h $(PROJECTNAME).bin $(PROJECTNAME).bin.h + +dirs: + @mkdir -p build + +$(PROJECTNAME).elf: $(OFILES) + @echo "LD $@" + @$(LINK) $(LDFLAGS) -o $(PROJECTNAME).elf $(sort $(filter-out build/crt0.o, $(OFILES))) $(LIBDIRS) $(LIBS) + +$(PROJECTNAME).bin: $(PROJECTNAME).elf + @echo "OBJCOPY $@\n" + @$(OBJCOPY) -j .text -j .rodata -j .data -O binary $(PROJECTNAME).elf $@ + +$(PROJECTNAME).bin.h: $(PROJECTNAME).bin + @xxd -i $< | sed "s/unsigned/static const unsigned/g;s/$(PROJECTNAME)$*/$(PROJECTNAME)/g" > $@ + +$(PROJECTNAME)_syms.h: + @echo "#ifndef $(PROJECTNAME)_SYMS_H" > $@ + @echo "#define $(PROJECTNAME)_SYMS_H" >> $@ + @$(OBJDUMP) -EB -t -marm $(PROJECTNAME).elf | grep 'g F .text' | grep -v '.hidden' | awk '{print "#define " $$6 " 0x" $$1}' >> $@ + @$(OBJDUMP) -EB -t -marm $(PROJECTNAME).elf | grep -e 'g .text' -e '_bss_' | awk '{print "#define " $$5 " 0x" $$1}' >> $@ + @echo "#endif" >> $@ + +clean: + @rm -f build/*.o build/*.d + @rm -f $(PROJECTNAME).elf $(PROJECTNAME).bin $(PROJECTNAME)_syms.h $(PROJECTNAME).bin $(PROJECTNAME).bin.h + @echo "all cleaned up !" + +-include $(DFILES) + +build/%.o: source/%.c + @echo "CC $(notdir $<)" + @$(CC) $(CFLAGS) -c $< -o $@ + @$(CC) -MM $< > build/$*.d + +build/%.o: source/%.s + @echo "CC $(notdir $<)" + @$(CC) $(CFLAGS) -xassembler-with-cpp -c $< -o $@ + @$(CC) -MM $< > build/$*.d + +build/%.bin.o: data/%.bin + @echo "BIN $(notdir $<)" + @$(bin2o) diff --git a/ios_mcp/link.ld b/ios_mcp/link.ld new file mode 100644 index 0000000..89a76a1 --- /dev/null +++ b/ios_mcp/link.ld @@ -0,0 +1,23 @@ +OUTPUT_ARCH(arm) + +SECTIONS +{ + .text 0x05116000 : { + _text_start = .; + build/crt0.o(.init) + *(.text*) + *(.rodata*) + } + _text_end = .; + + .bss 0x050BE000 : { + _bss_start = .; + *(.bss*); + } + _bss_end = .; + + /DISCARD/ : { + *(*); + } +} + diff --git a/ios_mcp/source/crt0.s b/ios_mcp/source/crt0.s new file mode 100644 index 0000000..7874223 --- /dev/null +++ b/ios_mcp/source/crt0.s @@ -0,0 +1,14 @@ +.section ".init" +.arm +.align 4 + +.extern _startMainThread +.type _startMainThread, %function + +mcpMainThread_hook: + mov r11, r0 + push {r0-r11,lr} + + bl _startMainThread + + pop {r0-r11,pc} diff --git a/ios_mcp/source/font.c b/ios_mcp/source/font.c new file mode 100644 index 0000000..91aef28 --- /dev/null +++ b/ios_mcp/source/font.c @@ -0,0 +1,49 @@ +const unsigned char font_bin[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x18, 0x18, 0x00, 0x0C, 0x00, + 0x00, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0xFF, 0x66, 0xFF, 0x66, 0x66, + 0x00, 0x18, 0x7C, 0x06, 0x3C, 0x60, 0x3E, 0x18, 0x10, 0x46, 0x66, 0x30, 0x18, 0x0C, 0x66, 0x62, + 0x00, 0x3C, 0x66, 0x3C, 0x1C, 0xE6, 0x66, 0xFC, 0x00, 0x18, 0x0C, 0x06, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x30, 0x18, 0x0C, 0x0C, 0x18, 0x30, 0x00, 0x00, 0x0C, 0x18, 0x30, 0x30, 0x18, 0x0C, 0x00, + 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x40, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x00, + 0x00, 0x3C, 0x66, 0x76, 0x6E, 0x66, 0x3C, 0x00, 0x00, 0x18, 0x1C, 0x18, 0x18, 0x18, 0x7E, 0x00, + 0x00, 0x3C, 0x62, 0x30, 0x0C, 0x06, 0x7E, 0x00, 0x00, 0x3C, 0x62, 0x38, 0x60, 0x66, 0x3C, 0x00, + 0x00, 0x6C, 0x6C, 0x66, 0xFE, 0x60, 0x60, 0x00, 0x00, 0x7E, 0x06, 0x7E, 0x60, 0x66, 0x3C, 0x00, + 0x00, 0x3C, 0x06, 0x3E, 0x66, 0x66, 0x3C, 0x00, 0x00, 0x7E, 0x30, 0x30, 0x18, 0x18, 0x18, 0x00, + 0x00, 0x3C, 0x66, 0x3C, 0x66, 0x66, 0x3C, 0x00, 0x00, 0x3C, 0x66, 0x7C, 0x60, 0x66, 0x3C, 0x00, + 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x18, 0x18, 0x0C, 0x00, + 0x00, 0x70, 0x1C, 0x06, 0x06, 0x1C, 0x70, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x3E, 0x00, 0x00, 0x00, + 0x00, 0x0E, 0x38, 0x60, 0x60, 0x38, 0x0E, 0x00, 0x00, 0x3C, 0x66, 0x30, 0x18, 0x00, 0x18, 0x00, + 0x00, 0x3C, 0x66, 0x76, 0x76, 0x06, 0x46, 0x3C, 0x00, 0x3C, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00, + 0x00, 0x3E, 0x66, 0x3E, 0x66, 0x66, 0x3E, 0x00, 0x00, 0x3C, 0x66, 0x06, 0x06, 0x66, 0x3C, 0x00, + 0x00, 0x1E, 0x36, 0x66, 0x66, 0x36, 0x1E, 0x00, 0x00, 0x7E, 0x06, 0x1E, 0x06, 0x06, 0x7E, 0x00, + 0x00, 0x3E, 0x06, 0x1E, 0x06, 0x06, 0x06, 0x00, 0x00, 0x3C, 0x66, 0x06, 0x76, 0x66, 0x3C, 0x00, + 0x00, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00, 0x00, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, + 0x00, 0x78, 0x30, 0x30, 0x30, 0x36, 0x1C, 0x00, 0x00, 0x66, 0x36, 0x1E, 0x1E, 0x36, 0x66, 0x00, + 0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x7E, 0x00, 0x00, 0x46, 0x6E, 0x7E, 0x56, 0x46, 0x46, 0x00, + 0x00, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x66, 0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00, + 0x00, 0x3E, 0x66, 0x3E, 0x06, 0x06, 0x06, 0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x70, 0x00, + 0x00, 0x3E, 0x66, 0x3E, 0x1E, 0x36, 0x66, 0x00, 0x00, 0x3C, 0x66, 0x0C, 0x30, 0x66, 0x3C, 0x00, + 0x00, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00, + 0x00, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00, 0x00, 0x46, 0x46, 0x56, 0x7E, 0x6E, 0x46, 0x00, + 0x00, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x66, 0x00, 0x00, 0x66, 0x66, 0x3C, 0x18, 0x18, 0x18, 0x00, + 0x00, 0x7E, 0x30, 0x18, 0x0C, 0x06, 0x7E, 0x00, 0x00, 0x3C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x3C, + 0x00, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x40, 0x00, 0x00, 0x3C, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3C, + 0x00, 0x18, 0x3C, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, + 0x00, 0x0C, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x60, 0x7C, 0x66, 0x7C, 0x00, + 0x00, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x3E, 0x00, 0x00, 0x00, 0x3C, 0x06, 0x06, 0x06, 0x3C, 0x00, + 0x00, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00, 0x00, 0x00, 0x3C, 0x66, 0x7E, 0x06, 0x3C, 0x00, + 0x00, 0x38, 0x0C, 0x3E, 0x0C, 0x0C, 0x0C, 0x00, 0x00, 0x00, 0x7C, 0x66, 0x7C, 0x40, 0x3C, 0x00, + 0x00, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x66, 0x00, 0x00, 0x18, 0x00, 0x1C, 0x18, 0x18, 0x3C, 0x00, + 0x00, 0x30, 0x00, 0x30, 0x30, 0x30, 0x1E, 0x00, 0x00, 0x06, 0x06, 0x36, 0x1E, 0x36, 0x66, 0x00, + 0x00, 0x1C, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x66, 0xFE, 0xFE, 0xD6, 0xC6, 0x00, + 0x00, 0x00, 0x3E, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00, + 0x00, 0x00, 0x3E, 0x66, 0x66, 0x3E, 0x06, 0x00, 0x00, 0x00, 0x7C, 0x66, 0x66, 0x7C, 0x60, 0x00, + 0x00, 0x00, 0x3E, 0x66, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x7C, 0x06, 0x3C, 0x60, 0x3E, 0x00, + 0x00, 0x18, 0x7E, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x00, + 0x00, 0x00, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00, 0x00, 0x00, 0xC6, 0xD6, 0xFE, 0x7C, 0x6C, 0x00, + 0x00, 0x00, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x00, 0x00, 0x00, 0x66, 0x66, 0x7C, 0x60, 0x3C, 0x00, + 0x00, 0x00, 0x7E, 0x30, 0x18, 0x0C, 0x7E, 0x00, 0x00, 0x00, 0x18, 0x08, 0x08, 0x04, 0x08, 0x08, + 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x0C, 0x08, 0x08, 0x10, 0x08, 0x08, +}; diff --git a/ios_mcp/source/font_bin.h b/ios_mcp/source/font_bin.h new file mode 100644 index 0000000..949de6c --- /dev/null +++ b/ios_mcp/source/font_bin.h @@ -0,0 +1 @@ +extern const u8 font_bin[]; \ No newline at end of file diff --git a/ios_mcp/source/fsa.c b/ios_mcp/source/fsa.c new file mode 100644 index 0000000..c7b4009 --- /dev/null +++ b/ios_mcp/source/fsa.c @@ -0,0 +1,437 @@ +#include +#include +#include +#include "svc.h" +#include "imports.h" +#include "fsa.h" + +static void* allocIobuf() +{ + void* ptr = svcAlloc(0xCAFF, 0x828); + + memset(ptr, 0x00, 0x828); + + return ptr; +} + +static void freeIobuf(void* ptr) +{ + svcFree(0xCAFF, ptr); +} + +int FSA_Mount(int fd, char* device_path, char* volume_path, u32 flags, char* arg_string, int arg_string_len) +{ + u8* iobuf = allocIobuf(); + u8* inbuf8 = iobuf; + u8* outbuf8 = &iobuf[0x520]; + iovec_s* iovec = (iovec_s*)&iobuf[0x7C0]; + u32* inbuf = (u32*)inbuf8; + u32* outbuf = (u32*)outbuf8; + + strncpy((char*)&inbuf8[0x04], device_path, 0x27F); + strncpy((char*)&inbuf8[0x284], volume_path, 0x27F); + inbuf[0x504 / 4] = (u32)flags; + inbuf[0x508 / 4] = (u32)arg_string_len; + + iovec[0].ptr = inbuf; + iovec[0].len = 0x520; + iovec[1].ptr = arg_string; + iovec[1].len = arg_string_len; + iovec[2].ptr = outbuf; + iovec[2].len = 0x293; + + int ret = svcIoctlv(fd, 0x01, 2, 1, iovec); + + freeIobuf(iobuf); + return ret; +} + +int FSA_Unmount(int fd, char* path, u32 flags) +{ + u8* iobuf = allocIobuf(); + u32* inbuf = (u32*)iobuf; + u32* outbuf = (u32*)&iobuf[0x520]; + + strncpy((char*)&inbuf[0x01], path, 0x27F); + inbuf[0x284 / 4] = flags; + + int ret = svcIoctl(fd, 0x02, inbuf, 0x520, outbuf, 0x293); + + freeIobuf(iobuf); + return ret; +} + +int FSA_MakeDir(int fd, char* path, u32 flags) +{ + u8* iobuf = allocIobuf(); + u32* inbuf = (u32*)iobuf; + u32* outbuf = (u32*)&iobuf[0x520]; + + strncpy((char*)&inbuf[0x01], path, 0x27F); + inbuf[0x284 / 4] = flags; + + int ret = svcIoctl(fd, 0x07, inbuf, 0x520, outbuf, 0x293); + + freeIobuf(iobuf); + return ret; +} + +int FSA_OpenDir(int fd, char* path, int* outHandle) +{ + u8* iobuf = allocIobuf(); + u32* inbuf = (u32*)iobuf; + u32* outbuf = (u32*)&iobuf[0x520]; + + strncpy((char*)&inbuf[0x01], path, 0x27F); + + int ret = svcIoctl(fd, 0x0A, inbuf, 0x520, outbuf, 0x293); + + if(outHandle) *outHandle = outbuf[1]; + + freeIobuf(iobuf); + return ret; +} + +int FSA_ReadDir(int fd, int handle, directoryEntry_s* out_data) +{ + u8* iobuf = allocIobuf(); + u32* inbuf = (u32*)iobuf; + u32* outbuf = (u32*)&iobuf[0x520]; + + inbuf[1] = handle; + + int ret = svcIoctl(fd, 0x0B, inbuf, 0x520, outbuf, 0x293); + + if(out_data) memcpy(out_data, &outbuf[1], sizeof(directoryEntry_s)); + + freeIobuf(iobuf); + return ret; +} + +int FSA_RewindDir(int fd, int handle) +{ + u8* iobuf = allocIobuf(); + u32* inbuf = (u32*)iobuf; + u32* outbuf = (u32*)&iobuf[0x520]; + + inbuf[1] = handle; + + int ret = svcIoctl(fd, 0x0C, inbuf, 0x520, outbuf, 0x293); + + freeIobuf(iobuf); + return ret; +} + +int FSA_CloseDir(int fd, int handle) +{ + u8* iobuf = allocIobuf(); + u32* inbuf = (u32*)iobuf; + u32* outbuf = (u32*)&iobuf[0x520]; + + inbuf[1] = handle; + + int ret = svcIoctl(fd, 0x0D, inbuf, 0x520, outbuf, 0x293); + + freeIobuf(iobuf); + return ret; +} + +int FSA_ChangeDir(int fd, char* path) +{ + u8* iobuf = allocIobuf(); + u32* inbuf = (u32*)iobuf; + u32* outbuf = (u32*)&iobuf[0x520]; + + strncpy((char*)&inbuf[0x01], path, 0x27F); + + int ret = svcIoctl(fd, 0x05, inbuf, 0x520, outbuf, 0x293); + + freeIobuf(iobuf); + return ret; +} + +int FSA_OpenFile(int fd, char* path, char* mode, int* outHandle) +{ + u8* iobuf = allocIobuf(); + u32* inbuf = (u32*)iobuf; + u32* outbuf = (u32*)&iobuf[0x520]; + + strncpy((char*)&inbuf[0x01], path, 0x27F); + strncpy((char*)&inbuf[0xA1], mode, 0x10); + + int ret = svcIoctl(fd, 0x0E, inbuf, 0x520, outbuf, 0x293); + + if(outHandle) *outHandle = outbuf[1]; + + freeIobuf(iobuf); + return ret; +} + +int _FSA_ReadWriteFile(int fd, void* data, u32 size, u32 cnt, int fileHandle, u32 flags, bool read) +{ + u8* iobuf = allocIobuf(); + u8* inbuf8 = iobuf; + u8* outbuf8 = &iobuf[0x520]; + iovec_s* iovec = (iovec_s*)&iobuf[0x7C0]; + u32* inbuf = (u32*)inbuf8; + u32* outbuf = (u32*)outbuf8; + + inbuf[0x08 / 4] = size; + inbuf[0x0C / 4] = cnt; + inbuf[0x14 / 4] = fileHandle; + inbuf[0x18 / 4] = flags; + + iovec[0].ptr = inbuf; + iovec[0].len = 0x520; + + iovec[1].ptr = data; + iovec[1].len = size * cnt; + + iovec[2].ptr = outbuf; + iovec[2].len = 0x293; + + int ret; + if(read) ret = svcIoctlv(fd, 0x0F, 1, 2, iovec); + else ret = svcIoctlv(fd, 0x10, 2, 1, iovec); + + freeIobuf(iobuf); + return ret; +} + +int FSA_ReadFile(int fd, void* data, u32 size, u32 cnt, int fileHandle, u32 flags) +{ + return _FSA_ReadWriteFile(fd, data, size, cnt, fileHandle, flags, true); +} + +int FSA_WriteFile(int fd, void* data, u32 size, u32 cnt, int fileHandle, u32 flags) +{ + return _FSA_ReadWriteFile(fd, data, size, cnt, fileHandle, flags, false); +} + +int FSA_StatFile(int fd, int handle, fileStat_s* out_data) +{ + u8* iobuf = allocIobuf(); + u32* inbuf = (u32*)iobuf; + u32* outbuf = (u32*)&iobuf[0x520]; + + inbuf[1] = handle; + + int ret = svcIoctl(fd, 0x14, inbuf, 0x520, outbuf, 0x293); + + if(out_data) memcpy(out_data, &outbuf[1], sizeof(fileStat_s)); + + freeIobuf(iobuf); + return ret; +} + +int FSA_CloseFile(int fd, int fileHandle) +{ + u8* iobuf = allocIobuf(); + u32* inbuf = (u32*)iobuf; + u32* outbuf = (u32*)&iobuf[0x520]; + + inbuf[1] = fileHandle; + + int ret = svcIoctl(fd, 0x15, inbuf, 0x520, outbuf, 0x293); + + freeIobuf(iobuf); + return ret; +} + +int FSA_SetPosFile(int fd, int fileHandle, u32 position) +{ + u8* iobuf = allocIobuf(); + u32* inbuf = (u32*)iobuf; + u32* outbuf = (u32*)&iobuf[0x520]; + + inbuf[1] = fileHandle; + inbuf[2] = position; + + int ret = svcIoctl(fd, 0x12, inbuf, 0x520, outbuf, 0x293); + + freeIobuf(iobuf); + return ret; +} + +int FSA_GetStat(int fd, char *path, fileStat_s* out_data) +{ + u8* iobuf = allocIobuf(); + u32* inbuf = (u32*)iobuf; + u32* outbuf = (u32*)&iobuf[0x520]; + + strncpy((char*)&inbuf[0x01], path, 0x27F); + inbuf[0x284/4] = 5; + + int ret = svcIoctl(fd, 0x18, inbuf, 0x520, outbuf, 0x293); + + if(out_data) memcpy(out_data, &outbuf[1], sizeof(fileStat_s)); + + freeIobuf(iobuf); + return ret; +} + +int FSA_Remove(int fd, char *path) +{ + u8* iobuf = allocIobuf(); + u32* inbuf = (u32*)iobuf; + u32* outbuf = (u32*)&iobuf[0x520]; + + strncpy((char*)&inbuf[0x01], path, 0x27F); + + int ret = svcIoctl(fd, 0x08, inbuf, 0x520, outbuf, 0x293); + + freeIobuf(iobuf); + return ret; +} + +int FSA_ChangeMode(int fd, char *path, int mode) +{ + u8* iobuf = allocIobuf(); + u32* inbuf = (u32*)iobuf; + u32* outbuf = (u32*)&iobuf[0x520]; + + strncpy((char*)&inbuf[0x01], path, 0x27F); + inbuf[0x284/4] = mode; + inbuf[0x288/4] = 0x777; // mask + + int ret = svcIoctl(fd, 0x20, inbuf, 0x520, outbuf, 0x293); + + freeIobuf(iobuf); + return ret; +} + +// type 4 : +// 0x08 : device size in sectors (u64) +// 0x10 : device sector size (u32) +int FSA_GetDeviceInfo(int fd, char* device_path, int type, u32* out_data) +{ + u8* iobuf = allocIobuf(); + u32* inbuf = (u32*)iobuf; + u32* outbuf = (u32*)&iobuf[0x520]; + + strncpy((char*)&inbuf[0x01], device_path, 0x27F); + inbuf[0x284 / 4] = type; + + int ret = svcIoctl(fd, 0x18, inbuf, 0x520, outbuf, 0x293); + + int size = 0; + + switch(type) + { + case 0: case 1: case 7: + size = 0x8; + break; + case 2: + size = 0x4; + break; + case 3: + size = 0x1E; + break; + case 4: + size = 0x28; + break; + case 5: + size = 0x64; + break; + case 6: case 8: + size = 0x14; + break; + } + + memcpy(out_data, &outbuf[1], size); + + freeIobuf(iobuf); + return ret; +} + +int FSA_RawOpen(int fd, char* device_path, int* outHandle) +{ + u8* iobuf = allocIobuf(); + u32* inbuf = (u32*)iobuf; + u32* outbuf = (u32*)&iobuf[0x520]; + + strncpy((char*)&inbuf[0x01], device_path, 0x27F); + + int ret = svcIoctl(fd, 0x6A, inbuf, 0x520, outbuf, 0x293); + + if(outHandle) *outHandle = outbuf[1]; + + freeIobuf(iobuf); + return ret; +} + +int FSA_RawClose(int fd, int device_handle) +{ + u8* iobuf = allocIobuf(); + u32* inbuf = (u32*)iobuf; + u32* outbuf = (u32*)&iobuf[0x520]; + + inbuf[1] = device_handle; + + int ret = svcIoctl(fd, 0x6D, inbuf, 0x520, outbuf, 0x293); + + freeIobuf(iobuf); + return ret; +} + +// offset in blocks of 0x1000 bytes +int FSA_RawRead(int fd, void* data, u32 size_bytes, u32 cnt, u64 blocks_offset, int device_handle) +{ + u8* iobuf = allocIobuf(); + u8* inbuf8 = iobuf; + u8* outbuf8 = &iobuf[0x520]; + iovec_s* iovec = (iovec_s*)&iobuf[0x7C0]; + u32* inbuf = (u32*)inbuf8; + u32* outbuf = (u32*)outbuf8; + + // note : offset_bytes = blocks_offset * size_bytes + inbuf[0x08 / 4] = (blocks_offset >> 32); + inbuf[0x0C / 4] = (blocks_offset & 0xFFFFFFFF); + inbuf[0x10 / 4] = cnt; + inbuf[0x14 / 4] = size_bytes; + inbuf[0x18 / 4] = device_handle; + + iovec[0].ptr = inbuf; + iovec[0].len = 0x520; + + iovec[1].ptr = data; + iovec[1].len = size_bytes * cnt; + + iovec[2].ptr = outbuf; + iovec[2].len = 0x293; + + int ret = svcIoctlv(fd, 0x6B, 1, 2, iovec); + + freeIobuf(iobuf); + return ret; +} + +int FSA_RawWrite(int fd, void* data, u32 size_bytes, u32 cnt, u64 blocks_offset, int device_handle) +{ + u8* iobuf = allocIobuf(); + u8* inbuf8 = iobuf; + u8* outbuf8 = &iobuf[0x520]; + iovec_s* iovec = (iovec_s*)&iobuf[0x7C0]; + u32* inbuf = (u32*)inbuf8; + u32* outbuf = (u32*)outbuf8; + + inbuf[0x08 / 4] = (blocks_offset >> 32); + inbuf[0x0C / 4] = (blocks_offset & 0xFFFFFFFF); + inbuf[0x10 / 4] = cnt; + inbuf[0x14 / 4] = size_bytes; + inbuf[0x18 / 4] = device_handle; + + iovec[0].ptr = inbuf; + iovec[0].len = 0x520; + + iovec[1].ptr = data; + iovec[1].len = size_bytes * cnt; + + iovec[2].ptr = outbuf; + iovec[2].len = 0x293; + + int ret = svcIoctlv(fd, 0x6C, 2, 1, iovec); + + freeIobuf(iobuf); + return ret; +} diff --git a/ios_mcp/source/fsa.h b/ios_mcp/source/fsa.h new file mode 100644 index 0000000..914e3d7 --- /dev/null +++ b/ios_mcp/source/fsa.h @@ -0,0 +1,59 @@ +#ifndef FSA_H +#define FSA_H + +typedef struct +{ + u32 flag; + u32 permission; + u32 owner_id; + u32 group_id; + u32 size; // size in bytes + u32 physsize; // physical size on disk in bytes + u32 unk[3]; + u32 id; + u32 ctime; + u32 mtime; + u32 unk2[0x0D]; +}fileStat_s; + +typedef struct +{ + fileStat_s stat; + char name[0x100]; +}directoryEntry_s; + +#define DIR_ENTRY_IS_DIRECTORY 0x80000000 + +#define FSA_MOUNTFLAGS_BINDMOUNT (1 << 0) +#define FSA_MOUNTFLAGS_GLOBAL (1 << 1) + +int FSA_Open(); + +int FSA_Mount(int fd, char* device_path, char* volume_path, u32 flags, char* arg_string, int arg_string_len); +int FSA_Unmount(int fd, char* path, u32 flags); + +int FSA_GetDeviceInfo(int fd, char* device_path, int type, u32* out_data); + +int FSA_MakeDir(int fd, char* path, u32 flags); +int FSA_OpenDir(int fd, char* path, int* outHandle); +int FSA_ReadDir(int fd, int handle, directoryEntry_s* out_data); +int FSA_RewindDir(int fd, int handle); +int FSA_CloseDir(int fd, int handle); +int FSA_ChangeDir(int fd, char* path); + +int FSA_OpenFile(int fd, char* path, char* mode, int* outHandle); +int FSA_ReadFile(int fd, void* data, u32 size, u32 cnt, int fileHandle, u32 flags); +int FSA_WriteFile(int fd, void* data, u32 size, u32 cnt, int fileHandle, u32 flags); +int FSA_StatFile(int fd, int handle, fileStat_s* out_data); +int FSA_CloseFile(int fd, int fileHandle); +int FSA_SetPosFile(int fd, int fileHandle, u32 position); +int FSA_GetStat(int fd, char *path, fileStat_s* out_data); +int FSA_Remove(int fd, char *path); +int FSA_ChangeMode(int fd, char *path, int mode); + +int FSA_RawOpen(int fd, char* device_path, int* outHandle); +int FSA_RawRead(int fd, void* data, u32 size_bytes, u32 cnt, u64 sector_offset, int device_handle); +int FSA_RawWrite(int fd, void* data, u32 size_bytes, u32 cnt, u64 sector_offset, int device_handle); +int FSA_RawClose(int fd, int device_handle); + +#endif diff --git a/ios_mcp/source/imports.c b/ios_mcp/source/imports.c new file mode 100644 index 0000000..a3f94b3 --- /dev/null +++ b/ios_mcp/source/imports.c @@ -0,0 +1,49 @@ +#include "imports.h" + +void usleep(u32 time) +{ + ((void (*const)(u32))0x050564E4)(time); +} + +void* memset(void* dst, int val, size_t size) +{ + char* _dst = dst; + + int i; + for(i = 0; i < size; i++) _dst[i] = val; + + return dst; +} + +void* (*const _memcpy)(void* dst, void* src, int size) = (void*)0x05054E54; + +void* memcpy(void* dst, const void* src, size_t size) +{ + return _memcpy(dst, (void*)src, size); +} + +int strlen(const char* str) +{ + unsigned int i = 0; + while (str[i]) { + i++; + } + return i; +} + +char* strncpy(char* dst, const char* src, size_t size) +{ + int i; + for(i = 0; i < size; i++) + { + dst[i] = src[i]; + if(src[i] == '\0') return dst; + } + + return dst; +} + +int vsnprintf(char * s, size_t n, const char * format, va_list arg) +{ + return ((int (*const)(char*, size_t, const char *, va_list))0x05055C40)(s, n, format, arg); +} diff --git a/ios_mcp/source/imports.h b/ios_mcp/source/imports.h new file mode 100644 index 0000000..72ee497 --- /dev/null +++ b/ios_mcp/source/imports.h @@ -0,0 +1,12 @@ +#ifndef IMPORTS_H +#define IMPORTS_H + +#include +#include +#include "types.h" + +#define MCP_SVC_BASE ((void*)0x050567EC) + +void usleep(u32 time); + +#endif diff --git a/ios_mcp/source/ipc.c b/ios_mcp/source/ipc.c new file mode 100644 index 0000000..53b83dd --- /dev/null +++ b/ios_mcp/source/ipc.c @@ -0,0 +1,480 @@ +/*************************************************************************** + * Copyright (C) 2016 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include +#include +#include +#include "imports.h" +#include "fsa.h" +#include "svc.h" +#include "text.h" +#include "logger.h" +#include "fsa.h" + +#define IOS_ERROR_UNKNOWN_VALUE 0xFFFFFFD6 +#define IOS_ERROR_INVALID_ARG 0xFFFFFFE3 +#define IOS_ERROR_INVALID_SIZE 0xFFFFFFE9 +#define IOS_ERROR_UNKNOWN 0xFFFFFFF7 +#define IOS_ERROR_NOEXISTS 0xFFFFFFFA + +#define IOCTL_MEM_WRITE 0x00 +#define IOCTL_MEM_READ 0x01 +#define IOCTL_SVC 0x02 +#define IOCTL_MEMCPY 0x04 +#define IOCTL_REPEATED_WRITE 0x05 +#define IOCTL_KERN_READ32 0x06 +#define IOCTL_KERN_WRITE32 0x07 + +#define IOCTL_FSA_OPEN 0x40 +#define IOCTL_FSA_CLOSE 0x41 +#define IOCTL_FSA_MOUNT 0x42 +#define IOCTL_FSA_UNMOUNT 0x43 +#define IOCTL_FSA_GETDEVICEINFO 0x44 +#define IOCTL_FSA_OPENDIR 0x45 +#define IOCTL_FSA_READDIR 0x46 +#define IOCTL_FSA_CLOSEDIR 0x47 +#define IOCTL_FSA_MAKEDIR 0x48 +#define IOCTL_FSA_OPENFILE 0x49 +#define IOCTL_FSA_READFILE 0x4A +#define IOCTL_FSA_WRITEFILE 0x4B +#define IOCTL_FSA_STATFILE 0x4C +#define IOCTL_FSA_CLOSEFILE 0x4D +#define IOCTL_FSA_SETFILEPOS 0x4E +#define IOCTL_FSA_GETSTAT 0x4F +#define IOCTL_FSA_REMOVE 0x50 +#define IOCTL_FSA_REWINDDIR 0x51 +#define IOCTL_FSA_CHDIR 0x52 +#define IOCTL_FSA_RENAME 0x53 +#define IOCTL_FSA_RAW_OPEN 0x54 +#define IOCTL_FSA_RAW_READ 0x55 +#define IOCTL_FSA_RAW_WRITE 0x56 +#define IOCTL_FSA_RAW_CLOSE 0x57 +#define IOCTL_FSA_CHANGEMODE 0x58 + +static u8 threadStack[0x1000] __attribute__((aligned(0x20))); + +static int ipc_ioctl(ipcmessage *message) +{ + int res = 0; + + switch(message->ioctl.command) + { + case IOCTL_MEM_WRITE: + { + if(message->ioctl.length_in < 4) + { + res = IOS_ERROR_INVALID_SIZE; + } + else + { + memcpy((void*)message->ioctl.buffer_in[0], message->ioctl.buffer_in + 1, message->ioctl.length_in - 4); + } + break; + } + case IOCTL_MEM_READ: + { + if(message->ioctl.length_in < 4) + { + res = IOS_ERROR_INVALID_SIZE; + } + else + { + memcpy(message->ioctl.buffer_io, (void*)message->ioctl.buffer_in[0], message->ioctl.length_io); + } + break; + } + case IOCTL_SVC: + { + if((message->ioctl.length_in < 4) || (message->ioctl.length_io < 4)) + { + res = IOS_ERROR_INVALID_SIZE; + } + else + { + int svc_id = message->ioctl.buffer_in[0]; + int size_arguments = message->ioctl.length_in - 4; + + u32 arguments[8]; + memset(arguments, 0x00, sizeof(arguments)); + memcpy(arguments, message->ioctl.buffer_in + 1, (size_arguments < 8 * 4) ? size_arguments : (8 * 4)); + + // return error code as data + message->ioctl.buffer_io[0] = ((int (*const)(u32, u32, u32, u32, u32, u32, u32, u32))(MCP_SVC_BASE + svc_id * 8))(arguments[0], arguments[1], arguments[2], arguments[3], arguments[4], arguments[5], arguments[6], arguments[7]); + } + break; + } + case IOCTL_MEMCPY: + { + if(message->ioctl.length_in < 12) + { + res = IOS_ERROR_INVALID_SIZE; + } + else + { + memcpy((void*)message->ioctl.buffer_in[0], (void*)message->ioctl.buffer_in[1], message->ioctl.buffer_in[2]); + } + break; + } + case IOCTL_REPEATED_WRITE: + { + if(message->ioctl.length_in < 12) + { + res = IOS_ERROR_INVALID_SIZE; + } + else + { + u32* dst = (u32*)message->ioctl.buffer_in[0]; + u32* cache_range = (u32*)(message->ioctl.buffer_in[0] & ~0xFF); + u32 value = message->ioctl.buffer_in[1]; + u32 n = message->ioctl.buffer_in[2]; + + u32 old = *dst; + int i; + for(i = 0; i < n; i++) + { + if(*dst != old) + { + if(*dst == 0x0) old = *dst; + else + { + *dst = value; + svcFlushDCache(cache_range, 0x100); + break; + } + }else + { + svcInvalidateDCache(cache_range, 0x100); + usleep(50); + } + } + } + break; + } + case IOCTL_KERN_READ32: + { + if((message->ioctl.length_in < 4) || (message->ioctl.length_io < 4)) + { + res = IOS_ERROR_INVALID_SIZE; + } + else + { + for(u32 i = 0; i < (message->ioctl.length_io/4); i++) + { + message->ioctl.buffer_io[i] = svcRead32(message->ioctl.buffer_in[0] + i * 4); + } + } + break; + } + case IOCTL_KERN_WRITE32: + { + //! TODO: add syscall as on kern_read32 + res = IOS_ERROR_NOEXISTS; + break; + } + //!-------------------------------------------------------------------------------------------------------------- + //! FSA handles for better performance + //!-------------------------------------------------------------------------------------------------------------- + //! TODO: add checks for i/o buffer length + case IOCTL_FSA_OPEN: + { + message->ioctl.buffer_io[0] = svcOpen("/dev/fsa", 0); + break; + } + case IOCTL_FSA_CLOSE: + { + int fd = message->ioctl.buffer_in[0]; + message->ioctl.buffer_io[0] = svcClose(fd); + break; + } + case IOCTL_FSA_MOUNT: + { + int fd = message->ioctl.buffer_in[0]; + char *device_path = ((char *)message->ioctl.buffer_in) + message->ioctl.buffer_in[1]; + char *volume_path = ((char *)message->ioctl.buffer_in) + message->ioctl.buffer_in[2]; + u32 flags = message->ioctl.buffer_in[3]; + char *arg_string = (message->ioctl.buffer_in[4] > 0) ? (((char *)message->ioctl.buffer_in) + message->ioctl.buffer_in[4]) : 0; + int arg_string_len = message->ioctl.buffer_in[5]; + + message->ioctl.buffer_io[0] = FSA_Mount(fd, device_path, volume_path, flags, arg_string, arg_string_len); + break; + } + case IOCTL_FSA_UNMOUNT: + { + int fd = message->ioctl.buffer_in[0]; + char *device_path = ((char *)message->ioctl.buffer_in) + message->ioctl.buffer_in[1]; + u32 flags = message->ioctl.buffer_in[2]; + + message->ioctl.buffer_io[0] = FSA_Unmount(fd, device_path, flags); + break; + } + case IOCTL_FSA_GETDEVICEINFO: + { + int fd = message->ioctl.buffer_in[0]; + char *device_path = ((char *)message->ioctl.buffer_in) + message->ioctl.buffer_in[1]; + int type = message->ioctl.buffer_in[2]; + + message->ioctl.buffer_io[0] = FSA_GetDeviceInfo(fd, device_path, type, message->ioctl.buffer_io + 1); + break; + } + case IOCTL_FSA_OPENDIR: + { + int fd = message->ioctl.buffer_in[0]; + char *path = ((char *)message->ioctl.buffer_in) + message->ioctl.buffer_in[1]; + + message->ioctl.buffer_io[0] = FSA_OpenDir(fd, path, (int*)message->ioctl.buffer_io + 1); + break; + } + case IOCTL_FSA_READDIR: + { + int fd = message->ioctl.buffer_in[0]; + int handle = message->ioctl.buffer_in[1]; + + message->ioctl.buffer_io[0] = FSA_ReadDir(fd, handle, (directoryEntry_s*)(message->ioctl.buffer_io + 1)); + break; + } + case IOCTL_FSA_CLOSEDIR: + { + int fd = message->ioctl.buffer_in[0]; + int handle = message->ioctl.buffer_in[1]; + + message->ioctl.buffer_io[0] = FSA_CloseDir(fd, handle); + break; + } + case IOCTL_FSA_MAKEDIR: + { + int fd = message->ioctl.buffer_in[0]; + char *path = ((char *)message->ioctl.buffer_in) + message->ioctl.buffer_in[1]; + u32 flags = message->ioctl.buffer_in[2]; + + message->ioctl.buffer_io[0] = FSA_MakeDir(fd, path, flags); + break; + } + case IOCTL_FSA_OPENFILE: + { + int fd = message->ioctl.buffer_in[0]; + char *path = ((char *)message->ioctl.buffer_in) + message->ioctl.buffer_in[1]; + char *mode = ((char *)message->ioctl.buffer_in) + message->ioctl.buffer_in[2]; + + message->ioctl.buffer_io[0] = FSA_OpenFile(fd, path, mode, (int*)message->ioctl.buffer_io + 1); + break; + } + case IOCTL_FSA_READFILE: + { + int fd = message->ioctl.buffer_in[0]; + u32 size = message->ioctl.buffer_in[1]; + u32 cnt = message->ioctl.buffer_in[2]; + int fileHandle = message->ioctl.buffer_in[3]; + u32 flags = message->ioctl.buffer_in[4]; + + message->ioctl.buffer_io[0] = FSA_ReadFile(fd, ((u8*)message->ioctl.buffer_io) + 0x40, size, cnt, fileHandle, flags); + break; + } + case IOCTL_FSA_WRITEFILE: + { + int fd = message->ioctl.buffer_in[0]; + u32 size = message->ioctl.buffer_in[1]; + u32 cnt = message->ioctl.buffer_in[2]; + int fileHandle = message->ioctl.buffer_in[3]; + u32 flags = message->ioctl.buffer_in[4]; + + message->ioctl.buffer_io[0] = FSA_WriteFile(fd, ((u8*)message->ioctl.buffer_in) + 0x40, size, cnt, fileHandle, flags); + break; + } + case IOCTL_FSA_STATFILE: + { + int fd = message->ioctl.buffer_in[0]; + int fileHandle = message->ioctl.buffer_in[1]; + + message->ioctl.buffer_io[0] = FSA_StatFile(fd, fileHandle, (fileStat_s*)(message->ioctl.buffer_io + 1)); + break; + } + case IOCTL_FSA_CLOSEFILE: + { + int fd = message->ioctl.buffer_in[0]; + int fileHandle = message->ioctl.buffer_in[1]; + + message->ioctl.buffer_io[0] = FSA_CloseFile(fd, fileHandle); + break; + } + case IOCTL_FSA_SETFILEPOS: + { + int fd = message->ioctl.buffer_in[0]; + int fileHandle = message->ioctl.buffer_in[1]; + u32 position = message->ioctl.buffer_in[2]; + + message->ioctl.buffer_io[0] = FSA_SetPosFile(fd, fileHandle, position); + break; + } + case IOCTL_FSA_GETSTAT: + { + int fd = message->ioctl.buffer_in[0]; + char *path = ((char *)message->ioctl.buffer_in) + message->ioctl.buffer_in[1]; + + message->ioctl.buffer_io[0] = FSA_GetStat(fd, path, (fileStat_s*)(message->ioctl.buffer_io + 1)); + break; + } + case IOCTL_FSA_REMOVE: + { + int fd = message->ioctl.buffer_in[0]; + char *path = ((char *)message->ioctl.buffer_in) + message->ioctl.buffer_in[1]; + + message->ioctl.buffer_io[0] = FSA_Remove(fd, path); + break; + } + case IOCTL_FSA_REWINDDIR: + { + int fd = message->ioctl.buffer_in[0]; + int dirFd = message->ioctl.buffer_in[1]; + + message->ioctl.buffer_io[0] = FSA_RewindDir(fd, dirFd); + break; + } + case IOCTL_FSA_CHDIR: + { + int fd = message->ioctl.buffer_in[0]; + char *path = ((char *)message->ioctl.buffer_in) + message->ioctl.buffer_in[1]; + + message->ioctl.buffer_io[0] = FSA_ChangeDir(fd, path); + break; + } + case IOCTL_FSA_RAW_OPEN: + { + int fd = message->ioctl.buffer_in[0]; + char *path = ((char *)message->ioctl.buffer_in) + message->ioctl.buffer_in[1]; + + message->ioctl.buffer_io[0] = FSA_RawOpen(fd, path, (int*)(message->ioctl.buffer_io + 1)); + break; + } + case IOCTL_FSA_RAW_READ: + { + int fd = message->ioctl.buffer_in[0]; + u32 block_size = message->ioctl.buffer_in[1]; + u32 cnt = message->ioctl.buffer_in[2]; + u64 sector_offset = ((u64)message->ioctl.buffer_in[3] << 32ULL) | message->ioctl.buffer_in[4]; + int deviceHandle = message->ioctl.buffer_in[5]; + + message->ioctl.buffer_io[0] = FSA_RawRead(fd, ((u8*)message->ioctl.buffer_io) + 0x40, block_size, cnt, sector_offset, deviceHandle); + break; + } + case IOCTL_FSA_RAW_WRITE: + { + int fd = message->ioctl.buffer_in[0]; + u32 block_size = message->ioctl.buffer_in[1]; + u32 cnt = message->ioctl.buffer_in[2]; + u64 sector_offset = ((u64)message->ioctl.buffer_in[3] << 32ULL) | message->ioctl.buffer_in[4]; + int deviceHandle = message->ioctl.buffer_in[5]; + + message->ioctl.buffer_io[0] = FSA_RawWrite(fd, ((u8*)message->ioctl.buffer_in) + 0x40, block_size, cnt, sector_offset, deviceHandle); + break; + } + case IOCTL_FSA_RAW_CLOSE: + { + int fd = message->ioctl.buffer_in[0]; + int deviceHandle = message->ioctl.buffer_in[1]; + + message->ioctl.buffer_io[0] = FSA_RawClose(fd, deviceHandle); + break; + } + case IOCTL_FSA_CHANGEMODE: + { + int fd = message->ioctl.buffer_in[0]; + char *path = ((char *)message->ioctl.buffer_in) + message->ioctl.buffer_in[1]; + int mode = message->ioctl.buffer_in[2]; + + message->ioctl.buffer_io[0] = FSA_ChangeMode(fd, path, mode); + break; + } + default: + res = IOS_ERROR_INVALID_ARG; + break; + } + + return res; +} + +static int ipc_thread(void *arg) +{ + int res; + ipcmessage *message; + u32 messageQueue[0x10]; + + int queueId = svcCreateMessageQueue(messageQueue, sizeof(messageQueue) / 4); + + if(svcRegisterResourceManager("/dev/iosuhax", queueId) != 0) + { + return 0; + } + + while(1) + { + res = svcReceiveMessage(queueId, &message, 0); + if(res < 0) + { + usleep(10000); + continue; + } + + switch(message->command) + { + case IOS_OPEN: + { + log_printf("IOS_OPEN\n"); + res = 0; + break; + } + case IOS_CLOSE: + { + log_printf("IOS_CLOSE\n"); + res = 0; + break; + } + case IOS_IOCTL: + { + log_printf("IOS_IOCTL\n"); + res = ipc_ioctl(message); + break; + } + case IOS_IOCTLV: + { + log_printf("IOS_IOCTLV\n"); + res = 0; + break; + } + default: + { + log_printf("unexpected command 0x%X\n", message->command); + res = IOS_ERROR_UNKNOWN_VALUE; + break; + } + } + + svcResourceReply(message, res); + } +} + +void ipc_init(void) +{ + int threadId = svcCreateThread(ipc_thread, 0, (u32*)(threadStack + sizeof(threadStack)), sizeof(threadStack), 0x78, 1); + if(threadId >= 0) + svcStartThread(threadId); +} diff --git a/ios_mcp/source/ipc.h b/ios_mcp/source/ipc.h new file mode 100644 index 0000000..72aac08 --- /dev/null +++ b/ios_mcp/source/ipc.h @@ -0,0 +1,6 @@ +#ifndef _IPC_H_ +#define _IPC_H_ + +void ipc_init(); + +#endif diff --git a/ios_mcp/source/ipc_types.h b/ios_mcp/source/ipc_types.h new file mode 100644 index 0000000..22e14ff --- /dev/null +++ b/ios_mcp/source/ipc_types.h @@ -0,0 +1,83 @@ +#ifndef _IPC_TYPES_H_ +#define _IPC_TYPES_H_ + +#include "types.h" + +#define IOS_COMMAND_INVALID 0x00 +#define IOS_OPEN 0x01 +#define IOS_CLOSE 0x02 +#define IOS_READ 0x03 +#define IOS_WRITE 0x04 +#define IOS_SEEK 0x05 +#define IOS_IOCTL 0x06 +#define IOS_IOCTLV 0x07 +#define IOS_REPLY 0x08 +#define IOS_IPC_MSG0 0x09 +#define IOS_IPC_MSG1 0x0A +#define IOS_IPC_MSG2 0x0B +#define IOS_SUSPEND 0x0C +#define IOS_RESUME 0x0D +#define IOS_SVCMSG 0x0E + + +/* IPC message */ +typedef struct ipcmessage +{ + u32 command; + u32 result; + u32 fd; + u32 flags; + u32 client_cpu; + u32 client_pid; + u64 client_gid; + u32 server_handle; + + union + { + u32 args[5]; + + struct + { + char *device; + u32 mode; + u32 resultfd; + } open; + + struct + { + void *data; + u32 length; + } read, write; + + struct + { + s32 offset; + s32 origin; + } seek; + + struct + { + u32 command; + + u32 *buffer_in; + u32 length_in; + u32 *buffer_io; + u32 length_io; + } ioctl; + struct _ioctlv + { + u32 command; + + u32 num_in; + u32 num_io; + struct _ioctlv *vector; + } ioctlv; + }; + + u32 prev_command; + u32 prev_fd; + u32 virt0; + u32 virt1; +} __attribute__((packed)) ipcmessage; + +#endif diff --git a/ios_mcp/source/logger.c b/ios_mcp/source/logger.c new file mode 100644 index 0000000..b5b4fe2 --- /dev/null +++ b/ios_mcp/source/logger.c @@ -0,0 +1,71 @@ +#include +#include +#include "types.h" +#include "imports.h" +#include "socket.h" +#include "logger.h" + +#ifdef DEBUG_LOGGER +static int log_socket = 0; + +int log_init(unsigned int ipAddress) +{ + log_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (log_socket < 0) + return log_socket; + + struct sockaddr_in connect_addr; + memset(&connect_addr, 0, sizeof(connect_addr)); + connect_addr.sin_family = AF_INET; + connect_addr.sin_port = 4405; + connect_addr.sin_addr.s_addr = ipAddress; + + if(connect(log_socket, (struct sockaddr*)&connect_addr, sizeof(connect_addr)) < 0) + { + closesocket(log_socket); + log_socket = -1; + } + + return log_socket; +} + +void log_deinit() +{ + if(log_socket >= 0) + { + closesocket(log_socket); + log_socket = -1; + } +} + +static void log_print(const char *str, int len) +{ + int ret; + while (len > 0) { + int block = len < 1400 ? len : 1400; // take max 1400 bytes per UDP packet + ret = send(log_socket, str, block, 0); + if(ret < 0) + break; + + len -= ret; + str += ret; + } +} + +void log_printf(const char *format, ...) +{ + if(log_socket < 0) { + return; + } + + va_list args; + va_start(args, format); + + char buffer[0x100]; + + int len = vsnprintf(buffer, sizeof(buffer), format, args); + log_print(buffer, len); + + va_end(args); +} +#endif // DEBUG_LOGGER diff --git a/ios_mcp/source/logger.h b/ios_mcp/source/logger.h new file mode 100644 index 0000000..085672c --- /dev/null +++ b/ios_mcp/source/logger.h @@ -0,0 +1,24 @@ +#ifndef __LOGGER_H_ +#define __LOGGER_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +//#define DEBUG_LOGGER 1 + +#ifdef DEBUG_LOGGER +int log_init(unsigned int ip); +void log_deinit(); +void log_printf(const char *format, ...); +#else +#define log_init(x) +#define log_deinit() +#define log_printf(x, ...) +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ios_mcp/source/main.c b/ios_mcp/source/main.c new file mode 100644 index 0000000..50c3c27 --- /dev/null +++ b/ios_mcp/source/main.c @@ -0,0 +1,239 @@ +#include +#include +#include +#include "imports.h" +#include "net_ifmgr_ncl.h" +#include "socket.h" +#include "fsa.h" +#include "svc.h" +#include "text.h" +#include "logger.h" +#include "ipc.h" + +static bool serverKilled; + +// overwrites command_buffer with response +// returns length of response (or 0 for no response, negative for error) +int serverCommandHandler(u32* command_buffer, u32 length) +{ + if(!command_buffer || !length) return -1; + + int out_length = 4; + + switch(command_buffer[0]) + { + case 0: + // write + // [cmd_id][addr] + { + void* dst = (void*)command_buffer[1]; + + memcpy(dst, &command_buffer[2], length - 8); + } + break; + case 1: + // read + // [cmd_id][addr][length] + { + void* src = (void*)command_buffer[1]; + length = command_buffer[2]; + + memcpy(&command_buffer[1], src, length); + out_length = length + 4; + } + break; + case 2: + // svc + // [cmd_id][svc_id] + { + int svc_id = command_buffer[1]; + int size_arguments = length - 8; + + u32 arguments[8]; + memset(arguments, 0x00, sizeof(arguments)); + memcpy(arguments, &command_buffer[2], (size_arguments < 8 * 4) ? size_arguments : (8 * 4)); + + // return error code as data + out_length = 8; + command_buffer[1] = ((int (*const)(u32, u32, u32, u32, u32, u32, u32, u32))(MCP_SVC_BASE + svc_id * 8))(arguments[0], arguments[1], arguments[2], arguments[3], arguments[4], arguments[5], arguments[6], arguments[7]); + } + break; + case 3: + // kill + // [cmd_id] + { + serverKilled = true; + } + break; + case 4: + // memcpy + // [dst][src][size] + { + void* dst = (void*)command_buffer[1]; + void* src = (void*)command_buffer[2]; + int size = command_buffer[3]; + + memcpy(dst, src, size); + } + break; + case 5: + // repeated-write + // [address][value][n] + { + u32* dst = (u32*)command_buffer[1]; + u32* cache_range = (u32*)(command_buffer[1] & ~0xFF); + u32 value = command_buffer[2]; + u32 n = command_buffer[3]; + + u32 old = *dst; + int i; + for(i = 0; i < n; i++) + { + if(*dst != old) + { + if(*dst == 0x0) old = *dst; + else + { + *dst = value; + svcFlushDCache(cache_range, 0x100); + break; + } + }else + { + svcInvalidateDCache(cache_range, 0x100); + usleep(50); + } + } + } + break; + default: + // unknown command + return -2; + break; + } + + // no error ! + command_buffer[0] = 0x00000000; + return out_length; +} + +void serverClientHandler(int sock) +{ + u32 command_buffer[0x180]; + + while(!serverKilled) + { + int ret = recv(sock, command_buffer, sizeof(command_buffer), 0); + + if(ret <= 0) break; + + ret = serverCommandHandler(command_buffer, ret); + + if(ret > 0) + { + send(sock, command_buffer, ret, 0); + }else if(ret < 0) + { + send(sock, &ret, sizeof(int), 0); + } + } + + closesocket(sock); +} + +void serverListenClients() +{ + int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + + struct sockaddr_in server; + + memset(&server, 0x00, sizeof(server)); + + server.sin_family = AF_INET; + server.sin_port = 1337; + server.sin_addr.s_addr = 0; + + if(bind(sock, (struct sockaddr *)&server, sizeof(server)) < 0) + { + closesocket(sock); + return; + } + + if(listen(sock, 1) < 0) + { + closesocket(sock); + return; + } + + while(!serverKilled) + { + int csock = accept(sock, NULL, NULL); + if(csock < 0) + break; + + serverClientHandler(csock); + } + + closesocket(sock); +} + +int _main(void *arg) +{ + while(ifmgrnclInit() <= 0) + { + //print(0, 0, "opening /dev/net/ifmgr/ncl..."); + usleep(1000); + } + + while(true) + { + u16 out0, out1; + + int ret0 = IFMGRNCL_GetInterfaceStatus(0, &out0); + if(!ret0 && out0 == 1) break; + + int ret1 = IFMGRNCL_GetInterfaceStatus(1, &out1); + if(!ret1 && out1 == 1) break; + + //print(0, 0, "initializing /dev/net/ifmgr/ncl... %08X %08X %08X %08X ", ret0, ret1, out0, out1); + + usleep(1000); + } + + while(socketInit() <= 0) + { + //print(0, 0, "opening /dev/socket..."); + usleep(1000); + } + + log_init(0xC0A8B203); + + //print(0, 0, "opened /dev/socket !"); + usleep(5*1000*1000); + //print(0, 10, "attempting sockets !"); + + serverKilled = false; + + while(1) + { + if(!serverKilled) + { + serverListenClients(); + } + usleep(1000*1000); + } + return 0; +} + +void _startMainThread(void) +{ + drawSplashScreen(); + + memset((void*)0x050BD000, 0, 0x3000); + + int threadId = svcCreateThread(_main, 0, (u32*)(0x050BD000 + 0x1000), 0x1000, 0x78, 1); + if(threadId >= 0) + svcStartThread(threadId); + + ipc_init(); +} diff --git a/ios_mcp/source/net_ifmgr_ncl.c b/ios_mcp/source/net_ifmgr_ncl.c new file mode 100644 index 0000000..9670542 --- /dev/null +++ b/ios_mcp/source/net_ifmgr_ncl.c @@ -0,0 +1,63 @@ +#include +#include +#include "net_ifmgr_ncl.h" +#include "imports.h" +#include "svc.h" + +static int ifmgrncl_handle = 0; + +int ifmgrnclInit() +{ + if(ifmgrncl_handle) return ifmgrncl_handle; + + int ret = svcOpen("/dev/net/ifmgr/ncl", 0); + + if(ret > 0) + { + ifmgrncl_handle = ret; + return ifmgrncl_handle; + } + + return ret; +} + +int ifmgrnclExit() +{ + int ret = svcClose(ifmgrncl_handle); + + ifmgrncl_handle = 0; + + return ret; +} + +static void* allocIobuf(u32 size) +{ + void* ptr = svcAlloc(0xCAFF, size); + + if(ptr) memset(ptr, 0x00, size); + + return ptr; +} + +static void freeIobuf(void* ptr) +{ + svcFree(0xCAFF, ptr); +} + +int IFMGRNCL_GetInterfaceStatus(u16 interface_id, u16* out_status) +{ + u8* iobuf1 = allocIobuf(0x2); + u16* inbuf = (u16*)iobuf1; + u8* iobuf2 = allocIobuf(0x8); + u16* outbuf = (u16*)iobuf2; + + inbuf[0] = interface_id; + + int ret = svcIoctl(ifmgrncl_handle, 0x14, inbuf, 0x2, outbuf, 0x8); + + if(!ret && out_status) *out_status = outbuf[2]; + + freeIobuf(iobuf1); + freeIobuf(iobuf2); + return ret; +} diff --git a/ios_mcp/source/net_ifmgr_ncl.h b/ios_mcp/source/net_ifmgr_ncl.h new file mode 100644 index 0000000..54a4f6b --- /dev/null +++ b/ios_mcp/source/net_ifmgr_ncl.h @@ -0,0 +1,11 @@ +#ifndef NET_IFMGR_NCL +#define NET_IFMGR_NCL + +#include "types.h" + +int ifmgrnclInit(); +int ifmgrnclExit(); + +int IFMGRNCL_GetInterfaceStatus(u16 interface_id, u16* out_status); + +#endif diff --git a/ios_mcp/source/socket.c b/ios_mcp/source/socket.c new file mode 100644 index 0000000..ca12f99 --- /dev/null +++ b/ios_mcp/source/socket.c @@ -0,0 +1,215 @@ +#include +#include +#include +#include "socket.h" +#include "svc.h" +#include "text.h" +#include "imports.h" + +static int socket_handle = 0; + +int socketInit() +{ + if(socket_handle) return socket_handle; + + int ret = svcOpen("/dev/socket", 0); + + if(ret > 0) + { + socket_handle = ret; + return socket_handle; + } + + return ret; +} + +int socketExit() +{ + int ret = svcClose(socket_handle); + + socket_handle = 0; + + return ret; +} + +static void* allocIobuf(u32 size) +{ + void* ptr = svcAlloc(0xCAFF, size); + + if(ptr) memset(ptr, 0x00, size); + + return ptr; +} + +static void freeIobuf(void* ptr) +{ + svcFree(0xCAFF, ptr); +} + +int socket(int domain, int type, int protocol) +{ + u8* iobuf = allocIobuf(0xC); + u32* inbuf = (u32*)iobuf; + + inbuf[0] = domain; + inbuf[1] = type; + inbuf[2] = protocol; + + int ret = svcIoctl(socket_handle, 0x11, inbuf, 0xC, NULL, 0); + + freeIobuf(iobuf); + return ret; +} + +int closesocket(int sockfd) +{ + u8* iobuf = allocIobuf(0x4); + u32* inbuf = (u32*)iobuf; + + inbuf[0] = sockfd; + + int ret = svcIoctl(socket_handle, 0x3, inbuf, 0x4, NULL, 0); + + freeIobuf(iobuf); + return ret; +} + +int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) +{ + u8* iobuf = allocIobuf(0x18); + u32* inbuf = (u32*)iobuf; + u32* outbuf = (u32*)inbuf; + + inbuf[0] = sockfd; + + int ret = -1; + + if(addr && addrlen && *addrlen == 0x10) + { + inbuf[5] = *addrlen; + + ret = svcIoctl(socket_handle, 0x1, inbuf, 0x18, outbuf, 0x18); + + if(ret >= 0) + { + memcpy(addr, &outbuf[1], outbuf[5]); + *addrlen = outbuf[5]; + } + }else{ + inbuf[5] = 0x10; + + ret = svcIoctl(socket_handle, 0x1, inbuf, 0x18, outbuf, 0x18); + } + + freeIobuf(iobuf); + return ret; +} + +int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) +{ + if(addrlen != 0x10) return -1; + + u8* iobuf = allocIobuf(0x18); + u32* inbuf = (u32*)iobuf; + + inbuf[0] = sockfd; + memcpy(&inbuf[1], addr, addrlen); + inbuf[5] = addrlen; + + int ret = svcIoctl(socket_handle, 0x2, inbuf, 0x18, NULL, 0); + + freeIobuf(iobuf); + return ret; +} + +int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) +{ + if(addrlen != 0x10) return -1; + + u8* iobuf = allocIobuf(0x18); + u32* inbuf = (u32*)iobuf; + + inbuf[0] = sockfd; + memcpy(&inbuf[1], addr, addrlen); + inbuf[5] = addrlen; + + int ret = svcIoctl(socket_handle, 0x4, inbuf, 0x18, NULL, 0); + + freeIobuf(iobuf); + return ret; +} + +int listen(int sockfd, int backlog) +{ + u8* iobuf = allocIobuf(0x8); + u32* inbuf = (u32*)iobuf; + + inbuf[0] = sockfd; + inbuf[1] = backlog; + + int ret = svcIoctl(socket_handle, 0xA, inbuf, 0x8, NULL, 0); + + freeIobuf(iobuf); + return ret; +} + +int recv(int sockfd, void *buf, size_t len, int flags) +{ + if(!len) return -101; + + // TODO : size checks, split up data into multiple vectors if necessary + void* data_buf = svcAllocAlign(0xCAFF, len, 0x40); + if(!data_buf) return -100; + + u8* iobuf = allocIobuf(0x38); + iovec_s* iovec = (iovec_s*)iobuf; + u32* inbuf = (u32*)&iobuf[0x30]; + + inbuf[0] = sockfd; + inbuf[1] = flags; + + iovec[0].ptr = inbuf; + iovec[0].len = 0x8; + iovec[1].ptr = (void*)data_buf; + iovec[1].len = len; + + int ret = svcIoctlv(socket_handle, 0xC, 1, 3, iovec); + + if(ret > 0 && buf) + { + memcpy(buf, data_buf, ret); + } + + freeIobuf(data_buf); + freeIobuf(iobuf); + return ret; +} + +int send(int sockfd, const void *buf, size_t len, int flags) +{ + if(!buf || !len) return -101; + + // TODO : size checks, split up data into multiple vectors if necessary + void* data_buf = svcAllocAlign(0xCAFF, len, 0x40); + if(!data_buf) return -100; + + u8* iobuf = allocIobuf(0x38); + iovec_s* iovec = (iovec_s*)iobuf; + u32* inbuf = (u32*)&iobuf[0x30]; + + memcpy(data_buf, buf, len); + + inbuf[0] = sockfd; + inbuf[1] = flags; + + iovec[0].ptr = inbuf; + iovec[0].len = 0x8; + iovec[1].ptr = (void*)data_buf; + iovec[1].len = len; + + int ret = svcIoctlv(socket_handle, 0xE, 4, 0, iovec); + + freeIobuf(data_buf); + freeIobuf(iobuf); + return ret; +} diff --git a/ios_mcp/source/socket.h b/ios_mcp/source/socket.h new file mode 100644 index 0000000..76d32eb --- /dev/null +++ b/ios_mcp/source/socket.h @@ -0,0 +1,131 @@ +#ifndef SOCKET_H +#define SOCKET_H + +// slightly stolen from ctrulib +#include +#include + +#define SOL_SOCKET 0xFFFF + +#define PF_UNSPEC 0 +#define PF_INET 2 +#define PF_INET6 10 + +#define AF_UNSPEC PF_UNSPEC +#define AF_INET PF_INET +#define AF_INET6 PF_INET6 + +#define SOCK_STREAM 1 +#define SOCK_DGRAM 2 + +#define MSG_CTRUNC 0x01000000 +#define MSG_DONTROUTE 0x02000000 +#define MSG_EOR 0x04000000 +#define MSG_OOB 0x08000000 +#define MSG_PEEK 0x10000000 +#define MSG_TRUNC 0x20000000 +#define MSG_WAITALL 0x40000000 + +#define SHUT_RD 0 +#define SHUT_WR 1 +#define SHUT_RDWR 2 + +#define SO_DEBUG 0x0001 +#define SO_ACCEPTCONN 0x0002 +#define SO_REUSEADDR 0x0004 +#define SO_KEEPALIVE 0x0008 +#define SO_DONTROUTE 0x0010 +#define SO_BROADCAST 0x0020 +#define SO_USELOOPBACK 0x0040 +#define SO_LINGER 0x0080 +#define SO_OOBINLINE 0x0100 +#define SO_REUSEPORT 0x0200 +#define SO_SNDBUF 0x1001 +#define SO_RCVBUF 0x1002 +#define SO_SNDLOWAT 0x1003 +#define SO_RCVLOWAT 0x1004 +#define SO_SNDTIMEO 0x1005 +#define SO_RCVTIMEO 0x1006 +#define SO_ERROR 0x1007 +#define SO_TYPE 0x1008 + +#define INADDR_ANY 0x00000000 +#define INADDR_BROADCAST 0xFFFFFFFF +#define INADDR_NONE 0xFFFFFFFF + +#define INET_ADDRSTRLEN 16 + +#define INADDR_LOOPBACK 0x7f000001 +#define INADDR_ANY 0x00000000 +#define INADDR_BROADCAST 0xFFFFFFFF +#define INADDR_NONE 0xFFFFFFFF + +#define INET_ADDRSTRLEN 16 + +#define IPPROTO_IP 0 /* dummy for IP */ +#define IPPROTO_UDP 17 /* user datagram protocol */ +#define IPPROTO_TCP 6 /* tcp */ + +#define IP_TOS 7 +#define IP_TTL 8 +#define IP_MULTICAST_LOOP 9 +#define IP_MULTICAST_TTL 10 +#define IP_ADD_MEMBERSHIP 11 +#define IP_DROP_MEMBERSHIP 12 + +typedef uint32_t socklen_t; +typedef uint16_t sa_family_t; + +struct sockaddr +{ + sa_family_t sa_family; + char sa_data[]; +}; + +struct sockaddr_storage +{ + sa_family_t ss_family; + char __ss_padding[14]; +}; + +typedef uint16_t in_port_t; +typedef uint32_t in_addr_t; + +struct in_addr { + in_addr_t s_addr; +}; + +struct sockaddr_in { + sa_family_t sin_family; + in_port_t sin_port; + struct in_addr sin_addr; + unsigned char sin_zero[8]; +}; + +struct linger +{ + int l_onoff; + int l_linger; +}; + +int socketInit(); +int socketExit(); + +int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); +int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); +int closesocket(int sockfd); +int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); +int getpeername(int sockfd, struct sockaddr *addr, socklen_t *addrlen); +int getsockname(int sockfd, struct sockaddr *addr, socklen_t *addrlen); +int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen); +int listen(int sockfd, int backlog); +ssize_t recv(int sockfd, void *buf, size_t len, int flags); +ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen); +ssize_t send(int sockfd, const void *buf, size_t len, int flags); +ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen); +int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen); +int shutdown(int sockfd, int how); +int socket(int domain, int type, int protocol); +int sockatmark(int sockfd); + +#endif diff --git a/ios_mcp/source/svc.h b/ios_mcp/source/svc.h new file mode 100644 index 0000000..8aa8aad --- /dev/null +++ b/ios_mcp/source/svc.h @@ -0,0 +1,31 @@ +#ifndef SVC_H +#define SVC_H + +#include "ipc_types.h" + +typedef struct +{ + void* ptr; + u32 len; + u32 unk; +}iovec_s; + +void* svcAlloc(u32 heapid, u32 size); +void* svcAllocAlign(u32 heapid, u32 size, u32 align); +void svcFree(u32 heapid, void* ptr); +int svcOpen(char* name, int mode); +int svcClose(int fd); +int svcIoctl(int fd, u32 request, void* input_buffer, u32 input_buffer_len, void* output_buffer, u32 output_buffer_len); +int svcIoctlv(int fd, u32 request, u32 vector_count_in, u32 vector_count_out, iovec_s* vector); +int svcInvalidateDCache(void* address, u32 size); +int svcFlushDCache(void* address, u32 size); + +int svcCreateThread(int (*callback)(void* arg), void* arg, u32* stack_top, u32 stacksize, int priority, int detached); +int svcStartThread(int threadId); +int svcCreateMessageQueue(u32 *ptr, u32 n_msgs); +int svcRegisterResourceManager(const char* device, int queueid); +int svcReceiveMessage(int queueid, ipcmessage ** ipc_buf, u32 flags); +int svcResourceReply(ipcmessage * ipc_message, u32 result); +u32 svcRead32(u32 addr); + +#endif diff --git a/ios_mcp/source/svc.s b/ios_mcp/source/svc.s new file mode 100644 index 0000000..1abd79a --- /dev/null +++ b/ios_mcp/source/svc.s @@ -0,0 +1,99 @@ +.section ".text" +.arm +.align 4 + +.global svcCreateThread +.type svcCreateThread, %function +svcCreateThread: + .word 0xE7F000F0 + bx lr + +.global svcStartThread +.type svcStartThread, %function +svcStartThread: + .word 0xE7F007F0 + bx lr + +.global svcCreateMessageQueue +.type svcCreateMessageQueue, %function +svcCreateMessageQueue: + .word 0xE7F00CF0 + bx lr + +.global svcReceiveMessage +.type svcReceiveMessage, %function +svcReceiveMessage: + .word 0xE7F010F0 + bx lr + +.global svcAlloc +.type svcAlloc, %function +svcAlloc: + .word 0xE7F027F0 + bx lr + +.global svcAllocAlign +.type svcAllocAlign, %function +svcAllocAlign: + .word 0xE7F028F0 + bx lr + +.global svcFree +.type svcFree, %function +svcFree: + .word 0xE7F029F0 + bx lr + +.global svcRegisterResourceManager +.type svcRegisterResourceManager, %function +svcRegisterResourceManager: + .word 0xE7F02CF0 + bx lr + +.global svcOpen +.type svcOpen, %function +svcOpen: + .word 0xE7F033F0 + bx lr + +.global svcClose +.type svcClose, %function +svcClose: + .word 0xE7F034F0 + bx lr + +.global svcIoctl +.type svcIoctl, %function +svcIoctl: + .word 0xE7F038F0 + bx lr + +.global svcIoctlv +.type svcIoctlv, %function +svcIoctlv: + .word 0xE7F039F0 + bx lr + +.global svcResourceReply +.type svcResourceReply, %function +svcResourceReply: + .word 0xE7F049F0 + bx lr + +.global svcInvalidateDCache +.type svcInvalidateDCache, %function +svcInvalidateDCache: + .word 0xE7F051F0 + bx lr + +.global svcFlushDCache +.type svcFlushDCache, %function +svcFlushDCache: + .word 0xE7F052F0 + bx lr + +.global svcRead32 +.type svcRead32, %function +svcRead32: + .word 0xE7F081F0 + bx lr diff --git a/ios_mcp/source/text.c b/ios_mcp/source/text.c new file mode 100644 index 0000000..8d5b425 --- /dev/null +++ b/ios_mcp/source/text.c @@ -0,0 +1,105 @@ +#include +#include +#include +#include "imports.h" +#include "font_bin.h" + +#define FRAMEBUFFER_ADDRESS (0x14000000+0x38C0000) +#define FRAMEBUFFER_STRIDE (0xE00) +#define FRAMEBUFFER_STRIDE_WORDS (FRAMEBUFFER_STRIDE >> 2) + +#define CHAR_SIZE_X (8) +#define CHAR_SIZE_Y (8) + +static const u8 *launch_image_tga = (const u8*)0x27000000; + +u32* const framebuffer = (u32*)FRAMEBUFFER_ADDRESS; + +void drawSplashScreen(void) +{ + // check if it is an unmapped RGB tga + if(*(u32*)launch_image_tga != 0x00000200) + return; + + int i; + for(i = 0; i < (896 * 504); i++) + { + u32 pixel; + u32 pixelOffset = 0x12 + i * 2; + // access only 4 byte aligned data as the file is in code section + u32 dualPixel = *(u32*)(launch_image_tga + (pixelOffset & ~3)); + + if((pixelOffset & 3) == 0) + { + pixel = ((dualPixel >> 24) & 0xFF) | (((dualPixel >> 16) & 0xFF) << 8); + } + else + { + pixel = ((dualPixel >> 8) & 0xFF) | ((dualPixel & 0xFF) << 8); + } + + framebuffer[i] = (((pixel >> 10) & 0x1F) << (3 + 24)) | (((pixel >> 5) & 0x1F) << (3 + 16)) | ((pixel & 0x1F) << (3 + 8)) | 0xFF; + } +} + +void clearScreen(u32 color) +{ + int i; + for(i = 0; i < 896 * 504; i++) + { + framebuffer[i] = color; + } +} + +void drawCharacter(char c, int x, int y) +{ + if(c < 32)return; + c -= 32; + u8* charData = (u8*)&font_bin[(CHAR_SIZE_X * CHAR_SIZE_Y * c) / 8]; + u32* fb = &framebuffer[x + y * FRAMEBUFFER_STRIDE_WORDS]; + int i, j; + for(i = 0; i < CHAR_SIZE_Y; i++) + { + u8 v= *(charData++); + for(j = 0; j < CHAR_SIZE_X; j++) + { + if(v & 1) *fb = 0x00000000; + else *fb = 0xFFFFFFFF; + v >>= 1; + fb++; + } + fb += FRAMEBUFFER_STRIDE_WORDS - CHAR_SIZE_X; + } +} + +void drawString(char* str, int x, int y) +{ + if(!str) return; + int k; + int dx = 0, dy = 0; + for(k = 0; str[k]; k++) + { + if(str[k] >= 32 && str[k] < 128) drawCharacter(str[k], x + dx, y + dy); + + dx += 8; + + if(str[k] == '\n') + { + dx = 0; + dy -= 8; + } + } +} + +void print(int x, int y, const char *format, ...) +{ + va_list args; + va_start(args, format); + + static char buffer[0x100]; + + vsnprintf(buffer, 0xFF, format, args); + drawString(buffer, x, y); + + va_end(args); +} diff --git a/ios_mcp/source/text.h b/ios_mcp/source/text.h new file mode 100644 index 0000000..b0d5835 --- /dev/null +++ b/ios_mcp/source/text.h @@ -0,0 +1,11 @@ +#ifndef TEXT_H +#define TEXT_H + +#include "types.h" + +void drawSplashScreen(void); +void clearScreen(u32 color); +void drawString(char* str, int x, int y); +void print(int x, int y, const char *format, ...); + +#endif diff --git a/ios_mcp/source/types.h b/ios_mcp/source/types.h new file mode 100644 index 0000000..832bc29 --- /dev/null +++ b/ios_mcp/source/types.h @@ -0,0 +1,29 @@ +#ifndef TYPES_H +#define TYPES_H + + #include + #include + + #define U64_MAX UINT64_MAX + + typedef uint8_t u8; + typedef uint16_t u16; + typedef uint32_t u32; + typedef uint64_t u64; + + typedef int8_t s8; + typedef int16_t s16; + typedef int32_t s32; + typedef int64_t s64; + + typedef volatile u8 vu8; + typedef volatile u16 vu16; + typedef volatile u32 vu32; + typedef volatile u64 vu64; + + typedef volatile s8 vs8; + typedef volatile s16 vs16; + typedef volatile s32 vs32; + typedef volatile s64 vs64; + +#endif diff --git a/ios_mcp/wupclient.py b/ios_mcp/wupclient.py new file mode 100644 index 0000000..9f5c094 --- /dev/null +++ b/ios_mcp/wupclient.py @@ -0,0 +1,756 @@ +# may or may not be inspired by plutoo's ctrrpc +import errno +import socket +import os +import sys +import struct +from time import sleep + +def buffer(size): + return bytearray([0x00] * size) + +def copy_string(buffer, s, offset): + s += "\0" + buffer[offset : (offset + len(s))] = bytearray(s, "ascii") + +def copy_word(buffer, w, offset): + buffer[offset : (offset + 4)] = struct.pack(">I", w) + +def get_string(buffer, offset): + s = buffer[offset:] + if b'\x00' in s: + return s[:s.index(b'\x00')].decode("utf-8") + else: + return s.decode("utf-8") + +class wupclient: + s=None + + def __init__(self, ip='192.168.178.23', port=1337): + self.s=socket.socket() + self.s.connect((ip, port)) + self.fsa_handle = None + self.cwd = "/vol/storage_mlc01" + + def __del__(self): + if self.fsa_handle != None: + self.close(self.fsa_handle) + self.fsa_handle = None + + # fundamental comms + def send(self, command, data): + request = struct.pack('>I', command) + data + + self.s.send(request) + response = self.s.recv(0x600) + + ret = struct.unpack(">I", response[:4])[0] + return (ret, response[4:]) + + # core commands + def read(self, addr, len): + data = struct.pack(">II", addr, len) + ret, data = self.send(1, data) + if ret == 0: + return data + else: + print("read error : %08X" % ret) + return None + + def write(self, addr, data): + data = struct.pack(">I", addr) + data + ret, data = self.send(0, data) + if ret == 0: + return ret + else: + print("write error : %08X" % ret) + return None + + def svc(self, svc_id, arguments): + data = struct.pack(">I", svc_id) + for a in arguments: + data += struct.pack(">I", a) + ret, data = self.send(2, data) + if ret == 0: + return struct.unpack(">I", data)[0] + else: + print("svc error : %08X" % ret) + return None + + def kill(self): + ret, _ = self.send(3, bytearray()) + return ret + + def memcpy(self, dst, src, len): + data = struct.pack(">III", dst, src, len) + ret, data = self.send(4, data) + if ret == 0: + return ret + else: + print("memcpy error : %08X" % ret) + return None + + def repeatwrite(self, dst, val, n): + data = struct.pack(">III", dst, val, n) + ret, data = self.send(5, data) + if ret == 0: + return ret + else: + print("repeatwrite error : %08X" % ret) + return None + + # derivatives + def alloc(self, size, align = None): + if size == 0: + return 0 + if align == None: + return self.svc(0x27, [0xCAFF, size]) + else: + return self.svc(0x28, [0xCAFF, size, align]) + + def free(self, address): + if address == 0: + return 0 + return self.svc(0x29, [0xCAFF, address]) + + def load_buffer(self, b, align = None): + if len(b) == 0: + return 0 + address = self.alloc(len(b), align) + self.write(address, b) + return address + + def load_string(self, s, align = None): + return self.load_buffer(bytearray(s + "\0", "ascii"), align) + + def open(self, device, mode): + address = self.load_string(device) + handle = self.svc(0x33, [address, mode]) + self.free(address) + return handle + + def close(self, handle): + return self.svc(0x34, [handle]) + + def ioctl(self, handle, cmd, inbuf, outbuf_size): + in_address = self.load_buffer(inbuf) + out_data = None + if outbuf_size > 0: + out_address = self.alloc(outbuf_size) + ret = self.svc(0x38, [handle, cmd, in_address, len(inbuf), out_address, outbuf_size]) + out_data = self.read(out_address, outbuf_size) + self.free(out_address) + else: + ret = self.svc(0x38, [handle, cmd, in_address, len(inbuf), 0, 0]) + self.free(in_address) + return (ret, out_data) + + def iovec(self, vecs): + data = bytearray() + for (a, s) in vecs: + data += struct.pack(">III", a, s, 0) + return self.load_buffer(data) + + def ioctlv(self, handle, cmd, inbufs, outbuf_sizes, inbufs_ptr = [], outbufs_ptr = []): + inbufs = [(self.load_buffer(b, 0x40), len(b)) for b in inbufs] + outbufs = [(self.alloc(s, 0x40), s) for s in outbuf_sizes] + iovecs = self.iovec(inbufs + inbufs_ptr + outbufs_ptr + outbufs) + out_data = [] + ret = self.svc(0x39, [handle, cmd, len(inbufs + inbufs_ptr), len(outbufs + outbufs_ptr), iovecs]) + for (a, s) in outbufs: + out_data += [self.read(a, s)] + for (a, _) in (inbufs + outbufs): + self.free(a) + self.free(iovecs) + return (ret, out_data) + + # fsa + def FSA_Mount(self, handle, device_path, volume_path, flags): + inbuffer = buffer(0x520) + copy_string(inbuffer, device_path, 0x0004) + copy_string(inbuffer, volume_path, 0x0284) + copy_word(inbuffer, flags, 0x0504) + (ret, _) = self.ioctlv(handle, 0x01, [inbuffer, bytearray()], [0x293]) + return ret + + def FSA_Unmount(self, handle, path, flags): + inbuffer = buffer(0x520) + copy_string(inbuffer, path, 0x4) + copy_word(inbuffer, flags, 0x284) + (ret, _) = self.ioctl(handle, 0x02, inbuffer, 0x293) + return ret + + def FSA_RawOpen(self, handle, device): + inbuffer = buffer(0x520) + copy_string(inbuffer, device, 0x4) + (ret, data) = self.ioctl(handle, 0x6A, inbuffer, 0x293) + return (ret, struct.unpack(">I", data[4:8])[0]) + + def FSA_OpenDir(self, handle, path): + inbuffer = buffer(0x520) + copy_string(inbuffer, path, 0x4) + (ret, data) = self.ioctl(handle, 0x0A, inbuffer, 0x293) + return (ret, struct.unpack(">I", data[4:8])[0]) + + def FSA_ReadDir(self, handle, dir_handle): + inbuffer = buffer(0x520) + copy_word(inbuffer, dir_handle, 0x4) + (ret, data) = self.ioctl(handle, 0x0B, inbuffer, 0x293) + data = bytearray(data[4:]) + unk = data[:0x64] + if ret == 0: + return (ret, {"name" : get_string(data, 0x64), "is_file" : (unk[0] & 128) != 128, "unk" : unk}) + else: + return (ret, None) + + def FSA_CloseDir(self, handle, dir_handle): + inbuffer = buffer(0x520) + copy_word(inbuffer, dir_handle, 0x4) + (ret, data) = self.ioctl(handle, 0x0D, inbuffer, 0x293) + return ret + + def FSA_OpenFile(self, handle, path, mode): + inbuffer = buffer(0x520) + copy_string(inbuffer, path, 0x4) + copy_string(inbuffer, mode, 0x284) + (ret, data) = self.ioctl(handle, 0x0E, inbuffer, 0x293) + return (ret, struct.unpack(">I", data[4:8])[0]) + + def FSA_MakeDir(self, handle, path, flags): + inbuffer = buffer(0x520) + copy_string(inbuffer, path, 0x4) + copy_word(inbuffer, flags, 0x284) + (ret, _) = self.ioctl(handle, 0x07, inbuffer, 0x293) + return ret + + def FSA_ReadFile(self, handle, file_handle, size, cnt): + inbuffer = buffer(0x520) + copy_word(inbuffer, size, 0x08) + copy_word(inbuffer, cnt, 0x0C) + copy_word(inbuffer, file_handle, 0x14) + (ret, data) = self.ioctlv(handle, 0x0F, [inbuffer], [size * cnt, 0x293]) + return (ret, data[0]) + + def FSA_WriteFile(self, handle, file_handle, data): + inbuffer = buffer(0x520) + copy_word(inbuffer, 1, 0x08) # size + copy_word(inbuffer, len(data), 0x0C) # cnt + copy_word(inbuffer, file_handle, 0x14) + (ret, data) = self.ioctlv(handle, 0x10, [inbuffer, data], [0x293]) + return (ret) + + def FSA_ReadFilePtr(self, handle, file_handle, size, cnt, ptr): + inbuffer = buffer(0x520) + copy_word(inbuffer, size, 0x08) + copy_word(inbuffer, cnt, 0x0C) + copy_word(inbuffer, file_handle, 0x14) + (ret, data) = self.ioctlv(handle, 0x0F, [inbuffer], [0x293], [], [(ptr, size*cnt)]) + return (ret, data[0]) + + def FSA_WriteFilePtr(self, handle, file_handle, size, cnt, ptr): + inbuffer = buffer(0x520) + copy_word(inbuffer, size, 0x08) + copy_word(inbuffer, cnt, 0x0C) + copy_word(inbuffer, file_handle, 0x14) + (ret, data) = self.ioctlv(handle, 0x10, [inbuffer], [0x293], [(ptr, size*cnt)], []) + return (ret) + + def FSA_GetStatFile(self, handle, file_handle): + inbuffer = buffer(0x520) + copy_word(inbuffer, file_handle, 0x4) + (ret, data) = self.ioctl(handle, 0x14, inbuffer, 0x64) + return (ret, struct.unpack(">IIIIIIIIIIIIIIIIIIIIIIIII", data)) + + def FSA_CloseFile(self, handle, file_handle): + inbuffer = buffer(0x520) + copy_word(inbuffer, file_handle, 0x4) + (ret, data) = self.ioctl(handle, 0x15, inbuffer, 0x293) + return ret + + def FSA_ChangeMode(self, handle, path, mode): + mask = 0x777 + inbuffer = buffer(0x520) + copy_string(inbuffer, path, 0x0004) + copy_word(inbuffer, mode, 0x0284) + copy_word(inbuffer, mask, 0x0288) + (ret, _) = self.ioctl(handle, 0x20, inbuffer, 0x293) + return ret + + # mcp + def MCP_InstallGetInfo(self, handle, path): + inbuffer = buffer(0x27F) + copy_string(inbuffer, path, 0x0) + (ret, data) = self.ioctlv(handle, 0x80, [inbuffer], [0x16]) + return (ret, struct.unpack(">IIIIIH", data[0])) + + def MCP_Install(self, handle, path): + inbuffer = buffer(0x27F) + copy_string(inbuffer, path, 0x0) + (ret, _) = self.ioctlv(handle, 0x81, [inbuffer], []) + return ret + + def MCP_InstallGetProgress(self, handle): + (ret, data) = self.ioctl(handle, 0x82, [], 0x24) + return (ret, struct.unpack(">IIIIIIIII", data)) + + def MCP_CopyTitle(self, handle, path, dst_device_id, flush): + inbuffer = buffer(0x27F) + copy_string(inbuffer, path, 0x0) + inbuffer2 = buffer(0x4) + copy_word(inbuffer2, dst_device_id, 0x0) + inbuffer3 = buffer(0x4) + copy_word(inbuffer3, flush, 0x0) + (ret, _) = self.ioctlv(handle, 0x85, [inbuffer, inbuffer2, inbuffer3], []) + return ret + + def MCP_InstallSetTargetDevice(self, handle, device): + inbuffer = buffer(0x4) + copy_word(inbuffer, device, 0x0) + (ret, _) = self.ioctl(handle, 0x8D, inbuffer, 0) + return ret + + def MCP_InstallSetTargetUsb(self, handle, device): + inbuffer = buffer(0x4) + copy_word(inbuffer, device, 0x0) + (ret, _) = self.ioctl(handle, 0xF1, inbuffer, 0) + return ret + + # syslog (tmp) + def dump_syslog(self): + syslog_address = struct.unpack(">I", self.read(0x05095ECC, 4))[0] + 0x10 + block_size = 0x400 + for i in range(0, 0x40000, block_size): + data = self.read(syslog_address + i, 0x400) + # if 0 in data: + # print(data[:data.index(0)].decode("ascii")) + # break + # else: + print(data.decode("ascii")) + + # file management + def get_fsa_handle(self): + if self.fsa_handle == None: + self.fsa_handle = self.open("/dev/fsa", 0) + return self.fsa_handle + + def mkdir(self, path, flags): + fsa_handle = self.get_fsa_handle() + if path[0] != "/": + path = self.cwd + "/" + path + ret = w.FSA_MakeDir(fsa_handle, path, flags) + if ret == 0: + return 0 + else: + print("mkdir error (%s, %08X)" % (path, ret)) + return ret + + def chmod(self, filename, flags): + fsa_handle = self.get_fsa_handle() + if filename[0] != "/": + filename = self.cwd + "/" + filename + ret = w.FSA_ChangeMode(fsa_handle, filename, flags) + print("chmod returned : " + hex(ret)) + + def cd(self, path): + if path[0] != "/" and self.cwd[0] == "/": + return self.cd(self.cwd + "/" + path) + fsa_handle = self.get_fsa_handle() + ret, dir_handle = self.FSA_OpenDir(fsa_handle, path if path != None else self.cwd) + if ret == 0: + self.cwd = path + self.FSA_CloseDir(fsa_handle, dir_handle) + return 0 + else: + print("cd error : path does not exist (%s)" % (path)) + return -1 + + def ls(self, path = None, return_data = False): + fsa_handle = self.get_fsa_handle() + if path != None and path[0] != "/": + path = self.cwd + "/" + path + ret, dir_handle = self.FSA_OpenDir(fsa_handle, path if path != None else self.cwd) + if ret != 0x0: + print("opendir error : " + hex(ret)) + return [] if return_data else None + entries = [] + while True: + ret, data = self.FSA_ReadDir(fsa_handle, dir_handle) + if ret != 0: + break + if not(return_data): + if data["is_file"]: + print(" %s" % data["name"]) + else: + print(" %s/" % data["name"]) + else: + entries += [data] + ret = self.FSA_CloseDir(fsa_handle, dir_handle) + return entries if return_data else None + + def dldir(self, path): + if path[0] != "/": + path = self.cwd + "/" + path + entries = self.ls(path, True) + for e in entries: + if e["is_file"]: + print(e["name"]) + self.dl(path + "/" + e["name"],path[1:]) + else: + print(e["name"] + "/") + self.dldir(path + "/" + e["name"]) + + def cpdir(self, srcpath, dstpath): + entries = self.ls(srcpath, True) + q = [(srcpath, dstpath, e) for e in entries] + while len(q) > 0: + _srcpath, _dstpath, e = q.pop() + _srcpath += "/" + e["name"] + _dstpath += "/" + e["name"] + if e["is_file"]: + print(e["name"]) + self.cp(_srcpath, _dstpath) + else: + self.mkdir(_dstpath, 0x600) + entries = self.ls(_srcpath, True) + q += [(_srcpath, _dstpath, e) for e in entries] + + def pwd(self): + return self.cwd + + def cp(self, filename_in, filename_out): + fsa_handle = self.get_fsa_handle() + ret, in_file_handle = self.FSA_OpenFile(fsa_handle, filename_in, "r") + if ret != 0x0: + print("cp error : could not open " + filename_in) + return + ret, out_file_handle = self.FSA_OpenFile(fsa_handle, filename_out, "w") + if ret != 0x0: + print("cp error : could not open " + filename_out) + return + block_size = 0x10000 + buffer = self.alloc(block_size, 0x40) + k = 0 + while True: + ret, _ = self.FSA_ReadFilePtr(fsa_handle, in_file_handle, 0x1, block_size, buffer) + k += ret + ret = self.FSA_WriteFilePtr(fsa_handle, out_file_handle, 0x1, ret, buffer) + sys.stdout.write(hex(k) + "\r"); sys.stdout.flush(); + if ret < block_size: + break + self.free(buffer) + ret = self.FSA_CloseFile(fsa_handle, out_file_handle) + ret = self.FSA_CloseFile(fsa_handle, in_file_handle) + + def df(self, filename_out, src, size): + fsa_handle = self.get_fsa_handle() + ret, out_file_handle = self.FSA_OpenFile(fsa_handle, filename_out, "w") + if ret != 0x0: + print("df error : could not open " + filename_out) + return + block_size = 0x10000 + buffer = self.alloc(block_size, 0x40) + k = 0 + while k < size: + cur_size = min(size - k, block_size) + self.memcpy(buffer, src + k, cur_size) + k += cur_size + ret = self.FSA_WriteFilePtr(fsa_handle, out_file_handle, 0x1, cur_size, buffer) + sys.stdout.write(hex(k) + " (%f) " % (float(k * 100) / size) + "\r"); sys.stdout.flush(); + self.free(buffer) + ret = self.FSA_CloseFile(fsa_handle, out_file_handle) + + def dl(self, filename, directorypath = None, local_filename = None): + fsa_handle = self.get_fsa_handle() + if filename[0] != "/": + filename = self.cwd + "/" + filename + if local_filename == None: + if "/" in filename: + local_filename = filename[[i for i, x in enumerate(filename) if x == "/"][-1]+1:] + else: + local_filename = filename + ret, file_handle = self.FSA_OpenFile(fsa_handle, filename, "r") + if ret != 0x0: + print("dl error : could not open " + filename) + return + buffer = bytearray() + block_size = 0x400 + while True: + ret, data = self.FSA_ReadFile(fsa_handle, file_handle, 0x1, block_size) + # print(hex(ret), data) + buffer += data[:ret] + sys.stdout.write(hex(len(buffer)) + "\r"); sys.stdout.flush(); + if ret < block_size: + break + ret = self.FSA_CloseFile(fsa_handle, file_handle) + if directorypath == None: + open(local_filename, "wb").write(buffer) + else: + dir_path = os.path.dirname(os.path.abspath(sys.argv[0])).replace('\\','/') + fullpath = dir_path + "/" + directorypath + "/" + fullpath = fullpath.replace("//","/") + mkdir_p(fullpath) + open(fullpath + local_filename, "wb").write(buffer) + + def mkdir_p(path): + try: + os.makedirs(path) + except OSError as exc: # Python >2.5 + if exc.errno == errno.EEXIST and os.path.isdir(path): + pass + else: + raise + + def fr(self, filename, offset, size): + fsa_handle = self.get_fsa_handle() + if filename[0] != "/": + filename = self.cwd + "/" + filename + ret, file_handle = self.FSA_OpenFile(fsa_handle, filename, "r") + if ret != 0x0: + print("fr error : could not open " + filename) + return + buffer = bytearray() + block_size = 0x400 + while True: + ret, data = self.FSA_ReadFile(fsa_handle, file_handle, 0x1, block_size if (block_size < size) else size) + buffer += data[:ret] + sys.stdout.write(hex(len(buffer)) + "\r"); sys.stdout.flush(); + if len(buffer) >= size: + break + ret = self.FSA_CloseFile(fsa_handle, file_handle) + return buffer + + def fw(self, filename, offset, buffer): + fsa_handle = self.get_fsa_handle() + if filename[0] != "/": + filename = self.cwd + "/" + filename + ret, file_handle = self.FSA_OpenFile(fsa_handle, filename, "r+") + if ret != 0x0: + print("fw error : could not open " + filename) + return + block_size = 0x400 + k = 0 + while True: + cur_size = min(len(buffer) - k, block_size) + if cur_size <= 0: + break + sys.stdout.write(hex(k) + "\r"); sys.stdout.flush(); + ret = self.FSA_WriteFile(fsa_handle, file_handle, buffer[k:(k+cur_size)]) + k += cur_size + ret = self.FSA_CloseFile(fsa_handle, file_handle) + + def stat(self, filename): + fsa_handle = self.get_fsa_handle() + if filename[0] != "/": + filename = self.cwd + "/" + filename + ret, file_handle = self.FSA_OpenFile(fsa_handle, filename, "r") + if ret != 0x0: + print("stat error : could not open " + filename) + return + (ret, stats) = self.FSA_GetStatFile(fsa_handle, file_handle) + if ret != 0x0: + print("stat error : " + hex(ret)) + else: + print("flags: " + hex(stats[1])) + print("mode: " + hex(stats[2])) + print("owner: " + hex(stats[3])) + print("group: " + hex(stats[4])) + print("size: " + hex(stats[5])) + ret = self.FSA_CloseFile(fsa_handle, file_handle) + + def up(self, local_filename, filename = None): + fsa_handle = self.get_fsa_handle() + if filename == None: + if "/" in local_filename: + filename = local_filename[[i for i, x in enumerate(local_filename) if x == "/"][-1]+1:] + else: + filename = local_filename + if filename[0] != "/": + filename = self.cwd + "/" + filename + f = open(local_filename, "rb") + ret, file_handle = self.FSA_OpenFile(fsa_handle, filename, "w") + if ret != 0x0: + print("up error : could not open " + filename) + return + progress = 0 + block_size = 0x400 + while True: + data = f.read(block_size) + ret = self.FSA_WriteFile(fsa_handle, file_handle, data) + progress += len(data) + sys.stdout.write(hex(progress) + "\r"); sys.stdout.flush(); + if len(data) < block_size: + break + ret = self.FSA_CloseFile(fsa_handle, file_handle) + +def mkdir_p(path): + try: + os.makedirs(path) + except OSError as exc: + if exc.errno == errno.EEXIST and os.path.isdir(path): + pass + else: + raise + +def mount_sd(): + handle = w.open("/dev/fsa", 0) + print(hex(handle)) + + ret = w.FSA_Mount(handle, "/dev/sdcard01", "/vol/storage_sdcard", 2) + print(hex(ret)) + + ret = w.close(handle) + print(hex(ret)) + +def unmount_sd(): + handle = w.open("/dev/fsa", 0) + print(hex(handle)) + + ret = w.FSA_Unmount(handle, "/vol/storage_sdcard", 2) + print(hex(ret)) + + ret = w.close(handle) + print(hex(ret)) + +def mount_slccmpt01(): + handle = w.open("/dev/fsa", 0) + print(hex(handle)) + + ret = w.FSA_Mount(handle, "/dev/slccmpt01", "/vol/storage_slccmpt01", 2) + print(hex(ret)) + + ret = w.close(handle) + print(hex(ret)) + +def unmount_slccmpt01(): + handle = w.open("/dev/fsa", 0) + print(hex(handle)) + + ret = w.FSA_Unmount(handle, "/vol/storage_slccmpt01", 2) + print(hex(ret)) + + ret = w.close(handle) + print(hex(ret)) + +def mount_odd_content(): + handle = w.open("/dev/fsa", 0) + print(hex(handle)) + + ret = w.FSA_Mount(handle, "/dev/odd03", "/vol/storage_odd_content", 2) + print(hex(ret)) + + ret = w.close(handle) + print(hex(ret)) + +def unmount_odd_content(): + handle = w.open("/dev/fsa", 0) + print(hex(handle)) + + ret = w.FSA_Unmount(handle, "/vol/storage_odd_content", 2) + print(hex(ret)) + + ret = w.close(handle) + print(hex(ret)) + +def mount_odd_update(): + handle = w.open("/dev/fsa", 0) + print(hex(handle)) + + ret = w.FSA_Mount(handle, "/dev/odd02", "/vol/storage_odd_update", 2) + print(hex(ret)) + + ret = w.close(handle) + print(hex(ret)) + +def unmount_odd_update(): + handle = w.open("/dev/fsa", 0) + print(hex(handle)) + + ret = w.FSA_Unmount(handle, "/vol/storage_odd_update", 2) + print(hex(ret)) + + ret = w.close(handle) + print(hex(ret)) + +def mount_odd_tickets(): + handle = w.open("/dev/fsa", 0) + print(hex(handle)) + + ret = w.FSA_Mount(handle, "/dev/odd01", "/vol/storage_odd_tickets", 2) + print(hex(ret)) + + ret = w.close(handle) + print(hex(ret)) + +def unmount_odd_tickets(): + handle = w.open("/dev/fsa", 0) + print(hex(handle)) + + ret = w.FSA_Unmount(handle, "/vol/storage_odd_tickets", 2) + print(hex(ret)) + + ret = w.close(handle) + print(hex(ret)) + +def install_title(path, installToUsb = 0): + mcp_handle = w.open("/dev/mcp", 0) + print(hex(mcp_handle)) + + ret, data = w.MCP_InstallGetInfo(mcp_handle, "/vol/storage_sdcard/"+path) + print("install info : " + hex(ret), [hex(v) for v in data]) + if ret != 0: + ret = w.close(mcp_handle) + print(hex(ret)) + return + + ret = w.MCP_InstallSetTargetDevice(mcp_handle, installToUsb) + print("install set target device : " + hex(ret)) + if ret != 0: + ret = w.close(mcp_handle) + print(hex(ret)) + return + + ret = w.MCP_InstallSetTargetUsb(mcp_handle, installToUsb) + print("install set target usb : " + hex(ret)) + if ret != 0: + ret = w.close(mcp_handle) + print(hex(ret)) + return + + ret = w.MCP_Install(mcp_handle, "/vol/storage_sdcard/"+path) + print("install : " + hex(ret)) + + ret = w.close(mcp_handle) + print(hex(ret)) + +def get_nim_status(): + nim_handle = w.open("/dev/nim", 0) + print(hex(nim_handle)) + + inbuffer = buffer(0x80) + (ret, data) = w.ioctlv(nim_handle, 0x00, [inbuffer], [0x80]) + + print(hex(ret), "".join("%02X" % v for v in data[0])) + + ret = w.close(nim_handle) + print(hex(ret)) + +def read_and_print(adr, size): + data = w.read(adr, size) + data = struct.unpack(">%dI" % (len(data) // 4), data) + for i in range(0, len(data), 4): + print(" ".join("%08X"%v for v in data[i:i+4])) + +if __name__ == '__main__': + w = wupclient() + # mount_sd() + # mount_odd_content() + + # w.up("/media/harddisk1/loadiine_code/homebrew_launcher_rpx/homebrew_launcher.rpx", "homebrew_launcher_rpx.rpx") + # w.up("/media/harddisk1/gx2sploit/gx2sploit.rpx", "homebrew_launcher_rpx.rpx") + # print(w.pwd()) + # w.ls() + w.dump_syslog() + # w.mkdir("/vol/storage_sdcard/usr", 0x600) + # install_title("install", 1) + # get_nim_status() + # w.kill() diff --git a/ios_usb/Makefile b/ios_usb/Makefile new file mode 100644 index 0000000..083d180 --- /dev/null +++ b/ios_usb/Makefile @@ -0,0 +1,80 @@ +ifeq ($(strip $(DEVKITARM)),) +$(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") +endif + +ifeq ($(filter $(DEVKITARM)/bin,$(PATH)),) +export PATH:=$(DEVKITARM)/bin:$(PATH) +endif + +CC = arm-none-eabi-gcc +LINK = arm-none-eabi-gcc +AS = arm-none-eabi-as +OBJCOPY = arm-none-eabi-objcopy +OBJDUMP = arm-none-eabi-objdump +CFLAGS += -Wall -mbig-endian -std=gnu11 -mcpu=arm926ej-s -msoft-float -mfloat-abi=soft -Os +LDFLAGS += -nostartfiles -nodefaultlibs -mbig-endian -Wl,-T,link.ld +LIBDIRS += -L$(CURDIR)/../libs +LIBS += -lgcc + +CFILES = $(wildcard source/*.c) +BINFILES = $(wildcard data/*.bin) +OFILES = $(BINFILES:data/%.bin=build/%.bin.o) +OFILES += $(CFILES:source/%.c=build/%.o) +DFILES = $(CFILES:source/%.c=build/%.d) +SFILES = $(wildcard source/*.s) +OFILES += $(SFILES:source/%.s=build/%.o) +PROJECTNAME = ${shell basename "$(CURDIR)"} +CWD = "$(CURDIR)"" + +#--------------------------------------------------------------------------------- +# canned command sequence for binary data, taken from devkitARM +#--------------------------------------------------------------------------------- +define bin2o + bin2s $< | $(AS) -EB -o $(@) +endef + +.PHONY:=all dirs + +all: dirs $(PROJECTNAME).bin $(PROJECTNAME)_syms.h $(PROJECTNAME).bin $(PROJECTNAME).bin.h + +dirs: + @mkdir -p build + +$(PROJECTNAME).elf: $(OFILES) + @echo "LD $@" + @$(LINK) $(LDFLAGS) -o $(PROJECTNAME).elf $(sort $(filter-out build/crt0.o, $(OFILES))) $(LIBDIRS) $(LIBS) + +$(PROJECTNAME).bin: $(PROJECTNAME).elf + @echo "OBJCOPY $@\n" + @$(OBJCOPY) -j .text -j .rodata -j .data -O binary $(PROJECTNAME).elf $@ + +$(PROJECTNAME).bin.h: $(PROJECTNAME).bin + @xxd -i $< | sed "s/unsigned/static const unsigned/g;s/$(PROJECTNAME)$*/$(PROJECTNAME)/g" > $@ + +$(PROJECTNAME)_syms.h: + @echo "#ifndef $(PROJECTNAME)_SYMS_H" > $@ + @echo "#define $(PROJECTNAME)_SYMS_H" >> $@ + @$(OBJDUMP) -EB -t -marm $(PROJECTNAME).elf | grep 'g F .text' | grep -v '.hidden' | awk '{print "#define " $$6 " 0x" $$1}' >> $@ + @$(OBJDUMP) -EB -t -marm $(PROJECTNAME).elf | grep -e 'g .text' -e '_bss_' | awk '{print "#define " $$5 " 0x" $$1}' >> $@ + @echo "#endif" >> $@ + +clean: + @rm -f build/*.o build/*.d + @rm -f $(PROJECTNAME).elf $(PROJECTNAME).bin $(PROJECTNAME)_syms.h $(PROJECTNAME).bin $(PROJECTNAME).bin.h + @echo "all cleaned up !" + +-include $(DFILES) + +build/%.o: source/%.c + @echo "CC $(notdir $<)" + @$(CC) $(CFLAGS) -c $< -o $@ + @$(CC) -MM $< > build/$*.d + +build/%.o: source/%.s + @echo "CC $(notdir $<)" + @$(CC) $(CFLAGS) -xassembler-with-cpp -c $< -o $@ + @$(CC) -MM $< > build/$*.d + +build/%.bin.o: data/%.bin + @echo "BIN $(notdir $<)" + @$(bin2o) diff --git a/ios_usb/link.ld b/ios_usb/link.ld new file mode 100644 index 0000000..d313e5b --- /dev/null +++ b/ios_usb/link.ld @@ -0,0 +1,17 @@ +OUTPUT_ARCH(arm) + +SECTIONS +{ + .text 0x101312D0 : { + _text_start = .; + build/crt0.o(.init) + *(.text*); + *(.rodata*); + } + _text_end = .; + + /DISCARD/ : { + *(*); + } +} + diff --git a/ios_usb/source/crt0.s b/ios_usb/source/crt0.s new file mode 100644 index 0000000..83d7bb6 --- /dev/null +++ b/ios_usb/source/crt0.s @@ -0,0 +1,9 @@ +.section ".init" +.arm +.align 4 + +.extern _main +.type _main, %function + +_start: + b _main diff --git a/ios_usb/source/main.c b/ios_usb/source/main.c new file mode 100644 index 0000000..25da595 --- /dev/null +++ b/ios_usb/source/main.c @@ -0,0 +1,26 @@ +void _main() +{ + + void(*ios_shutdown)(int) = (void(*)(int))0x1012EE4C; + + int(*reply)(int, int) = (int(*)(int, int))0x1012ED04; + + int saved_handle = *(volatile int*)0x0012F000; + int myret = reply(saved_handle, 0); + if (myret != 0) + ios_shutdown(1); + + // stack pointer will be 0x1016AE30 + // link register will be 0x1012EACC + asm("LDR SP, newsp\n" + "LDR R0, newr0\n" + "LDR LR, newlr\n" + "LDR PC, newpc\n" + "newsp: .word 0x1016AE30\n" + "newlr: .word 0x1012EACC\n" + "newr0: .word 0x10146080\n" + "newpc: .word 0x10111164\n"); + + + +} diff --git a/libs/libc.a b/libs/libc.a new file mode 100644 index 0000000000000000000000000000000000000000..10cb849cece0e7d380eadc54dd496eb95f1275a7 GIT binary patch literal 909796 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≫fs7D$(S@Ar}6*aF^10#W$|Np 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

Ne-ilJg8v1~NT1gNhT!-7Tf_}e!{30J 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 +#include +#include +#include +#include +#include +#include "cfw_config.h" +#include "fs/fs_utils.h" + +static int split_string(const char *string, char splitChar, char *left, char *right, int size) +{ + int cnt = 0; + char *writePtr = left; + + while(*string != '\0' && *string != '\n' && *string != '\r' && *string != splitChar && (cnt+1) < size) + { + *writePtr++ = *string++; + cnt++; + } + + *writePtr = 0; + *right = 0; + + writePtr--; + + // remove trailing spaces + while(writePtr > left && *writePtr == ' ') + *writePtr-- = 0; + + if(*string == splitChar) + { + string++; + writePtr = right; + + // skip spaces after split character + while(*string == ' ') + string++; + + cnt = 0; + while(*string != '\0' && *string != '\n' && *string != '\r' && (cnt+1) < size) + { + *writePtr++ = *string++; + } + *writePtr = 0; + return 1; + } + else + { + return -1; + } +} + +void default_config(cfw_config_t * config) +{ + memset(config, 0, sizeof(cfw_config_t)); + config->viewMode = 0; + config->directLaunch = 0; + config->launchImage = 1; + config->redNAND = 0; + config->seeprom_red = 0; + config->otp_red = 0; + config->syshaxXml = 0; +} + +int read_config(cfw_config_t * config) +{ + FILE *pFile = fopen(CONFIG_PATH, "rb"); + if(!pFile) + return -1; + + char option[64]; + char value[64]; + char line[0x100]; + + while(fgets(line, sizeof(line), pFile) != 0) + { + if(line[0] == '#' || line[0] == '[') + continue; + + if(split_string(line, '=', option, value, sizeof(option)) == 1) + { + if(strcmp(option, "directLaunch") == 0) + config->directLaunch = atoi(value); + else if(strcmp(option, "launchImage") == 0) + config->launchImage = atoi(value); + else if(strcmp(option, "redNAND") == 0) + config->redNAND = atoi(value); + else if(strcmp(option, "seeprom_red") == 0) + config->seeprom_red = atoi(value); + else if(strcmp(option, "otp_red") == 0) + config->otp_red = atoi(value); + else if(strcmp(option, "syshaxXml") == 0) + config->syshaxXml = atoi(value); + else if(strcmp(option, "viewMode") == 0) + config->viewMode = atoi(value); + } + } + + fclose(pFile); + return 0; +} + +int write_config(cfw_config_t * config) +{ + CreateSubfolder(APP_PATH); + + FILE *pFile = fopen(CONFIG_PATH, "wb"); + if(!pFile) + return -1; + + fprintf(pFile, "[RIOSUHAX]\n"); + fprintf(pFile, "viewMode=%i\n", config->viewMode); + fprintf(pFile, "directLaunch=%i\n", config->directLaunch); + fprintf(pFile, "launchImage=%i\n", config->launchImage); + fprintf(pFile, "redNAND=%i\n", config->redNAND); + fprintf(pFile, "seeprom_red=%i\n", config->seeprom_red); + fprintf(pFile, "otp_red=%i\n", config->otp_red); + fprintf(pFile, "syshaxXml=%i\n", config->syshaxXml); + fclose(pFile); + return 0; +} diff --git a/src/cfw_config.h b/src/cfw_config.h new file mode 100644 index 0000000..c49972a --- /dev/null +++ b/src/cfw_config.h @@ -0,0 +1,46 @@ +/*************************************************************************** + * Copyright (C) 2016 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef CFW_CONFIG_H_ +#define CFW_CONFIG_H_ + +#define APP_VERSION "v0.1" +#define APP_PATH "sd:/wiiu/apps/mocha" +#define CONFIG_PATH (APP_PATH "/config.ini") + +typedef struct +{ + int viewMode; + int directLaunch; + int launchImage; + int redNAND; + int seeprom_red; + int otp_red; + int syshaxXml; +} cfw_config_t; + +void default_config(cfw_config_t * config); +int read_config(cfw_config_t * config); +int write_config(cfw_config_t * config); + +#endif diff --git a/src/common/common.h b/src/common/common.h new file mode 100644 index 0000000..538b5ad --- /dev/null +++ b/src/common/common.h @@ -0,0 +1,36 @@ +#ifndef COMMON_H +#define COMMON_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "os_defs.h" + +#define CAFE_OS_SD_PATH "/vol/external01" +#define SD_PATH "sd:" +#define WIIU_PATH "/wiiu" + +#ifndef MEM_BASE +#define MEM_BASE (0x00800000) +#endif + +#define ELF_DATA_ADDR (*(volatile unsigned int*)(MEM_BASE + 0x1300 + 0x00)) +#define ELF_DATA_SIZE (*(volatile unsigned int*)(MEM_BASE + 0x1300 + 0x04)) +#define MAIN_ENTRY_ADDR (*(volatile unsigned int*)(MEM_BASE + 0x1400 + 0x00)) +#define OS_FIRMWARE (*(volatile unsigned int*)(MEM_BASE + 0x1400 + 0x04)) + +#define OS_SPECIFICS ((OsSpecifics*)(MEM_BASE + 0x1500)) + +#ifndef EXIT_SUCCESS +#define EXIT_SUCCESS 0 +#endif +#define EXIT_HBL_EXIT 0xFFFFFFFE +#define EXIT_RELAUNCH_ON_LOAD 0xFFFFFFFD + +#ifdef __cplusplus +} +#endif + +#endif /* COMMON_H */ + diff --git a/src/common/fs_defs.h b/src/common/fs_defs.h new file mode 100644 index 0000000..feda725 --- /dev/null +++ b/src/common/fs_defs.h @@ -0,0 +1,62 @@ +#ifndef FS_DEFS_H +#define FS_DEFS_H + +#include "types.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/* FS defines and types */ +#define FS_MAX_LOCALPATH_SIZE 511 +#define FS_MAX_MOUNTPATH_SIZE 128 +#define FS_MAX_FULLPATH_SIZE (FS_MAX_LOCALPATH_SIZE + FS_MAX_MOUNTPATH_SIZE) +#define FS_MAX_ARGPATH_SIZE FS_MAX_FULLPATH_SIZE + +#define FS_STATUS_OK 0 +#define FS_RET_UNSUPPORTED_CMD 0x0400 +#define FS_RET_NO_ERROR 0x0000 +#define FS_RET_ALL_ERROR (unsigned int)(-1) + +#define FS_STAT_FLAG_IS_DIRECTORY 0x80000000 + +/* max length of file/dir name */ +#define FS_MAX_ENTNAME_SIZE 256 + +#define FS_SOURCETYPE_EXTERNAL 0 +#define FS_SOURCETYPE_HFIO 1 +#define FS_SOURCETYPE_HFIO 1 + +#define FS_MOUNT_SOURCE_SIZE 0x300 +#define FS_CLIENT_SIZE 0x1700 +#define FS_CMD_BLOCK_SIZE 0xA80 + +typedef struct +{ + uint32_t flag; + uint32_t permission; + uint32_t owner_id; + uint32_t group_id; + uint32_t size; + uint32_t alloc_size; + uint64_t quota_size; + uint32_t ent_id; + uint64_t ctime; + uint64_t mtime; + uint8_t attributes[48]; +} __attribute__((packed)) FSStat; + +typedef struct +{ + FSStat stat; + char name[FS_MAX_ENTNAME_SIZE]; +} FSDirEntry; + + +#ifdef __cplusplus +} +#endif + +#endif /* FS_DEFS_H */ + diff --git a/src/common/os_defs.h b/src/common/os_defs.h new file mode 100644 index 0000000..48a4c8f --- /dev/null +++ b/src/common/os_defs.h @@ -0,0 +1,25 @@ +#ifndef __OS_DEFS_H_ +#define __OS_DEFS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _OsSpecifics +{ + unsigned int addr_OSDynLoad_Acquire; + unsigned int addr_OSDynLoad_FindExport; + unsigned int addr_OSTitle_main_entry; + + unsigned int addr_KernSyscallTbl1; + unsigned int addr_KernSyscallTbl2; + unsigned int addr_KernSyscallTbl3; + unsigned int addr_KernSyscallTbl4; + unsigned int addr_KernSyscallTbl5; +} OsSpecifics; + +#ifdef __cplusplus +} +#endif + +#endif // __OS_DEFS_H_ diff --git a/src/common/types.h b/src/common/types.h new file mode 100644 index 0000000..3435e56 --- /dev/null +++ b/src/common/types.h @@ -0,0 +1,7 @@ +#ifndef TYPES_H +#define TYPES_H + +#include + +#endif /* TYPES_H */ + diff --git a/src/dynamic_libs/.gitattributes b/src/dynamic_libs/.gitattributes new file mode 100644 index 0000000..bdb0cab --- /dev/null +++ b/src/dynamic_libs/.gitattributes @@ -0,0 +1,17 @@ +# Auto detect text files and perform LF normalization +* text=auto + +# Custom for Visual Studio +*.cs diff=csharp + +# Standard to msysgit +*.doc diff=astextplain +*.DOC diff=astextplain +*.docx diff=astextplain +*.DOCX diff=astextplain +*.dot diff=astextplain +*.DOT diff=astextplain +*.pdf diff=astextplain +*.PDF diff=astextplain +*.rtf diff=astextplain +*.RTF diff=astextplain diff --git a/src/dynamic_libs/.gitignore b/src/dynamic_libs/.gitignore new file mode 100644 index 0000000..cd2946a --- /dev/null +++ b/src/dynamic_libs/.gitignore @@ -0,0 +1,47 @@ +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msm +*.msp + +# Windows shortcuts +*.lnk + +# ========================= +# Operating System Files +# ========================= + +# OSX +# ========================= + +.DS_Store +.AppleDouble +.LSOverride + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk diff --git a/src/dynamic_libs/README.md b/src/dynamic_libs/README.md new file mode 100644 index 0000000..be82302 --- /dev/null +++ b/src/dynamic_libs/README.md @@ -0,0 +1,2 @@ +# dynamic_libs +Dynamic libs for WiiU homebrew diff --git a/src/dynamic_libs/fs_defs.h b/src/dynamic_libs/fs_defs.h new file mode 100644 index 0000000..1b1bc41 --- /dev/null +++ b/src/dynamic_libs/fs_defs.h @@ -0,0 +1,61 @@ +#ifndef FS_DEFS_H +#define FS_DEFS_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +/* FS defines and types */ +#define FS_MAX_LOCALPATH_SIZE 511 +#define FS_MAX_MOUNTPATH_SIZE 128 +#define FS_MAX_FULLPATH_SIZE (FS_MAX_LOCALPATH_SIZE + FS_MAX_MOUNTPATH_SIZE) +#define FS_MAX_ARGPATH_SIZE FS_MAX_FULLPATH_SIZE + +#define FS_STATUS_OK 0 +#define FS_RET_UNSUPPORTED_CMD 0x0400 +#define FS_RET_NO_ERROR 0x0000 +#define FS_RET_ALL_ERROR (unsigned int)(-1) + +#define FS_STAT_FLAG_IS_DIRECTORY 0x80000000 + +/* max length of file/dir name */ +#define FS_MAX_ENTNAME_SIZE 256 + +#define FS_SOURCETYPE_EXTERNAL 0 +#define FS_SOURCETYPE_HFIO 1 + +#define FS_MOUNT_SOURCE_SIZE 0x300 +#define FS_CLIENT_SIZE 0x1700 +#define FS_CMD_BLOCK_SIZE 0xA80 + +typedef struct +{ + uint32_t flag; + uint32_t permission; + uint32_t owner_id; + uint32_t group_id; + uint32_t size; + uint32_t alloc_size; + uint64_t quota_size; + uint32_t ent_id; + uint64_t ctime; + uint64_t mtime; + uint8_t attributes[48]; +} __attribute__((packed)) FSStat; + +typedef struct +{ + FSStat stat; + char name[FS_MAX_ENTNAME_SIZE]; +} FSDirEntry; + + +#ifdef __cplusplus +} +#endif + +#endif /* FS_DEFS_H */ + diff --git a/src/dynamic_libs/fs_functions.c b/src/dynamic_libs/fs_functions.c new file mode 100644 index 0000000..08a4fb6 --- /dev/null +++ b/src/dynamic_libs/fs_functions.c @@ -0,0 +1,131 @@ +/**************************************************************************** + * Copyright (C) 2015 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include "fs_functions.h" +#include "os_functions.h" + +EXPORT_DECL(int, FSInit, void); +EXPORT_DECL(int, FSShutdown, void); +EXPORT_DECL(int, FSAddClientEx, void *pClient, int unk_zero_param, int errHandling); +EXPORT_DECL(int, FSDelClient, void *pClient); +EXPORT_DECL(void, FSInitCmdBlock, void *pCmd); +EXPORT_DECL(int, FSGetMountSource, void *pClient, void *pCmd, int type, void *source, int errHandling); + +EXPORT_DECL(int, FSMount, void *pClient, void *pCmd, void *source, char *target, uint32_t bytes, int errHandling); +EXPORT_DECL(int, FSUnmount, void *pClient, void *pCmd, const char *target, int errHandling); + +EXPORT_DECL(int, FSGetStat, void *pClient, void *pCmd, const char *path, FSStat *stats, int errHandling); +EXPORT_DECL(int, FSGetStatAsync, void *pClient, void *pCmd, const char *path, void *stats, int error, void *asyncParams); +EXPORT_DECL(int, FSRename, void *pClient, void *pCmd, const char *oldPath, const char *newPath, int error); +EXPORT_DECL(int, FSRenameAsync, void *pClient, void *pCmd, const char *oldPath, const char *newPath, int error, void *asyncParams); +EXPORT_DECL(int, FSRemove, void *pClient, void *pCmd, const char *path, int error); +EXPORT_DECL(int, FSRemoveAsync, void *pClient, void *pCmd, const char *path, int error, void *asyncParams); +EXPORT_DECL(int, FSFlushQuota, void *pClient, void *pCmd, const char* path, int error); +EXPORT_DECL(int, FSFlushQuotaAsync, void *pClient, void *pCmd, const char *path, int error, void *asyncParams); +EXPORT_DECL(int, FSGetFreeSpaceSize, void *pClient, void *pCmd, const char *path, uint64_t *returnedFreeSize, int error); +EXPORT_DECL(int, FSGetFreeSpaceSizeAsync, void *pClient, void *pCmd, const char *path, uint64_t *returnedFreeSize, int error, void *asyncParams); +EXPORT_DECL(int, FSRollbackQuota, void *pClient, void *pCmd, const char *path, int error); +EXPORT_DECL(int, FSRollbackQuotaAsync, void *pClient, void *pCmd, const char *path, int error, void *asyncParams); + +EXPORT_DECL(int, FSOpenDir, void *pClient, void *pCmd, const char *path, int *dh, int errHandling); +EXPORT_DECL(int, FSOpenDirAsync, void *pClient, void* pCmd, const char *path, int *handle, int error, void *asyncParams); +EXPORT_DECL(int, FSReadDir, void *pClient, void *pCmd, int dh, FSDirEntry *dir_entry, int errHandling); +EXPORT_DECL(int, FSRewindDir, void *pClient, void *pCmd, int dh, int errHandling); +EXPORT_DECL(int, FSCloseDir, void *pClient, void *pCmd, int dh, int errHandling); +EXPORT_DECL(int, FSChangeDir, void *pClient, void *pCmd, const char *path, int errHandling); +EXPORT_DECL(int, FSChangeDirAsync, void *pClient, void *pCmd, const char *path, int error, void *asyncParams); +EXPORT_DECL(int, FSMakeDir, void *pClient, void *pCmd, const char *path, int errHandling); +EXPORT_DECL(int, FSMakeDirAsync, void *pClient, void *pCmd, const char *path, int error, void *asyncParams); + +EXPORT_DECL(int, FSOpenFile, void *pClient, void *pCmd, const char *path, const char *mode, int *fd, int errHandling); +EXPORT_DECL(int, FSOpenFileAsync, void *pClient, void *pCmd, const char *path, const char *mode, int *handle, int error, const void *asyncParams); +EXPORT_DECL(int, FSReadFile, void *pClient, void *pCmd, void *buffer, int size, int count, int fd, int flag, int errHandling); +EXPORT_DECL(int, FSCloseFile, void *pClient, void *pCmd, int fd, int errHandling); + +EXPORT_DECL(int, FSFlushFile, void *pClient, void *pCmd, int fd, int error); +EXPORT_DECL(int, FSTruncateFile, void *pClient, void *pCmd, int fd, int error); +EXPORT_DECL(int, FSGetStatFile, void *pClient, void *pCmd, int fd, void *buffer, int error); +EXPORT_DECL(int, FSSetPosFile, void *pClient, void *pCmd, int fd, int pos, int error); +EXPORT_DECL(int, FSWriteFile, void *pClient, void *pCmd, const void *source, int block_size, int block_count, int fd, int flag, int error); + +EXPORT_DECL(int, FSBindMount, void *pClient, void *pCmd, char *source, char *target, int error); +EXPORT_DECL(int, FSBindUnmount, void *pClient, void *pCmd, char *target, int error); + +EXPORT_DECL(int, FSMakeQuota, void *pClient, void *pCmd, const char *path,u32 mode, u64 size, int errHandling); +EXPORT_DECL(int, FSMakeQuotaAsync ,void *pClient, void *pCmd, const char *path,u32 mode, u64 size, int errHandling,const void *asyncParams); + +void InitFSFunctionPointers(void) +{ + unsigned int *funcPointer = 0; + + OS_FIND_EXPORT(coreinit_handle, FSInit); + OS_FIND_EXPORT(coreinit_handle, FSShutdown); + OS_FIND_EXPORT(coreinit_handle, FSAddClientEx); + OS_FIND_EXPORT(coreinit_handle, FSDelClient); + OS_FIND_EXPORT(coreinit_handle, FSInitCmdBlock); + OS_FIND_EXPORT(coreinit_handle, FSGetMountSource); + + OS_FIND_EXPORT(coreinit_handle, FSMount); + OS_FIND_EXPORT(coreinit_handle, FSUnmount); + + OS_FIND_EXPORT(coreinit_handle, FSGetStat); + OS_FIND_EXPORT(coreinit_handle, FSGetStatAsync); + OS_FIND_EXPORT(coreinit_handle, FSRename); + OS_FIND_EXPORT(coreinit_handle, FSRenameAsync); + OS_FIND_EXPORT(coreinit_handle, FSRemove); + OS_FIND_EXPORT(coreinit_handle, FSRemoveAsync); + OS_FIND_EXPORT(coreinit_handle, FSFlushQuota); + OS_FIND_EXPORT(coreinit_handle, FSFlushQuotaAsync); + OS_FIND_EXPORT(coreinit_handle, FSGetFreeSpaceSize); + OS_FIND_EXPORT(coreinit_handle, FSGetFreeSpaceSizeAsync); + OS_FIND_EXPORT(coreinit_handle, FSRollbackQuota); + OS_FIND_EXPORT(coreinit_handle, FSRollbackQuotaAsync); + + OS_FIND_EXPORT(coreinit_handle, FSOpenDir); + OS_FIND_EXPORT(coreinit_handle, FSOpenDirAsync); + OS_FIND_EXPORT(coreinit_handle, FSReadDir); + OS_FIND_EXPORT(coreinit_handle, FSRewindDir); + OS_FIND_EXPORT(coreinit_handle, FSCloseDir); + OS_FIND_EXPORT(coreinit_handle, FSChangeDir); + OS_FIND_EXPORT(coreinit_handle, FSChangeDirAsync); + OS_FIND_EXPORT(coreinit_handle, FSMakeDir); + OS_FIND_EXPORT(coreinit_handle, FSMakeDirAsync); + + + OS_FIND_EXPORT(coreinit_handle, FSOpenFile); + OS_FIND_EXPORT(coreinit_handle, FSOpenFileAsync); + OS_FIND_EXPORT(coreinit_handle, FSReadFile); + OS_FIND_EXPORT(coreinit_handle, FSCloseFile); + + OS_FIND_EXPORT(coreinit_handle, FSFlushFile); + OS_FIND_EXPORT(coreinit_handle, FSTruncateFile); + OS_FIND_EXPORT(coreinit_handle, FSGetStatFile); + OS_FIND_EXPORT(coreinit_handle, FSSetPosFile); + OS_FIND_EXPORT(coreinit_handle, FSWriteFile); + + OS_FIND_EXPORT(coreinit_handle, FSBindMount); + OS_FIND_EXPORT(coreinit_handle, FSBindUnmount); + + OS_FIND_EXPORT(coreinit_handle, FSMakeQuota); + OS_FIND_EXPORT(coreinit_handle, FSMakeQuotaAsync); +} diff --git a/src/dynamic_libs/fs_functions.h b/src/dynamic_libs/fs_functions.h new file mode 100644 index 0000000..d024655 --- /dev/null +++ b/src/dynamic_libs/fs_functions.h @@ -0,0 +1,95 @@ +/**************************************************************************** + * Copyright (C) 2015 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef __FS_FUNCTIONS_H_ +#define __FS_FUNCTIONS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "fs_defs.h" + +void InitFSFunctionPointers(void); + +extern int (* FSInit)(void); +extern int (* FSShutdown)(void); +extern int (* FSAddClientEx)(void *pClient, int unk_zero_param, int errHandling); +extern int (* FSDelClient)(void *pClient); +extern void (* FSInitCmdBlock)(void *pCmd); +extern int (* FSGetMountSource)(void *pClient, void *pCmd, int type, void *source, int errHandling); + +extern int (* FSMount)(void *pClient, void *pCmd, void *source, char *target, uint32_t bytes, int errHandling); +extern int (* FSUnmount)(void *pClient, void *pCmd, const char *target, int errHandling); +extern int (* FSRename)(void *pClient, void *pCmd, const char *oldPath, const char *newPath, int error); +extern int (* FSRenameAsync)(void *pClient, void *pCmd, const char *oldPath, const char *newPath, int error, void *asyncParams); +extern int (* FSRemove)(void *pClient, void *pCmd, const char *path, int error); +extern int (* FSRemoveAsync)(void *pClient, void *pCmd, const char *path, int error, void *asyncParams); + +extern int (* FSGetStat)(void *pClient, void *pCmd, const char *path, FSStat *stats, int errHandling); +extern int (* FSGetStatAsync)(void *pClient, void *pCmd, const char *path, void *stats, int error, void *asyncParams); +extern int (* FSRename)(void *pClient, void *pCmd, const char *oldPath, const char *newPath, int error); +extern int (* FSRenameAsync)(void *pClient, void *pCmd, const char *oldPath, const char *newPath, int error, void *asyncParams); +extern int (* FSRemove)(void *pClient, void *pCmd, const char *path, int error); +extern int (* FSRemoveAsync)(void *pClient, void *pCmd, const char *path, int error, void *asyncParams); +extern int (* FSFlushQuota)(void *pClient, void *pCmd, const char* path, int error); +extern int (* FSFlushQuotaAsync)(void *pClient, void *pCmd, const char *path, int error, void *asyncParams); +extern int (* FSGetFreeSpaceSize)(void *pClient, void *pCmd, const char *path, uint64_t *returnedFreeSize, int error); +extern int (* FSGetFreeSpaceSizeAsync)(void *pClient, void *pCmd, const char *path, uint64_t *returnedFreeSize, int error, void *asyncParams); +extern int (* FSRollbackQuota)(void *pClient, void *pCmd, const char *path, int error); +extern int (* FSRollbackQuotaAsync)(void *pClient, void *pCmd, const char *path, int error, void *asyncParams); + +extern int (* FSOpenDir)(void *pClient, void *pCmd, const char *path, int *dh, int errHandling); +extern int (* FSOpenDirAsync)(void *pClient, void* pCmd, const char *path, int *handle, int error, void *asyncParams); +extern int (* FSReadDir)(void *pClient, void *pCmd, int dh, FSDirEntry *dir_entry, int errHandling); +extern int (* FSRewindDir)(void *pClient, void *pCmd, int dh, int errHandling); +extern int (* FSCloseDir)(void *pClient, void *pCmd, int dh, int errHandling); +extern int (* FSChangeDir)(void *pClient, void *pCmd, const char *path, int errHandling); +extern int (* FSChangeDirAsync)(void *pClient, void *pCmd, const char *path, int error, void *asyncParams); +extern int (* FSMakeDir)(void *pClient, void *pCmd, const char *path, int errHandling); +extern int (* FSMakeDirAsync)(void *pClient, void *pCmd, const char *path, int error, void *asyncParams); + +extern int (* FSOpenFile)(void *pClient, void *pCmd, const char *path, const char *mode, int *fd, int errHandling); +extern int (* FSOpenFileAsync)(void *pClient, void *pCmd, const char *path, const char *mode, int *handle, int error, const void *asyncParams); +extern int (* FSReadFile)(void *pClient, void *pCmd, void *buffer, int size, int count, int fd, int flag, int errHandling); +extern int (* FSCloseFile)(void *pClient, void *pCmd, int fd, int errHandling); + +extern int (* FSFlushFile)(void *pClient, void *pCmd, int fd, int error); +extern int (* FSTruncateFile)(void *pClient, void *pCmd, int fd, int error); +extern int (* FSGetStatFile)(void *pClient, void *pCmd, int fd, void *buffer, int error); +extern int (* FSSetPosFile)(void *pClient, void *pCmd, int fd, int pos, int error); +extern int (* FSWriteFile)(void *pClient, void *pCmd, const void *source, int block_size, int block_count, int fd, int flag, int error); + +extern int (* FSBindMount)(void *pClient, void *pCmd, char *source, char *target, int error); +extern int (* FSBindUnmount)(void *pClient, void *pCmd, char *target, int error); + +extern int (* FSMakeQuota)( void *pClient, void *pCmd, const char *path,u32 mode, u64 size, int errHandling); +extern int (* FSMakeQuotaAsync)(void *pClient, void *pCmd, const char *path,u32 mode, u64 size, int errHandling,const void *asyncParams); + + +#ifdef __cplusplus +} +#endif + +#endif // __FS_FUNCTIONS_H_ diff --git a/src/dynamic_libs/gx2_functions.c b/src/dynamic_libs/gx2_functions.c new file mode 100644 index 0000000..a34807e --- /dev/null +++ b/src/dynamic_libs/gx2_functions.c @@ -0,0 +1,173 @@ +/**************************************************************************** + * Copyright (C) 2015 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include "os_functions.h" +#include "gx2_types.h" + +unsigned int gx2_handle __attribute__((section(".data"))) = 0; + +EXPORT_DECL(void, GX2Init, u32 * init_attribs); +EXPORT_DECL(void, GX2Shutdown, void); +EXPORT_DECL(void, GX2Flush, void); +EXPORT_DECL(s32, GX2GetMainCoreId, void) ; +EXPORT_DECL(s32, GX2DrawDone, void); +EXPORT_DECL(void, GX2ClearColor, GX2ColorBuffer *colorBuffer, f32 r, f32 g, f32 b, f32 a); +EXPORT_DECL(void, GX2SetViewport, f32 x, f32 y, f32 w, f32 h, f32 nearZ, f32 farZ); +EXPORT_DECL(void, GX2SetScissor, u32 x_orig, u32 y_orig, u32 wd, u32 ht); +EXPORT_DECL(void, GX2SetContextState, const GX2ContextState* state); +EXPORT_DECL(void, GX2DrawEx, s32 primitive_type, u32 count, u32 first_vertex, u32 instances_count); +EXPORT_DECL(void, GX2DrawIndexedEx, s32 primitive_type, u32 count, s32 index_format, const void* idx, u32 first_vertex, u32 instances_count); +EXPORT_DECL(void, GX2ClearDepthStencilEx, GX2DepthBuffer *depthBuffer, f32 depth_value, u8 stencil_value, s32 clear_mode); +EXPORT_DECL(void, GX2SetClearDepthStencil, GX2DepthBuffer *depthBuffer, f32 depth_value, u8 stencil_value); +EXPORT_DECL(void, GX2CopyColorBufferToScanBuffer, const GX2ColorBuffer *colorBuffer, s32 scan_target); +EXPORT_DECL(void, GX2SwapScanBuffers, void); +EXPORT_DECL(void, GX2SetTVEnable, s32 enable); +EXPORT_DECL(void, GX2SetSwapInterval, u32 swap_interval); +EXPORT_DECL(u32, GX2GetSwapInterval, void); +EXPORT_DECL(void, GX2WaitForVsync, void); +EXPORT_DECL(void, GX2CalcTVSize, s32 tv_render_mode, s32 format, s32 buffering_mode, u32 * size, s32 * scale_needed); +EXPORT_DECL(void, GX2Invalidate, s32 invalidate_type, void * ptr, u32 buffer_size); +EXPORT_DECL(void, GX2SetTVBuffer, void *buffer, u32 buffer_size, s32 tv_render_mode, s32 format, s32 buffering_mode); +EXPORT_DECL(void, GX2CalcSurfaceSizeAndAlignment, GX2Surface *surface); +EXPORT_DECL(void, GX2InitDepthBufferRegs, GX2DepthBuffer *depthBuffer); +EXPORT_DECL(void, GX2InitColorBufferRegs, GX2ColorBuffer *colorBuffer); +EXPORT_DECL(void, GX2CalcColorBufferAuxInfo, GX2ColorBuffer *colorBuffer, u32 *size, u32 *align); +EXPORT_DECL(void, GX2CalcDepthBufferHiZInfo, GX2DepthBuffer *depthBuffer, u32 *size, u32 *align); +EXPORT_DECL(void, GX2InitDepthBufferHiZEnable, GX2DepthBuffer *depthBuffer, s32 hiZ_enable); +EXPORT_DECL(void, GX2SetupContextStateEx, GX2ContextState* state, s32 enable_profiling); +EXPORT_DECL(void, GX2SetColorBuffer, const GX2ColorBuffer *colorBuffer, s32 target); +EXPORT_DECL(void, GX2SetDepthBuffer, const GX2DepthBuffer *depthBuffer); +EXPORT_DECL(void, GX2SetAttribBuffer, u32 attr_index, u32 attr_size, u32 stride, const void* attr); +EXPORT_DECL(void, GX2InitTextureRegs, GX2Texture *texture); +EXPORT_DECL(void, GX2InitSampler, GX2Sampler *sampler, s32 tex_clamp, s32 min_mag_filter); +EXPORT_DECL(u32, GX2CalcFetchShaderSizeEx, u32 num_attrib, s32 fetch_shader_type, s32 tessellation_mode); +EXPORT_DECL(void, GX2InitFetchShaderEx, GX2FetchShader* fs, void* fs_buffer, u32 count, const GX2AttribStream* attribs, s32 fetch_shader_type, s32 tessellation_mode); +EXPORT_DECL(void, GX2SetFetchShader, const GX2FetchShader* fs); +EXPORT_DECL(void, GX2SetVertexUniformReg, u32 offset, u32 count, const void *values); +EXPORT_DECL(void, GX2SetPixelUniformReg, u32 offset, u32 count, const void *values); +EXPORT_DECL(void, GX2SetPixelTexture, const GX2Texture *texture, u32 texture_hw_location); +EXPORT_DECL(void, GX2SetVertexTexture, const GX2Texture *texture, u32 texture_hw_location); +EXPORT_DECL(void, GX2SetPixelSampler, const GX2Sampler *sampler, u32 sampler_hw_location); +EXPORT_DECL(void, GX2SetVertexSampler, const GX2Sampler *sampler, u32 sampler_hw_location); +EXPORT_DECL(void, GX2SetPixelShader, const GX2PixelShader* pixelShader); +EXPORT_DECL(void, GX2SetVertexShader, const GX2VertexShader* vertexShader); +EXPORT_DECL(void, GX2InitSamplerZMFilter, GX2Sampler *sampler, s32 z_filter, s32 mip_filter); +EXPORT_DECL(void, GX2SetColorControl, s32 lop, u8 blend_enable_mask, s32 enable_multi_write, s32 enable_color_buffer); +EXPORT_DECL(void, GX2SetDepthOnlyControl, s32 enable_depth, s32 enable_depth_write, s32 depth_comp_function); +EXPORT_DECL(void, GX2SetBlendControl, s32 target, s32 color_src_blend, s32 color_dst_blend, s32 color_combine, s32 separate_alpha_blend, s32 alpha_src_blend, s32 alpha_dst_blend, s32 alpha_combine); +EXPORT_DECL(void, GX2CalcDRCSize, s32 drc_mode, s32 format, s32 buffering_mode, u32 *size, s32 *scale_needed); +EXPORT_DECL(void, GX2SetDRCBuffer, void *buffer, u32 buffer_size, s32 drc_mode, s32 surface_format, s32 buffering_mode); +EXPORT_DECL(void, GX2SetDRCScale, u32 width, u32 height); +EXPORT_DECL(void, GX2SetDRCEnable, s32 enable); +EXPORT_DECL(void, GX2SetPolygonControl, s32 front_face_mode, s32 cull_front, s32 cull_back, s32 enable_mode, s32 mode_font, s32 mode_back, s32 poly_offset_front, s32 poly_offset_back, s32 point_line_offset); +EXPORT_DECL(void, GX2SetCullOnlyControl, s32 front_face_mode, s32 cull_front, s32 cull_back); +EXPORT_DECL(void, GX2SetDepthStencilControl, s32 enable_depth_test, s32 enable_depth_write, s32 depth_comp_function, s32 stencil_test_enable, s32 back_stencil_enable, + s32 font_stencil_func, s32 front_stencil_z_pass, s32 front_stencil_z_fail, s32 front_stencil_fail, + s32 back_stencil_func, s32 back_stencil_z_pass, s32 back_stencil_z_fail, s32 back_stencil_fail); +EXPORT_DECL(void, GX2SetStencilMask, u8 mask_front, u8 write_mask_front, u8 ref_front, u8 mask_back, u8 write_mask_back, u8 ref_back); +EXPORT_DECL(void, GX2SetLineWidth, f32 width); +EXPORT_DECL(void, GX2SetTVGamma, f32 val); +EXPORT_DECL(void, GX2SetDRCGamma, f32 gam); +EXPORT_DECL(s32, GX2GetSystemTVScanMode, void); +EXPORT_DECL(s32, GX2GetSystemDRCScanMode, void); +EXPORT_DECL(void, GX2RSetAllocator, void * (* allocFunc)(u32, u32, u32), void (* freeFunc)(u32, void*)); +EXPORT_DECL(void, GX2CopySurface, GX2Surface * srcSurface,u32 srcMip,u32 srcSlice,GX2Surface * dstSurface,u32 dstMip,u32 dstSlice ); + +EXPORT_DECL(void, GX2ClearBuffersEx, GX2ColorBuffer * colorBuffer,GX2DepthBuffer * depthBuffer,f32 r, f32 g, f32 b, f32 a,f32 depthValue,u8 stencilValue,int clearFlags); + +void InitAcquireGX2(void) +{ + OSDynLoad_Acquire("gx2.rpl", &gx2_handle); +} + +void InitGX2FunctionPointers(void) +{ + unsigned int *funcPointer = 0; + InitAcquireGX2(); + + OS_FIND_EXPORT(gx2_handle, GX2Init); + OS_FIND_EXPORT(gx2_handle, GX2Shutdown); + OS_FIND_EXPORT(gx2_handle, GX2Flush); + OS_FIND_EXPORT(gx2_handle, GX2GetMainCoreId); + OS_FIND_EXPORT(gx2_handle, GX2DrawDone); + OS_FIND_EXPORT(gx2_handle, GX2ClearColor); + OS_FIND_EXPORT(gx2_handle, GX2SetViewport); + OS_FIND_EXPORT(gx2_handle, GX2SetScissor); + OS_FIND_EXPORT(gx2_handle, GX2SetContextState); + OS_FIND_EXPORT(gx2_handle, GX2DrawEx); + OS_FIND_EXPORT(gx2_handle, GX2DrawIndexedEx); + OS_FIND_EXPORT(gx2_handle, GX2ClearDepthStencilEx); + OS_FIND_EXPORT(gx2_handle, GX2CopyColorBufferToScanBuffer); + OS_FIND_EXPORT(gx2_handle, GX2SwapScanBuffers); + OS_FIND_EXPORT(gx2_handle, GX2SetTVEnable); + OS_FIND_EXPORT(gx2_handle, GX2SetSwapInterval); + OS_FIND_EXPORT(gx2_handle, GX2GetSwapInterval); + OS_FIND_EXPORT(gx2_handle, GX2WaitForVsync); + OS_FIND_EXPORT(gx2_handle, GX2CalcTVSize); + OS_FIND_EXPORT(gx2_handle, GX2Invalidate); + OS_FIND_EXPORT(gx2_handle, GX2SetTVBuffer); + OS_FIND_EXPORT(gx2_handle, GX2CalcSurfaceSizeAndAlignment); + OS_FIND_EXPORT(gx2_handle, GX2InitDepthBufferRegs); + OS_FIND_EXPORT(gx2_handle, GX2InitColorBufferRegs); + OS_FIND_EXPORT(gx2_handle, GX2CalcColorBufferAuxInfo); + OS_FIND_EXPORT(gx2_handle, GX2CalcDepthBufferHiZInfo); + OS_FIND_EXPORT(gx2_handle, GX2InitDepthBufferHiZEnable); + OS_FIND_EXPORT(gx2_handle, GX2SetupContextStateEx); + OS_FIND_EXPORT(gx2_handle, GX2SetColorBuffer); + OS_FIND_EXPORT(gx2_handle, GX2SetDepthBuffer); + OS_FIND_EXPORT(gx2_handle, GX2SetAttribBuffer); + OS_FIND_EXPORT(gx2_handle, GX2InitTextureRegs); + OS_FIND_EXPORT(gx2_handle, GX2InitSampler); + OS_FIND_EXPORT(gx2_handle, GX2CalcFetchShaderSizeEx); + OS_FIND_EXPORT(gx2_handle, GX2InitFetchShaderEx); + OS_FIND_EXPORT(gx2_handle, GX2SetFetchShader); + OS_FIND_EXPORT(gx2_handle, GX2SetVertexUniformReg); + OS_FIND_EXPORT(gx2_handle, GX2SetPixelUniformReg); + OS_FIND_EXPORT(gx2_handle, GX2SetPixelTexture); + OS_FIND_EXPORT(gx2_handle, GX2SetVertexTexture); + OS_FIND_EXPORT(gx2_handle, GX2SetPixelSampler); + OS_FIND_EXPORT(gx2_handle, GX2SetVertexSampler); + OS_FIND_EXPORT(gx2_handle, GX2SetPixelShader); + OS_FIND_EXPORT(gx2_handle, GX2SetVertexShader); + OS_FIND_EXPORT(gx2_handle, GX2InitSamplerZMFilter); + OS_FIND_EXPORT(gx2_handle, GX2SetColorControl); + OS_FIND_EXPORT(gx2_handle, GX2SetDepthOnlyControl); + OS_FIND_EXPORT(gx2_handle, GX2SetBlendControl); + OS_FIND_EXPORT(gx2_handle, GX2CalcDRCSize); + OS_FIND_EXPORT(gx2_handle, GX2SetDRCBuffer); + OS_FIND_EXPORT(gx2_handle, GX2SetDRCScale); + OS_FIND_EXPORT(gx2_handle, GX2SetDRCEnable); + OS_FIND_EXPORT(gx2_handle, GX2SetPolygonControl); + OS_FIND_EXPORT(gx2_handle, GX2SetCullOnlyControl); + OS_FIND_EXPORT(gx2_handle, GX2SetDepthStencilControl); + OS_FIND_EXPORT(gx2_handle, GX2SetStencilMask); + OS_FIND_EXPORT(gx2_handle, GX2SetLineWidth); + OS_FIND_EXPORT(gx2_handle, GX2SetDRCGamma); + OS_FIND_EXPORT(gx2_handle, GX2SetTVGamma); + OS_FIND_EXPORT(gx2_handle, GX2GetSystemTVScanMode); + OS_FIND_EXPORT(gx2_handle, GX2GetSystemDRCScanMode); + OS_FIND_EXPORT(gx2_handle, GX2RSetAllocator); + OS_FIND_EXPORT(gx2_handle, GX2CopySurface); + OS_FIND_EXPORT(gx2_handle, GX2ClearBuffersEx); + OS_FIND_EXPORT(gx2_handle, GX2SetClearDepthStencil); +} diff --git a/src/dynamic_libs/gx2_functions.h b/src/dynamic_libs/gx2_functions.h new file mode 100644 index 0000000..0b06826 --- /dev/null +++ b/src/dynamic_libs/gx2_functions.h @@ -0,0 +1,211 @@ +/**************************************************************************** + * Copyright (C) 2015 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef __GX2_FUNCTIONS_H_ +#define __GX2_FUNCTIONS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "gx2_types.h" + +extern unsigned int gx2_handle; + +void InitGX2FunctionPointers(void); +void InitAcquireGX2(void); + +extern void (* GX2Init)(u32 * init_attribs); +extern void (* GX2Shutdown)(void); +extern void (* GX2Flush)(void); +extern s32 (* GX2GetMainCoreId)(void) ; +extern s32 (* GX2DrawDone)(void); +extern void (* GX2ClearColor)(GX2ColorBuffer *colorBuffer, f32 r, f32 g, f32 b, f32 a); +extern void (* GX2SetViewport)(f32 x, f32 y, f32 w, f32 h, f32 nearZ, f32 farZ); +extern void (* GX2SetScissor)(u32 x_orig, u32 y_orig, u32 wd, u32 ht); +extern void (* GX2SetContextState)(const GX2ContextState* state); +extern void (* GX2DrawEx)(s32 primitive_type, u32 count, u32 first_vertex, u32 instances_count); +extern void (* GX2DrawIndexedEx)(s32 primitive_type, u32 count, s32 index_format, const void* idx, u32 first_vertex, u32 instances_count); +extern void (* GX2ClearDepthStencilEx)(GX2DepthBuffer *depthBuffer, f32 depth_value, u8 stencil_value, s32 clear_mode); +extern void (* GX2SetClearDepthStencil)(GX2DepthBuffer *depthBuffer, f32 depth_value, u8 stencil_value); +extern void (* GX2CopyColorBufferToScanBuffer)(const GX2ColorBuffer *colorBuffer, s32 scan_target); +extern void (* GX2SwapScanBuffers)(void); +extern void (* GX2SetTVEnable)(s32 enable); +extern void (* GX2SetSwapInterval)(u32 swap_interval); +extern u32 (* GX2GetSwapInterval)(void); +extern void (* GX2WaitForVsync)(void); +extern void (* GX2CalcTVSize)(s32 tv_render_mode, s32 format, s32 buffering_mode, u32 * size, s32 * scale_needed); +extern void (* GX2Invalidate)(s32 invalidate_type, void * ptr, u32 buffer_size); +extern void (* GX2SetTVBuffer)(void *buffer, u32 buffer_size, s32 tv_render_mode, s32 format, s32 buffering_mode); +extern void (* GX2CalcSurfaceSizeAndAlignment)(GX2Surface *surface); +extern void (* GX2InitDepthBufferRegs)(GX2DepthBuffer *depthBuffer); +extern void (* GX2InitColorBufferRegs)(GX2ColorBuffer *colorBuffer); +extern void (* GX2CalcColorBufferAuxInfo)(GX2ColorBuffer *colorBuffer, u32 *size, u32 *align); +extern void (* GX2CalcDepthBufferHiZInfo)(GX2DepthBuffer *depthBuffer, u32 *size, u32 *align); +extern void (* GX2InitDepthBufferHiZEnable)(GX2DepthBuffer *depthBuffer, s32 hiZ_enable); +extern void (* GX2SetupContextStateEx)(GX2ContextState* state, s32 enable_profiling); +extern void (* GX2SetColorBuffer)(const GX2ColorBuffer *colorBuffer, s32 target); +extern void (* GX2SetDepthBuffer)(const GX2DepthBuffer *depthBuffer); +extern void (* GX2SetAttribBuffer)(u32 attr_index, u32 attr_size, u32 stride, const void* attr); +extern void (* GX2InitTextureRegs)(GX2Texture *texture); +extern void (* GX2InitSampler)(GX2Sampler *sampler, s32 tex_clamp, s32 min_mag_filter); +extern u32 (* GX2CalcFetchShaderSizeEx)(u32 num_attrib, s32 fetch_shader_type, s32 tessellation_mode); +extern void (* GX2InitFetchShaderEx)(GX2FetchShader* fs, void* fs_buffer, u32 count, const GX2AttribStream* attribs, s32 fetch_shader_type, s32 tessellation_mode); +extern void (* GX2SetFetchShader)(const GX2FetchShader* fs); +extern void (* GX2SetVertexUniformReg)(u32 offset, u32 count, const void *values); +extern void (* GX2SetPixelUniformReg)(u32 offset, u32 count, const void *values); +extern void (* GX2SetPixelTexture)(const GX2Texture *texture, u32 texture_hw_location); +extern void (* GX2SetVertexTexture)(const GX2Texture *texture, u32 texture_hw_location); +extern void (* GX2SetPixelSampler)(const GX2Sampler *sampler, u32 sampler_hw_location); +extern void (* GX2SetVertexSampler)(const GX2Sampler *sampler, u32 sampler_hw_location); +extern void (* GX2SetPixelShader)(const GX2PixelShader* pixelShader); +extern void (* GX2SetVertexShader)(const GX2VertexShader* vertexShader); +extern void (* GX2InitSamplerZMFilter)(GX2Sampler *sampler, s32 z_filter, s32 mip_filter); +extern void (* GX2SetColorControl)(s32 lop, u8 blend_enable_mask, s32 enable_multi_write, s32 enable_color_buffer); +extern void (* GX2SetDepthOnlyControl)(s32 enable_depth, s32 enable_depth_write, s32 depth_comp_function); +extern void (* GX2SetBlendControl)(s32 target, s32 color_src_blend, s32 color_dst_blend, s32 color_combine, s32 separate_alpha_blend, s32 alpha_src_blend, s32 alpha_dst_blend, s32 alpha_combine); +extern void (* GX2CalcDRCSize)(s32 drc_mode, s32 format, s32 buffering_mode, u32 *size, s32 *scale_needed); +extern void (* GX2SetDRCBuffer)(void *buffer, u32 buffer_size, s32 drc_mode, s32 surface_format, s32 buffering_mode); +extern void (* GX2SetDRCScale)(u32 width, u32 height); +extern void (* GX2SetDRCEnable)(s32 enable); +extern void (* GX2SetPolygonControl)(s32 front_face_mode, s32 cull_front, s32 cull_back, s32 enable_mode, s32 mode_font, s32 mode_back, s32 poly_offset_front, s32 poly_offset_back, s32 point_line_offset); +extern void (* GX2SetCullOnlyControl)(s32 front_face_mode, s32 cull_front, s32 cull_back); +extern void (* GX2SetDepthStencilControl)(s32 enable_depth_test, s32 enable_depth_write, s32 depth_comp_function, s32 stencil_test_enable, s32 back_stencil_enable, + s32 font_stencil_func, s32 front_stencil_z_pass, s32 front_stencil_z_fail, s32 front_stencil_fail, + s32 back_stencil_func, s32 back_stencil_z_pass, s32 back_stencil_z_fail, s32 back_stencil_fail); +extern void (* GX2SetStencilMask)(u8 mask_front, u8 write_mask_front, u8 ref_front, u8 mask_back, u8 write_mask_back, u8 ref_back); +extern void (* GX2SetLineWidth)(f32 width); +extern void (* GX2SetTVGamma)(f32 val); +extern void (* GX2SetDRCGamma)(f32 val); +extern s32 (* GX2GetSystemTVScanMode)(void); +extern s32 (* GX2GetSystemDRCScanMode)(void); +extern void (* GX2RSetAllocator)(void * (*allocFunc)(u32, u32, u32), void (*freeFunc)(u32, void*)); +extern void (* GX2CopySurface)(GX2Surface * srcSurface,u32 srcMip,u32 srcSlice,GX2Surface * dstSurface,u32 dstMip,u32 dstSlice ); +extern void (* GX2ClearBuffersEx)(GX2ColorBuffer * colorBuffer,GX2DepthBuffer * depthBuffer,f32 r, f32 g, f32 b, f32 a,f32 depthValue,u8 stencilValue,int clearFlags); + +static inline void GX2InitDepthBuffer(GX2DepthBuffer *depthBuffer, s32 dimension, u32 width, u32 height, u32 depth, s32 format, s32 aa) +{ + depthBuffer->surface.dimension = dimension; + depthBuffer->surface.width = width; + depthBuffer->surface.height = height; + depthBuffer->surface.depth = depth; + depthBuffer->surface.num_mips = 1; + depthBuffer->surface.format = format; + depthBuffer->surface.aa = aa; + depthBuffer->surface.use = ((format==GX2_SURFACE_FORMAT_D_D24_S8_UNORM) || (format==GX2_SURFACE_FORMAT_D_D24_S8_FLOAT)) ? GX2_SURFACE_USE_DEPTH_BUFFER : GX2_SURFACE_USE_DEPTH_BUFFER_TEXTURE; + depthBuffer->surface.tile = GX2_TILE_MODE_DEFAULT; + depthBuffer->surface.swizzle = 0; + depthBuffer->view_mip = 0; + depthBuffer->view_first_slice = 0; + depthBuffer->view_slices_count = depth; + depthBuffer->clear_depth = 1.0f; + depthBuffer->clear_stencil = 0; + depthBuffer->hiZ_data = NULL; + depthBuffer->hiZ_size = 0; + GX2CalcSurfaceSizeAndAlignment(&depthBuffer->surface); + GX2InitDepthBufferRegs(depthBuffer); +} + +static inline void GX2InitColorBuffer(GX2ColorBuffer *colorBuffer, s32 dimension, u32 width, u32 height, u32 depth, s32 format, s32 aa) +{ + colorBuffer->surface.dimension = dimension; + colorBuffer->surface.width = width; + colorBuffer->surface.height = height; + colorBuffer->surface.depth = depth; + colorBuffer->surface.num_mips = 1; + colorBuffer->surface.format = format; + colorBuffer->surface.aa = aa; + colorBuffer->surface.use = GX2_SURFACE_USE_COLOR_BUFFER_TEXTURE_FTV; + colorBuffer->surface.image_size = 0; + colorBuffer->surface.image_data = NULL; + colorBuffer->surface.mip_size = 0; + colorBuffer->surface.mip_data = NULL; + colorBuffer->surface.tile = GX2_TILE_MODE_DEFAULT; + colorBuffer->surface.swizzle = 0; + colorBuffer->surface.align = 0; + colorBuffer->surface.pitch = 0; + u32 i; + for(i = 0; i < 13; i++) + colorBuffer->surface.mip_offset[i] = 0; + colorBuffer->view_mip = 0; + colorBuffer->view_first_slice = 0; + colorBuffer->view_slices_count = depth; + colorBuffer->aux_data = NULL; + colorBuffer->aux_size = 0; + for(i = 0; i < 5; i++) + colorBuffer->regs[i] = 0; + + GX2CalcSurfaceSizeAndAlignment(&colorBuffer->surface); + GX2InitColorBufferRegs(colorBuffer); +} + +static inline void GX2InitAttribStream(GX2AttribStream* attr, u32 location, u32 buffer, u32 offset, s32 format) +{ + attr->location = location; + attr->buffer = buffer; + attr->offset = offset; + attr->format = format; + attr->index_type = 0; + attr->divisor = 0; + attr->destination_selector = attribute_dest_comp_selector[format & 0xff]; + attr->endian_swap = GX2_ENDIANSWAP_DEFAULT; +} + +static inline void GX2InitTexture(GX2Texture *tex, u32 width, u32 height, u32 depth, u32 num_mips, s32 format, s32 dimension, s32 tile) +{ + tex->surface.dimension = dimension; + tex->surface.width = width; + tex->surface.height = height; + tex->surface.depth = depth; + tex->surface.num_mips = num_mips; + tex->surface.format = format; + tex->surface.aa = GX2_AA_MODE_1X; + tex->surface.use = GX2_SURFACE_USE_TEXTURE; + tex->surface.image_size = 0; + tex->surface.image_data = NULL; + tex->surface.mip_size = 0; + tex->surface.mip_data = NULL; + tex->surface.tile = tile; + tex->surface.swizzle = 0; + tex->surface.align = 0; + tex->surface.pitch = 0; + u32 i; + for(i = 0; i < 13; i++) + tex->surface.mip_offset[i] = 0; + tex->view_first_mip = 0; + tex->view_mips_count = num_mips; + tex->view_first_slice = 0; + tex->view_slices_count = depth; + tex->component_selector = texture_comp_selector[format & 0x3f]; + for(i = 0; i < 5; i++) + tex->regs[i] = 0; + + GX2CalcSurfaceSizeAndAlignment(&tex->surface); + GX2InitTextureRegs(tex); +} + +#ifdef __cplusplus +} +#endif + +#endif // __GX2_FUNCTIONS_H_ diff --git a/src/dynamic_libs/gx2_types.h b/src/dynamic_libs/gx2_types.h new file mode 100644 index 0000000..e292318 --- /dev/null +++ b/src/dynamic_libs/gx2_types.h @@ -0,0 +1,699 @@ +/**************************************************************************** + * Copyright (C) 2015 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef _GX2_TYPES_H_ +#define _GX2_TYPES_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +//!----------------------------------------------------------------------------------------------------------------------- +//! Constants +//!----------------------------------------------------------------------------------------------------------------------- +#define GX2_COMMAND_BUFFER_SIZE 0x400000 +#define GX2_SCAN_BUFFER_ALIGNMENT 0x1000 +#define GX2_SHADER_ALIGNMENT 0x100 +#define GX2_CONTEXT_STATE_ALIGNMENT 0x100 +#define GX2_DISPLAY_LIST_ALIGNMENT 0x20 +#define GX2_VERTEX_BUFFER_ALIGNMENT 0x40 +#define GX2_INDEX_BUFFER_ALIGNMENT 0x20 + +#define GX2_CONTEXT_STATE_SIZE 0xA100 + +#define GX2_AUX_BUFFER_CLEAR_VALUE 0xCC + +//!----------------------------------------------------------------------------------------------------------------------- +//! Common +//!----------------------------------------------------------------------------------------------------------------------- +#define GX2_FALSE 0 +#define GX2_TRUE 1 +#define GX2_DISABLE 0 +#define GX2_ENABLE 1 + +//!----------------------------------------------------------------------------------------------------------------------- +//! GX2InitAttrib +//!----------------------------------------------------------------------------------------------------------------------- +#define GX2_INIT_ATTRIB_NULL 0 +#define GX2_INIT_ATTRIB_CB_BASE 1 +#define GX2_INIT_ATTRIB_CB_SIZE 2 +#define GX2_INIT_ATTRIB_ARGC 7 +#define GX2_INIT_ATTRIB_ARGV 8 + +//!----------------------------------------------------------------------------------------------------------------------- +//! GX2 compare functions +//!----------------------------------------------------------------------------------------------------------------------- +#define GX2_COMPARE_NEVER 0 +#define GX2_COMPARE_LESS 1 +#define GX2_COMPARE_EQUAL 2 +#define GX2_COMPARE_LEQUAL 3 +#define GX2_COMPARE_GREATER 4 +#define GX2_COMPARE_NOTEQUAL 5 +#define GX2_COMPARE_GEQUAL 6 +#define GX2_COMPARE_ALWAYS 7 + +//!----------------------------------------------------------------------------------------------------------------------- +//! GX2 stencil functions +//!----------------------------------------------------------------------------------------------------------------------- +#define GX2_STENCIL_KEEP 0 +#define GX2_STENCIL_ZERO 1 +#define GX2_STENCIL_REPLACE 2 +#define GX2_STENCIL_INCR 3 +#define GX2_STENCIL_DECR 4 +#define GX2_STENCIL_INVERT 5 +#define GX2_STENCIL_INCR_WRAP 6 +#define GX2_STENCIL_DECR_WRAP 7 + +//!----------------------------------------------------------------------------------------------------------------------- +//! GX2 logic op functions +//!----------------------------------------------------------------------------------------------------------------------- +#define GX2_LOGIC_OP_CLEAR 0x00 +#define GX2_LOGIC_OP_NOR 0x11 +#define GX2_LOGIC_OP_INVAND 0x22 +#define GX2_LOGIC_OP_INVCOPY 0x33 +#define GX2_LOGIC_OP_REVAND 0x44 +#define GX2_LOGIC_OP_INV 0x55 +#define GX2_LOGIC_OP_XOR 0x66 +#define GX2_LOGIC_OP_NAND 0x77 +#define GX2_LOGIC_OP_AND 0x88 +#define GX2_LOGIC_OP_EQUIV 0x99 +#define GX2_LOGIC_OP_NOOP 0xAA +#define GX2_LOGIC_OP_INVOR 0xBB +#define GX2_LOGIC_OP_COPY 0xCC +#define GX2_LOGIC_OP_REVOR 0xDD +#define GX2_LOGIC_OP_OR 0xEE +#define GX2_LOGIC_OP_SET 0xFF + +//!----------------------------------------------------------------------------------------------------------------------- +//! GX2 blend combination functions +//!----------------------------------------------------------------------------------------------------------------------- +#define GX2_BLEND_COMBINE_ADD 0x00 +#define GX2_BLEND_COMBINE_SRC_MINUS_DST 0x01 +#define GX2_BLEND_COMBINE_MIN 0x02 +#define GX2_BLEND_COMBINE_MAX 0x03 +#define GX2_BLEND_COMBINE_DST_MINUS_SRC 0x04 + +//!----------------------------------------------------------------------------------------------------------------------- +//! GX2 blend functions +//!----------------------------------------------------------------------------------------------------------------------- +#define GX2_BLEND_ZERO 0x00 +#define GX2_BLEND_ONE 0x01 +#define GX2_BLEND_SRC_ALPHA 0x04 +#define GX2_BLEND_ONE_MINUS_SRC_ALPHA 0x05 + +//!----------------------------------------------------------------------------------------------------------------------- +//! GX2 render targets +//!----------------------------------------------------------------------------------------------------------------------- +#define GX2_RENDER_TARGET_0 0 +#define GX2_RENDER_TARGET_1 1 +#define GX2_RENDER_TARGET_2 2 +#define GX2_RENDER_TARGET_3 3 +#define GX2_RENDER_TARGET_4 4 +#define GX2_RENDER_TARGET_5 5 +#define GX2_RENDER_TARGET_6 6 +#define GX2_RENDER_TARGET_7 7 + +//!----------------------------------------------------------------------------------------------------------------------- +//! GX2 cull modes +//!----------------------------------------------------------------------------------------------------------------------- +#define GX2_FRONT_FACE_CCW 0 +#define GX2_FRONT_FACE_CW 1 +//!----------------------------------------------------------------------------------------------------------------------- +//! GX2 polygon modes +//!----------------------------------------------------------------------------------------------------------------------- +#define GX2_POLYGON_MODE_POINT 0 +#define GX2_POLYGON_MODE_LINE 1 +#define GX2_POLYGON_MODE_TRIANGLE 2 + +//!----------------------------------------------------------------------------------------------------------------------- +//! GX2 special states +//!----------------------------------------------------------------------------------------------------------------------- +#define GX2_SPECIAL_STATE_CLEAR 0 +#define GX2_SPECIAL_STATE_CLEAR_HIZ 1 +#define GX2_SPECIAL_STATE_COPY 2 +#define GX2_SPECIAL_STATE_EXPAND_COLOR 3 +#define GX2_SPECIAL_STATE_EXPAND_DEPTH 4 +#define GX2_SPECIAL_STATE_CONVERT_DEPTH 5 +#define GX2_SPECIAL_STATE_CONVERT_AADEPTH 6 +#define GX2_SPECIAL_STATE_RESOLVE_COLOR 7 +#define GX2_SPECIAL_STATE_CLEAR_COLOR_AS_DEPTH 8 + +//!----------------------------------------------------------------------------------------------------------------------- +//! GX2 attribute formats +//!----------------------------------------------------------------------------------------------------------------------- +#define GX2_ATTRIB_FORMAT_8_UNORM 0x00000000 +#define GX2_ATTRIB_FORMAT_4_4_UNORM 0x00000001 +#define GX2_ATTRIB_FORMAT_16_UNORM 0x00000002 +#define GX2_ATTRIB_FORMAT_8_8_UNORM 0x00000004 +#define GX2_ATTRIB_FORMAT_16_16_UNORM 0x00000007 +#define GX2_ATTRIB_FORMAT_8_8_8_8_UNORM 0x0000000A +#define GX2_ATTRIB_FORMAT_10_10_10_2_UNORM 0x0000000B +#define GX2_ATTRIB_FORMAT_16_16_16_16_UNORM 0x0000000E + +#define GX2_ATTRIB_FORMAT_8_UINT 0x00000100 +#define GX2_ATTRIB_FORMAT_16_UINT 0x00000102 +#define GX2_ATTRIB_FORMAT_8_8_UINT 0x00000104 +#define GX2_ATTRIB_FORMAT_32_UINT 0x00000105 +#define GX2_ATTRIB_FORMAT_16_16_UINT 0x00000107 +#define GX2_ATTRIB_FORMAT_8_8_8_8_UINT 0x0000010A +#define GX2_ATTRIB_FORMAT_10_10_10_2_UINT 0x0000010B +#define GX2_ATTRIB_FORMAT_32_32_UINT 0x0000010C +#define GX2_ATTRIB_FORMAT_16_16_16_16_UINT 0x0000010E +#define GX2_ATTRIB_FORMAT_32_32_32_UINT 0x00000110 +#define GX2_ATTRIB_FORMAT_32_32_32_32_UINT 0x00000112 + +#define GX2_ATTRIB_FORMAT_8_SNORM 0x00000200 +#define GX2_ATTRIB_FORMAT_16_SNORM 0x00000202 +#define GX2_ATTRIB_FORMAT_8_8_SNORM 0x00000204 +#define GX2_ATTRIB_FORMAT_16_16_SNORM 0x00000207 +#define GX2_ATTRIB_FORMAT_8_8_8_8_SNORM 0x0000020A +#define GX2_ATTRIB_FORMAT_10_10_10_2_SNORM 0x0000020B +#define GX2_ATTRIB_FORMAT_16_16_16_16_SNORM 0x0000020E + +#define GX2_ATTRIB_FORMAT_8_SINT 0x00000300 +#define GX2_ATTRIB_FORMAT_16_SINT 0x00000303 +#define GX2_ATTRIB_FORMAT_8_8_SINT 0x00000304 +#define GX2_ATTRIB_FORMAT_32_SINT 0x00000305 +#define GX2_ATTRIB_FORMAT_16_16_SINT 0x00000307 +#define GX2_ATTRIB_FORMAT_8_8_8_8_SINT 0x0000030A +#define GX2_ATTRIB_FORMAT_10_10_10_2_SINT 0x0000030B +#define GX2_ATTRIB_FORMAT_32_32_SINT 0x0000030C +#define GX2_ATTRIB_FORMAT_16_16_16_16_SINT 0x0000030E +#define GX2_ATTRIB_FORMAT_32_32_32_SINT 0x00000310 +#define GX2_ATTRIB_FORMAT_32_32_32_32_SINT 0x00000312 + +#define GX2_ATTRIB_FORMAT_8_UINT_TO_FLOAT 0x00000800 +#define GX2_ATTRIB_FORMAT_16_UINT_TO_FLOAT 0x00000802 +#define GX2_ATTRIB_FORMAT_16_FLOAT 0x00000803 +#define GX2_ATTRIB_FORMAT_8_8_UINT_TO_FLOAT 0x00000804 +#define GX2_ATTRIB_FORMAT_32_FLOAT 0x00000806 +#define GX2_ATTRIB_FORMAT_16_16_UINT_TO_FLOAT 0x00000807 +#define GX2_ATTRIB_FORMAT_16_16_FLOAT 0x00000808 +#define GX2_ATTRIB_FORMAT_10_11_11_FLOAT 0x00000809 +#define GX2_ATTRIB_FORMAT_8_8_8_8_UINT_TO_FLOAT 0x0000080A +#define GX2_ATTRIB_FORMAT_32_32_FLOAT 0x0000080D +#define GX2_ATTRIB_FORMAT_16_16_16_16_UINT_TO_FLOAT 0x0000080E +#define GX2_ATTRIB_FORMAT_16_16_16_16_FLOAT 0x0000080F +#define GX2_ATTRIB_FORMAT_32_32_32_FLOAT 0x00000811 +#define GX2_ATTRIB_FORMAT_32_32_32_32_FLOAT 0x00000813 + +#define GX2_ATTRIB_FORMAT_8_SINT_TO_FLOAT 0x00000A00 +#define GX2_ATTRIB_FORMAT_16_SINT_TO_FLOAT 0x00000A02 +#define GX2_ATTRIB_FORMAT_8_8_SINT_TO_FLOAT 0x00000A04 +#define GX2_ATTRIB_FORMAT_16_16_SINT_TO_FLOAT 0x00000A07 +#define GX2_ATTRIB_FORMAT_8_8_8_8_SINT_TO_FLOAT 0x00000A0A +#define GX2_ATTRIB_FORMAT_16_16_16_16_SINT_TO_FLOAT 0x00000A0E + +//!----------------------------------------------------------------------------------------------------------------------- +//! GX2 shader modes +//!----------------------------------------------------------------------------------------------------------------------- +#define GX2_SHADER_MODE_UNIFORM_REGISTER 0 +#define GX2_SHADER_MODE_UNIFORM_BLOCK 1 +#define GX2_SHADER_MODE_GEOMETRY_SHADER 2 +#define GX2_SHADER_MODE_COMPUTE_SHADER 3 + +//!----------------------------------------------------------------------------------------------------------------------- +//! GX2 shader modes +//!----------------------------------------------------------------------------------------------------------------------- +#define GX2_COMP_SEL_NONE 0x04040405 +#define GX2_COMP_SEL_X001 0x00040405 +#define GX2_COMP_SEL_XY01 0x00010405 +#define GX2_COMP_SEL_XYZ1 0x00010205 +#define GX2_COMP_SEL_XYZW 0x00010203 +#define GX2_COMP_SEL_XXXX 0x00000000 +#define GX2_COMP_SEL_YYYY 0x01010101 +#define GX2_COMP_SEL_ZZZZ 0x02020202 +#define GX2_COMP_SEL_WWWW 0x03030303 +#define GX2_COMP_SEL_WZYX 0x03020100 +#define GX2_COMP_SEL_WXYZ 0x03000102 + +//!----------------------------------------------------------------------------------------------------------------------- +//! GX2 variable types +//!----------------------------------------------------------------------------------------------------------------------- +#define GX2_VAR_TYPE_VOID 0 +#define GX2_VAR_TYPE_BOOL 1 +#define GX2_VAR_TYPE_INT 2 +#define GX2_VAR_TYPE_UINT 3 +#define GX2_VAR_TYPE_FLOAT 4 +#define GX2_VAR_TYPE_DOUBLE 5 +#define GX2_VAR_TYPE_VEC2 9 +#define GX2_VAR_TYPE_VEC3 10 +#define GX2_VAR_TYPE_VEC4 11 +#define GX2_VAR_TYPE_MAT2 21 +#define GX2_VAR_TYPE_MAT3 25 +#define GX2_VAR_TYPE_MAT4 29 + +//!----------------------------------------------------------------------------------------------------------------------- +//! GX2 sample types +//!----------------------------------------------------------------------------------------------------------------------- +#define GX2_SAMPLER_TYPE_2D 1 + + +//!----------------------------------------------------------------------------------------------------------------------- +//! GX2 index formats +//!----------------------------------------------------------------------------------------------------------------------- +#define GX2_INDEX_FORMAT_U16 4 +#define GX2_INDEX_FORMAT_U32 9 + +//!----------------------------------------------------------------------------------------------------------------------- +//! GX2 primitive types +//!----------------------------------------------------------------------------------------------------------------------- +#define GX2_PRIMITIVE_POINTS 0x01 +#define GX2_PRIMITIVE_LINES 0x02 +#define GX2_PRIMITIVE_LINE_STRIP 0x03 +#define GX2_PRIMITIVE_TRIANGLES 0x04 +#define GX2_PRIMITIVE_TRIANGLE_FAN 0x05 +#define GX2_PRIMITIVE_TRIANGLE_STRIP 0x06 +#define GX2_PRIMITIVE_RECTS 0x11 +#define GX2_PRIMITIVE_QUADS 0x13 +#define GX2_PRIMITIVE_QUAD_STRIP 0x14 + +//!----------------------------------------------------------------------------------------------------------------------- +//! GX2 clear modes +//!----------------------------------------------------------------------------------------------------------------------- +#define GX2_CLEAR_DEPTH 0x01 +#define GX2_CLEAR_STENCIL 0x02 +#define GX2_CLEAR_BOTH (GX2_CLEAR_DEPTH | GX2_CLEAR_STENCIL) + +//!----------------------------------------------------------------------------------------------------------------------- +//! GX2 surface formats +//!----------------------------------------------------------------------------------------------------------------------- +#define GX2_SURFACE_FORMAT_TC_R8_UNORM 0x00000001 +#define GX2_SURFACE_FORMAT_T_R4_G4_UNORM 0x00000002 +#define GX2_SURFACE_FORMAT_TCD_R16_UNORM 0x00000005 +#define GX2_SURFACE_FORMAT_TC_R8_G8_UNORM 0x00000007 +#define GX2_SURFACE_FORMAT_TCS_R5_G6_B5_UNORM 0x00000008 +#define GX2_SURFACE_FORMAT_TC_R5_G5_B5_A1_UNORM 0x0000000a +#define GX2_SURFACE_FORMAT_TC_R4_G4_B4_A4_UNORM 0x0000000b +#define GX2_SURFACE_FORMAT_TC_A1_B5_G5_R5_UNORM 0x0000000c +#define GX2_SURFACE_FORMAT_TC_R16_G16_UNORM 0x0000000f +#define GX2_SURFACE_FORMAT_D_D24_S8_UNORM 0x00000011 +#define GX2_SURFACE_FORMAT_T_R24_UNORM_X8 0x00000011 +#define GX2_SURFACE_FORMAT_TCS_R10_G10_B10_A2_UNORM 0x00000019 +#define GX2_SURFACE_FORMAT_TCS_R8_G8_B8_A8_UNORM 0x0000001a +#define GX2_SURFACE_FORMAT_TCS_A2_B10_G10_R10_UNORM 0x0000001b +#define GX2_SURFACE_FORMAT_TC_R16_G16_B16_A16_UNORM 0x0000001f +#define GX2_SURFACE_FORMAT_T_BC1_UNORM 0x00000031 +#define GX2_SURFACE_FORMAT_T_BC2_UNORM 0x00000032 +#define GX2_SURFACE_FORMAT_T_BC3_UNORM 0x00000033 +#define GX2_SURFACE_FORMAT_T_BC4_UNORM 0x00000034 +#define GX2_SURFACE_FORMAT_T_BC5_UNORM 0x00000035 +#define GX2_SURFACE_FORMAT_T_NV12_UNORM 0x00000081 + +#define GX2_SURFACE_FORMAT_TC_R8_UINT 0x00000101 +#define GX2_SURFACE_FORMAT_TC_R16_UINT 0x00000105 +#define GX2_SURFACE_FORMAT_TC_R8_G8_UINT 0x00000107 +#define GX2_SURFACE_FORMAT_TC_R32_UINT 0x0000010d +#define GX2_SURFACE_FORMAT_TC_R16_G16_UINT 0x0000010f +#define GX2_SURFACE_FORMAT_T_X24_G8_UINT 0x00000111 +#define GX2_SURFACE_FORMAT_TC_R10_G10_B10_A2_UINT 0x00000119 +#define GX2_SURFACE_FORMAT_TC_R8_G8_B8_A8_UINT 0x0000011a +#define GX2_SURFACE_FORMAT_TC_A2_B10_G10_R10_UINT 0x0000011b +#define GX2_SURFACE_FORMAT_T_X32_G8_UINT_X24 0x0000011c +#define GX2_SURFACE_FORMAT_TC_R32_G32_UINT 0x0000011d +#define GX2_SURFACE_FORMAT_TC_R16_G16_B16_A16_UINT 0x0000011f +#define GX2_SURFACE_FORMAT_TC_R32_G32_B32_A32_UINT 0x00000122 + +#define GX2_SURFACE_FORMAT_TC_R8_SNORM 0x00000201 +#define GX2_SURFACE_FORMAT_TC_R16_SNORM 0x00000205 +#define GX2_SURFACE_FORMAT_TC_R8_G8_SNORM 0x00000207 +#define GX2_SURFACE_FORMAT_TC_R16_G16_SNORM 0x0000020f +#define GX2_SURFACE_FORMAT_T_R10_G10_B10_A2_SNORM 0x00000219 +#define GX2_SURFACE_FORMAT_TC_R10_G10_B10_A2_SNORM 0x00000219 +#define GX2_SURFACE_FORMAT_TC_R8_G8_B8_A8_SNORM 0x0000021a +#define GX2_SURFACE_FORMAT_TC_R16_G16_B16_A16_SNORM 0x0000021f +#define GX2_SURFACE_FORMAT_T_BC4_SNORM 0x00000234 +#define GX2_SURFACE_FORMAT_T_BC5_SNORM 0x00000235 + +#define GX2_SURFACE_FORMAT_TC_R8_SINT 0x00000301 +#define GX2_SURFACE_FORMAT_TC_R16_SINT 0x00000305 +#define GX2_SURFACE_FORMAT_TC_R8_G8_SINT 0x00000307 +#define GX2_SURFACE_FORMAT_TC_R32_SINT 0x0000030d +#define GX2_SURFACE_FORMAT_TC_R16_G16_SINT 0x0000030f +#define GX2_SURFACE_FORMAT_TC_R10_G10_B10_A2_SINT 0x00000319 +#define GX2_SURFACE_FORMAT_TC_R8_G8_B8_A8_SINT 0x0000031a +#define GX2_SURFACE_FORMAT_TC_R32_G32_SINT 0x0000031d +#define GX2_SURFACE_FORMAT_TC_R16_G16_B16_A16_SINT 0x0000031f +#define GX2_SURFACE_FORMAT_TC_R32_G32_B32_A32_SINT 0x00000322 + +#define GX2_SURFACE_FORMAT_TCS_R8_G8_B8_A8_SRGB 0x0000041a +#define GX2_SURFACE_FORMAT_T_BC1_SRGB 0x00000431 +#define GX2_SURFACE_FORMAT_T_BC2_SRGB 0x00000432 +#define GX2_SURFACE_FORMAT_T_BC3_SRGB 0x00000433 + +#define GX2_SURFACE_FORMAT_TC_R16_FLOAT 0x00000806 +#define GX2_SURFACE_FORMAT_TCD_R32_FLOAT 0x0000080e +#define GX2_SURFACE_FORMAT_TC_R16_G16_FLOAT 0x00000810 +#define GX2_SURFACE_FORMAT_D_D24_S8_FLOAT 0x00000811 +#define GX2_SURFACE_FORMAT_TC_R11_G11_B10_FLOAT 0x00000816 +#define GX2_SURFACE_FORMAT_D_D32_FLOAT_S8_UINT_X24 0x0000081c +#define GX2_SURFACE_FORMAT_T_R32_FLOAT_X8_X24 0x0000081c +#define GX2_SURFACE_FORMAT_TC_R32_G32_FLOAT 0x0000081e +#define GX2_SURFACE_FORMAT_TC_R16_G16_B16_A16_FLOAT 0x00000820 +#define GX2_SURFACE_FORMAT_TC_R32_G32_B32_A32_FLOAT 0x00000823 + +//!----------------------------------------------------------------------------------------------------------------------- +//! GX2 tile modes +//!----------------------------------------------------------------------------------------------------------------------- +#define GX2_TILE_MODE_DEFAULT 0x00000000 +#define GX2_TILE_MODE_LINEAR_ALIGNED 0x00000001 + +//!----------------------------------------------------------------------------------------------------------------------- +//! GX2 surface use +//!----------------------------------------------------------------------------------------------------------------------- +#define GX2_SURFACE_USE_TEXTURE 0x00000001 +#define GX2_SURFACE_USE_COLOR_BUFFER 0x00000002 +#define GX2_SURFACE_USE_DEPTH_BUFFER 0x00000004 +#define GX2_SURFACE_USE_SCAN_BUFFER 0x00000008 +#define GX2_SURFACE_USE_FTV 0x80000000 +#define GX2_SURFACE_USE_COLOR_BUFFER_TEXTURE (GX2_SURFACE_USE_COLOR_BUFFER | GX2_SURFACE_USE_TEXTURE) +#define GX2_SURFACE_USE_DEPTH_BUFFER_TEXTURE (GX2_SURFACE_USE_DEPTH_BUFFER | GX2_SURFACE_USE_TEXTURE) +#define GX2_SURFACE_USE_COLOR_BUFFER_FTV (GX2_SURFACE_USE_COLOR_BUFFER | GX2_SURFACE_USE_FTV) +#define GX2_SURFACE_USE_COLOR_BUFFER_TEXTURE_FTV (GX2_SURFACE_USE_COLOR_BUFFER_TEXTURE | GX2_SURFACE_USE_FTV) + +//!----------------------------------------------------------------------------------------------------------------------- +//! GX2 surface dim +//!----------------------------------------------------------------------------------------------------------------------- +#define GX2_SURFACE_DIM_1D 0x00000000 +#define GX2_SURFACE_DIM_2D 0x00000001 +#define GX2_SURFACE_DIM_3D 0x00000002 +#define GX2_SURFACE_DIM_CUBE 0x00000003 +#define GX2_SURFACE_DIM_1D_ARRAY 0x00000004 +#define GX2_SURFACE_DIM_2D_ARRAY 0x00000005 +#define GX2_SURFACE_DIM_2D_MSAA 0x00000006 +#define GX2_SURFACE_DIM_2D_MSAA_ARRAY 0x00000007 + +//!----------------------------------------------------------------------------------------------------------------------- +//! GX2 AA modes +//!----------------------------------------------------------------------------------------------------------------------- +#define GX2_AA_MODE_1X 0x00000000 +#define GX2_AA_MODE_2X 0x00000001 +#define GX2_AA_MODE_4X 0x00000002 +#define GX2_AA_MODE_8X 0x00000003 + +//!----------------------------------------------------------------------------------------------------------------------- +//! GX2 texture clamp +//!----------------------------------------------------------------------------------------------------------------------- +#define GX2_TEX_CLAMP_WRAP 0x00000000 +#define GX2_TEX_CLAMP_MIRROR 0x00000001 +#define GX2_TEX_CLAMP_CLAMP 0x00000002 +#define GX2_TEX_CLAMP_MIRROR_ONCE 0x00000003 +#define GX2_TEX_CLAMP_CLAMP_HALF_BORDER 0x00000004 +#define GX2_TEX_CLAMP_MIRROR_ONCE_HALF_BORDER 0x00000005 +#define GX2_TEX_CLAMP_CLAMP_BORDER 0x00000006 +#define GX2_TEX_CLAMP_MIRROR_ONCE_BORDER 0x00000007 + +//!----------------------------------------------------------------------------------------------------------------------- +//! GX2 texture filter +//!----------------------------------------------------------------------------------------------------------------------- +#define GX2_TEX_XY_FILTER_POINT 0x00000000 +#define GX2_TEX_XY_FILTER_BILINEAR 0x00000001 + +//!----------------------------------------------------------------------------------------------------------------------- +//! GX2 TV scan modes +//!----------------------------------------------------------------------------------------------------------------------- +#define GX2_TV_SCAN_MODE_NONE 0x00000000 +#define GX2_TV_SCAN_MODE_576I 0x00000001 +#define GX2_TV_SCAN_MODE_480I 0x00000002 +#define GX2_TV_SCAN_MODE_480P 0x00000003 +#define GX2_TV_SCAN_MODE_720P 0x00000004 +#define GX2_TV_SCAN_MODE_1080I 0x00000006 +#define GX2_TV_SCAN_MODE_1080P 0x00000007 + +//!----------------------------------------------------------------------------------------------------------------------- +//! GX2 TV render modes +//!----------------------------------------------------------------------------------------------------------------------- +#define GX2_TV_RENDER_480_NARROW 0x00000001 +#define GX2_TV_RENDER_480_WIDE 0x00000002 +#define GX2_TV_RENDER_720 0x00000003 +#define GX2_TV_RENDER_1080 0x00000005 + +//!----------------------------------------------------------------------------------------------------------------------- +//! GX2 DRC render modes +//!----------------------------------------------------------------------------------------------------------------------- +#define GX2_DRC_NONE 0x00000000 +#define GX2_DRC_SINGLE 0x00000001 +#define GX2_DRC_DOUBLE 0x00000002 +#define GX2_DRC_SINGLE_30HZ 0x00000004 + +//!----------------------------------------------------------------------------------------------------------------------- +//! GX2 buffering mode +//!----------------------------------------------------------------------------------------------------------------------- +#define GX2_BUFFERING_SINGLE 0x00000001 +#define GX2_BUFFERING_DOUBLE 0x00000002 +#define GX2_BUFFERING_TRIPLE 0x00000003 +#define GX2_BUFFERING_QUAD +//!----------------------------------------------------------------------------------------------------------------------- +//! GX2 scan targets +//!----------------------------------------------------------------------------------------------------------------------- +#define GX2_SCAN_TARGET_TV 0x00000001 +#define GX2_SCAN_TARGET_DRC_FIRST 0x00000004 +#define GX2_SCAN_TARGET_DRC_SECOND 0x00000008 + +//!----------------------------------------------------------------------------------------------------------------------- +//! GX2 invalidate types +//!----------------------------------------------------------------------------------------------------------------------- +#define GX2_INVALIDATE_ATTRIB_BUFFER 0x00000001 +#define GX2_INVALIDATE_TEXTURE 0x00000002 +#define GX2_INVALIDATE_UNIFORM_BLOCK 0x00000004 +#define GX2_INVALIDATE_SHADER 0x00000008 +#define GX2_INVALIDATE_COLOR_BUFFER 0x00000010 +#define GX2_INVALIDATE_DEPTH_BUFFER 0x00000020 +#define GX2_INVALIDATE_CPU 0x00000040 +#define GX2_INVALIDATE_CPU_ATTRIB_BUFFER (GX2_INVALIDATE_CPU | GX2_INVALIDATE_ATTRIB_BUFFER) +#define GX2_INVALIDATE_CPU_TEXTURE (GX2_INVALIDATE_CPU | GX2_INVALIDATE_TEXTURE) +#define GX2_INVALIDATE_CPU_UNIFORM_BLOCK (GX2_INVALIDATE_CPU | GX2_INVALIDATE_UNIFORM_BLOCK) +#define GX2_INVALIDATE_CPU_SHADER (GX2_INVALIDATE_CPU | GX2_INVALIDATE_SHADER) + +//!----------------------------------------------------------------------------------------------------------------------- +//! GX2 swap modes +//!----------------------------------------------------------------------------------------------------------------------- +#define GX2_ENDIANSWAP_DEFAULT 0x00000003 + +//!----------------------------------------------------------------------------------------------------------------------- +//! GX2 tessellation modes +//!----------------------------------------------------------------------------------------------------------------------- +#define GX2_TESSELLATION_MODE_DISCRETE 0x00000000 +#define GX2_TESSELLATION_MODE_CONTINUOUS 0x00000001 +#define GX2_TESSELLATION_MODE_ADAPTIVE 0x00000002 + +//!----------------------------------------------------------------------------------------------------------------------- +//! GX2 fetch shader types +//!----------------------------------------------------------------------------------------------------------------------- +#define GX2_FETCH_SHADER_TESSELATION_NONE 0x00000000 +#define GX2_FETCH_SHADER_TESSELATION_LINES 0x00000001 +#define GX2_FETCH_SHADER_TESSELATION_TRIANGLES 0x00000002 +#define GX2_FETCH_SHADER_TESSELATION_QUADS 0x00000003 + + +typedef struct _GX2ContextState { + u8 data[GX2_CONTEXT_STATE_SIZE]; +} GX2ContextState; + +typedef struct _GX2Surface { + s32 dimension; + u32 width; + u32 height; + u32 depth; + u32 num_mips; + s32 format; + s32 aa; + s32 use; + u32 image_size; + void *image_data; + u32 mip_size; + void *mip_data; + s32 tile; + u32 swizzle; + u32 align; + u32 pitch; + u32 mip_offset[13]; +} GX2Surface; + +typedef struct _GX2ColorBuffer { + GX2Surface surface; + u32 view_mip; + u32 view_first_slice; + u32 view_slices_count; + void *aux_data; + u32 aux_size; + u32 regs[5]; +} GX2ColorBuffer; + +typedef struct _GX2DepthBuffer { + GX2Surface surface; + u32 view_mip; + u32 view_first_slice; + u32 view_slices_count; + void *hiZ_data; + u32 hiZ_size; + f32 clear_depth; + u32 clear_stencil; + u32 regs[7]; +} GX2DepthBuffer; + + +typedef struct _GX2Texture { + GX2Surface surface; + u32 view_first_mip; + u32 view_mips_count; + u32 view_first_slice; + u32 view_slices_count; + u32 component_selector; + u32 regs[5]; +} GX2Texture; + + +typedef struct _GX2Sampler { + u32 regs[3]; +} GX2Sampler; + +typedef struct _GX2AttribStream { + u32 location; + u32 buffer; + u32 offset; + s32 format; + s32 index_type; + u32 divisor; + u32 destination_selector; + s32 endian_swap; +} GX2AttribStream; + +typedef struct _GX2FetchShader { + s32 type; + u32 reg; + u32 shader_size; + void *shader_program; + u32 attributes_count; + u32 divisor[3]; +} GX2FetchShader; + +typedef struct _GX2AttribVar +{ + const char *name; + s32 var_type; + u32 array_count; + u32 location; +} GX2AttribVar; + + +typedef struct _GX2UniformBlock { + const char *name; + u32 location; + u32 block_size; +} GX2UniformBlock; + +typedef struct _GX2UniformInitialValue { + f32 value[4]; + u32 offset; +} GX2UniformInitialValue; + +typedef struct _GX2SamplerVar +{ + const char *name; + s32 sampler_type; + u32 location; +} GX2SamplerVar; + +typedef struct _GX2UniformVar +{ + const char *name; + s32 var_type; + u32 array_count; + u32 offset; + u32 block_index; +} GX2UniformVar; + +typedef struct _GX2VertexShader { + u32 regs[52]; + u32 shader_size; + void *shader_data; + s32 shader_mode; + u32 uniform_blocks_count; + GX2UniformBlock *uniform_block; + u32 uniform_vars_count; + GX2UniformVar *uniform_var; + u32 initial_values_count; + GX2UniformInitialValue *initial_value; + u32 loops_count; + void *loops_data; + u32 sampler_vars_count; + GX2SamplerVar *sampler_var; + u32 attribute_vars_count; + GX2AttribVar *attribute_var; + u32 data[6]; + u32 shader_program_buffer[16]; +} GX2VertexShader; + +typedef struct _GX2PixelShader { + u32 regs[41]; + u32 shader_size; + void *shader_data; + s32 shader_mode; + u32 uniform_blocks_count; + GX2UniformBlock *uniform_block; + u32 uniform_vars_count; + GX2UniformVar *uniform_var; + u32 initial_values_count; + GX2UniformInitialValue *initial_value; + u32 loops_count; + void *loops_data; + u32 sampler_vars_count; + GX2SamplerVar *sampler_var; + u32 shader_program_buffer[16]; +} GX2PixelShader; + +static const u32 attribute_dest_comp_selector[20] = { + GX2_COMP_SEL_X001, GX2_COMP_SEL_XY01, GX2_COMP_SEL_X001, GX2_COMP_SEL_X001, GX2_COMP_SEL_XY01, GX2_COMP_SEL_X001, + GX2_COMP_SEL_X001, GX2_COMP_SEL_XY01, GX2_COMP_SEL_XY01, GX2_COMP_SEL_XYZ1, GX2_COMP_SEL_XYZW, GX2_COMP_SEL_XYZW, + GX2_COMP_SEL_XY01, GX2_COMP_SEL_XY01, GX2_COMP_SEL_XYZW, GX2_COMP_SEL_XYZW, GX2_COMP_SEL_XYZ1, GX2_COMP_SEL_XYZ1, + GX2_COMP_SEL_XYZW, GX2_COMP_SEL_XYZW +}; + +static const u32 texture_comp_selector[54] = { + GX2_COMP_SEL_NONE, GX2_COMP_SEL_X001, GX2_COMP_SEL_XY01, GX2_COMP_SEL_NONE, GX2_COMP_SEL_NONE, GX2_COMP_SEL_X001, + GX2_COMP_SEL_X001, GX2_COMP_SEL_XY01, GX2_COMP_SEL_XYZ1, GX2_COMP_SEL_XYZ1, GX2_COMP_SEL_XYZW, GX2_COMP_SEL_XYZW, + GX2_COMP_SEL_WZYX, GX2_COMP_SEL_X001, GX2_COMP_SEL_X001, GX2_COMP_SEL_XY01, GX2_COMP_SEL_XY01, GX2_COMP_SEL_NONE, + GX2_COMP_SEL_NONE, GX2_COMP_SEL_NONE, GX2_COMP_SEL_NONE, GX2_COMP_SEL_NONE, GX2_COMP_SEL_XYZ1, GX2_COMP_SEL_NONE, + GX2_COMP_SEL_NONE, GX2_COMP_SEL_XYZW, GX2_COMP_SEL_XYZW, GX2_COMP_SEL_WZYX, GX2_COMP_SEL_XY01, GX2_COMP_SEL_XY01, + GX2_COMP_SEL_XY01, GX2_COMP_SEL_XYZW, GX2_COMP_SEL_XYZW, GX2_COMP_SEL_NONE, GX2_COMP_SEL_XYZW, GX2_COMP_SEL_XYZW, + GX2_COMP_SEL_NONE, GX2_COMP_SEL_NONE, GX2_COMP_SEL_NONE, GX2_COMP_SEL_XYZ1, GX2_COMP_SEL_XYZ1, GX2_COMP_SEL_X001, + GX2_COMP_SEL_XY01, GX2_COMP_SEL_XYZ1, GX2_COMP_SEL_NONE, GX2_COMP_SEL_NONE, GX2_COMP_SEL_NONE, GX2_COMP_SEL_XYZ1, + GX2_COMP_SEL_XYZ1, GX2_COMP_SEL_XYZW, GX2_COMP_SEL_XYZW, GX2_COMP_SEL_XYZW, GX2_COMP_SEL_X001, GX2_COMP_SEL_XY01 +}; + +typedef struct _GX2Color { + u8 r, g, b, a; +} GX2Color; + +typedef struct _GX2ColorF32 { + f32 r, g, b, a; +} GX2ColorF32; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/dynamic_libs/os_functions.c b/src/dynamic_libs/os_functions.c new file mode 100644 index 0000000..ac4df6f --- /dev/null +++ b/src/dynamic_libs/os_functions.c @@ -0,0 +1,216 @@ +/**************************************************************************** + * Copyright (C) 2015 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include "common/common.h" +#include "os_functions.h" + +unsigned int coreinit_handle __attribute__((section(".data"))) = 0; + +//!---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//! Lib handle functions +//!---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +EXPORT_DECL(int, OSDynLoad_Acquire, const char* rpl, u32 *handle); +EXPORT_DECL(int, OSDynLoad_FindExport, u32 handle, int isdata, const char *symbol, void *address); + +//!---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//! Security functions +//!---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +EXPORT_DECL(int, OSGetSecurityLevel, void); +EXPORT_DECL(int, OSForceFullRelaunch, void); + +//!---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//! Thread functions +//!---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +EXPORT_DECL(int, OSCreateThread, void *thread, s32 (*callback)(s32, void*), s32 argc, void *args, u32 stack, u32 stack_size, s32 priority, u32 attr); +EXPORT_DECL(int, OSResumeThread, void *thread); +EXPORT_DECL(int, OSSuspendThread, void *thread); +EXPORT_DECL(int, OSIsThreadTerminated, void *thread); +EXPORT_DECL(int, OSIsThreadSuspended, void *thread); +EXPORT_DECL(int, OSSetThreadPriority, void * thread, int priority); +EXPORT_DECL(int, OSJoinThread, void * thread, int * ret_val); +EXPORT_DECL(void, OSDetachThread, void * thread); +EXPORT_DECL(void, OSSleepTicks, u64 ticks); +EXPORT_DECL(u64, OSGetTick, void); +EXPORT_DECL(u64, OSGetTime, void); +EXPORT_DECL(void, OSTicksToCalendarTime, u64 time, OSCalendarTime * calendarTime); + + +//!---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//! Mutex functions +//!---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +EXPORT_DECL(void, OSInitMutex, void* mutex); +EXPORT_DECL(void, OSLockMutex, void* mutex); +EXPORT_DECL(void, OSUnlockMutex, void* mutex); +EXPORT_DECL(int, OSTryLockMutex, void* mutex); + +//!---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//! System functions +//!---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +EXPORT_DECL(u64, OSGetTitleID, void); +EXPORT_DECL(void, OSGetArgcArgv, int* argc, char*** argv); +EXPORT_DECL(void, __Exit, void); +EXPORT_DECL(void, OSFatal, const char* msg); +EXPORT_DECL(void, OSSetExceptionCallback, u8 exceptionType, exception_callback newCallback); +EXPORT_DECL(void, DCFlushRange, const void *addr, u32 length); +EXPORT_DECL(void, DCStoreRange, const void *addr, u32 length); +EXPORT_DECL(void, DCInvalidateRange, const void *addr, u32 length); +EXPORT_DECL(void, ICInvalidateRange, const void *addr, u32 length); +EXPORT_DECL(void*, OSEffectiveToPhysical, const void*); +EXPORT_DECL(int, __os_snprintf, char* s, int n, const char * format, ...); +EXPORT_DECL(int *, __gh_errno_ptr, void); + +EXPORT_DECL(void, OSScreenInit, void); +EXPORT_DECL(void, OSScreenShutdown, void); +EXPORT_DECL(unsigned int, OSScreenGetBufferSizeEx, unsigned int bufferNum); +EXPORT_DECL(int, OSScreenSetBufferEx, unsigned int bufferNum, void * addr); +EXPORT_DECL(int, OSScreenClearBufferEx, unsigned int bufferNum, unsigned int temp); +EXPORT_DECL(int, OSScreenFlipBuffersEx, unsigned int bufferNum); +EXPORT_DECL(int, OSScreenPutFontEx, unsigned int bufferNum, unsigned int posX, unsigned int posY, const char * buffer); +EXPORT_DECL(int, OSScreenEnableEx, unsigned int bufferNum, int enable); + +EXPORT_DECL(int, IOS_Ioctl,int fd, unsigned int request, void *input_buffer,unsigned int input_buffer_len, void *output_buffer, unsigned int output_buffer_len); +EXPORT_DECL(int, IOS_Open,char *path, unsigned int mode); +EXPORT_DECL(int, IOS_Close,int fd); + +//!---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//! Memory functions +//!---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +EXPORT_VAR(unsigned int *, pMEMAllocFromDefaultHeapEx); +EXPORT_VAR(unsigned int *, pMEMAllocFromDefaultHeap); +EXPORT_VAR(unsigned int *, pMEMFreeToDefaultHeap); + +EXPORT_DECL(int, MEMGetBaseHeapHandle, int mem_arena); +EXPORT_DECL(unsigned int, MEMGetAllocatableSizeForFrmHeapEx, int heap, int align); +EXPORT_DECL(void *, MEMAllocFromFrmHeapEx, int heap, unsigned int size, int align); +EXPORT_DECL(void, MEMFreeToFrmHeap, int heap, int mode); +EXPORT_DECL(void *, MEMAllocFromExpHeapEx, int heap, unsigned int size, int align); +EXPORT_DECL(int , MEMCreateExpHeapEx, void* address, unsigned int size, unsigned short flags); +EXPORT_DECL(void *, MEMDestroyExpHeap, int heap); +EXPORT_DECL(void, MEMFreeToExpHeap, int heap, void* ptr); + +//!---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//! MCP functions +//!---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +EXPORT_DECL(int, MCP_Open, void); +EXPORT_DECL(int, MCP_Close, int handle); +EXPORT_DECL(int, MCP_GetOwnTitleInfo, int handle, void * data); + + +void InitAcquireOS(void) +{ + //!---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + //! Lib handle functions + //!---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + EXPORT_FUNC_WRITE(OSDynLoad_Acquire, (int (*)(const char*, unsigned *))OS_SPECIFICS->addr_OSDynLoad_Acquire); + EXPORT_FUNC_WRITE(OSDynLoad_FindExport, (int (*)(u32, int, const char *, void *))OS_SPECIFICS->addr_OSDynLoad_FindExport); + + OSDynLoad_Acquire("coreinit.rpl", &coreinit_handle); +} + +void InitOSFunctionPointers(void) +{ + unsigned int *funcPointer = 0; + + InitAcquireOS(); + + //!---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + //! Security functions + //!---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + OS_FIND_EXPORT(coreinit_handle, OSGetSecurityLevel); + OS_FIND_EXPORT(coreinit_handle, OSForceFullRelaunch); + //!---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + //! System functions + //!---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + OS_FIND_EXPORT(coreinit_handle, OSFatal); + OS_FIND_EXPORT(coreinit_handle, OSGetTitleID); + OS_FIND_EXPORT(coreinit_handle, OSGetArgcArgv); + OS_FIND_EXPORT(coreinit_handle, OSSetExceptionCallback); + OS_FIND_EXPORT(coreinit_handle, DCFlushRange); + OS_FIND_EXPORT(coreinit_handle, DCStoreRange); + OS_FIND_EXPORT(coreinit_handle, DCInvalidateRange); + OS_FIND_EXPORT(coreinit_handle, ICInvalidateRange); + OS_FIND_EXPORT(coreinit_handle, OSEffectiveToPhysical); + OS_FIND_EXPORT(coreinit_handle, __os_snprintf); + OS_FIND_EXPORT(coreinit_handle, __gh_errno_ptr); + + OSDynLoad_FindExport(coreinit_handle, 0, "_Exit", &__Exit); + + OS_FIND_EXPORT(coreinit_handle, OSScreenInit); + OS_FIND_EXPORT(coreinit_handle, OSScreenShutdown); + OS_FIND_EXPORT(coreinit_handle, OSScreenGetBufferSizeEx); + OS_FIND_EXPORT(coreinit_handle, OSScreenSetBufferEx); + OS_FIND_EXPORT(coreinit_handle, OSScreenClearBufferEx); + OS_FIND_EXPORT(coreinit_handle, OSScreenFlipBuffersEx); + OS_FIND_EXPORT(coreinit_handle, OSScreenPutFontEx); + OS_FIND_EXPORT(coreinit_handle, OSScreenEnableEx); + + OS_FIND_EXPORT(coreinit_handle, IOS_Ioctl); + OS_FIND_EXPORT(coreinit_handle, IOS_Open); + OS_FIND_EXPORT(coreinit_handle, IOS_Close); + + //!---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + //! Thread functions + //!---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + OS_FIND_EXPORT(coreinit_handle, OSCreateThread); + OS_FIND_EXPORT(coreinit_handle, OSResumeThread); + OS_FIND_EXPORT(coreinit_handle, OSSuspendThread); + OS_FIND_EXPORT(coreinit_handle, OSIsThreadTerminated); + OS_FIND_EXPORT(coreinit_handle, OSIsThreadSuspended); + OS_FIND_EXPORT(coreinit_handle, OSJoinThread); + OS_FIND_EXPORT(coreinit_handle, OSSetThreadPriority); + OS_FIND_EXPORT(coreinit_handle, OSDetachThread); + OS_FIND_EXPORT(coreinit_handle, OSSleepTicks); + OS_FIND_EXPORT(coreinit_handle, OSGetTick); + OS_FIND_EXPORT(coreinit_handle, OSGetTime); + OS_FIND_EXPORT(coreinit_handle, OSTicksToCalendarTime); + + //!---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + //! Mutex functions + //!---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + OS_FIND_EXPORT(coreinit_handle, OSInitMutex); + OS_FIND_EXPORT(coreinit_handle, OSLockMutex); + OS_FIND_EXPORT(coreinit_handle, OSUnlockMutex); + OS_FIND_EXPORT(coreinit_handle, OSTryLockMutex); + //!---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + //! MCP functions + //!---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + OS_FIND_EXPORT(coreinit_handle, MCP_Open); + OS_FIND_EXPORT(coreinit_handle, MCP_Close); + OS_FIND_EXPORT(coreinit_handle, MCP_GetOwnTitleInfo); + + //!---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + //! Memory functions + //!---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + OSDynLoad_FindExport(coreinit_handle, 1, "MEMAllocFromDefaultHeapEx", &pMEMAllocFromDefaultHeapEx); + OSDynLoad_FindExport(coreinit_handle, 1, "MEMAllocFromDefaultHeap", &pMEMAllocFromDefaultHeap); + OSDynLoad_FindExport(coreinit_handle, 1, "MEMFreeToDefaultHeap", &pMEMFreeToDefaultHeap); + + OS_FIND_EXPORT(coreinit_handle, MEMGetBaseHeapHandle); + OS_FIND_EXPORT(coreinit_handle, MEMGetAllocatableSizeForFrmHeapEx); + OS_FIND_EXPORT(coreinit_handle, MEMAllocFromFrmHeapEx); + OS_FIND_EXPORT(coreinit_handle, MEMFreeToFrmHeap); + OS_FIND_EXPORT(coreinit_handle, MEMAllocFromExpHeapEx); + OS_FIND_EXPORT(coreinit_handle, MEMCreateExpHeapEx); + OS_FIND_EXPORT(coreinit_handle, MEMDestroyExpHeap); + OS_FIND_EXPORT(coreinit_handle, MEMFreeToExpHeap); +} diff --git a/src/dynamic_libs/os_functions.h b/src/dynamic_libs/os_functions.h new file mode 100644 index 0000000..0dc7c52 --- /dev/null +++ b/src/dynamic_libs/os_functions.h @@ -0,0 +1,150 @@ +/**************************************************************************** + * Copyright (C) 2015 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef __OS_FUNCTIONS_H_ +#define __OS_FUNCTIONS_H_ + +#include +#include "common/os_defs.h" +#include "os_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define BUS_SPEED 248625000 +#define SECS_TO_TICKS(sec) (((unsigned long long)(sec)) * (BUS_SPEED/4)) +#define MILLISECS_TO_TICKS(msec) (SECS_TO_TICKS(msec) / 1000) +#define MICROSECS_TO_TICKS(usec) (SECS_TO_TICKS(usec) / 1000000) + +#define usleep(usecs) OSSleepTicks(MICROSECS_TO_TICKS(usecs)) +#define sleep(secs) OSSleepTicks(SECS_TO_TICKS(secs)) + +#define FLUSH_DATA_BLOCK(addr) asm volatile("dcbf 0, %0; sync" : : "r"(((addr) & ~31))) +#define INVAL_DATA_BLOCK(addr) asm volatile("dcbi 0, %0; sync" : : "r"(((addr) & ~31))) + +#define EXPORT_DECL(res, func, ...) res (* func)(__VA_ARGS__) __attribute__((section(".data"))) = 0; +#define EXPORT_VAR(type, var) type var __attribute__((section(".data"))); + + +#define EXPORT_FUNC_WRITE(func, val) *(u32*)(((u32)&func) + 0) = (u32)val + +#define OS_FIND_EXPORT(handle, func) funcPointer = 0; \ + OSDynLoad_FindExport(handle, 0, # func, &funcPointer); \ + if(!funcPointer) \ + OSFatal("Function " # func " is NULL"); \ + EXPORT_FUNC_WRITE(func, funcPointer); + +#define OS_FIND_EXPORT_EX(handle, func, func_p) \ + funcPointer = 0; \ + OSDynLoad_FindExport(handle, 0, # func, &funcPointer); \ + if(!funcPointer) \ + OSFatal("Function " # func " is NULL"); \ + EXPORT_FUNC_WRITE(func_p, funcPointer); + +#define OS_MUTEX_SIZE 44 + +/* Handle for coreinit */ +extern unsigned int coreinit_handle; +void InitOSFunctionPointers(void); +void InitAcquireOS(void); + +//!---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//! Lib handle functions +//!---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +extern int (* OSDynLoad_Acquire)(const char* rpl, u32 *handle); +extern int (* OSDynLoad_FindExport)(u32 handle, int isdata, const char *symbol, void *address); + +//!---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//! Security functions +//!---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +extern int (* OSGetSecurityLevel)(void); +extern int (* OSForceFullRelaunch)(void); + +//!---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//! Thread functions +//!---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +extern int (* OSCreateThread)(void *thread, s32 (*callback)(s32, void*), s32 argc, void *args, u32 stack, u32 stack_size, s32 priority, u32 attr); +extern int (* OSResumeThread)(void *thread); +extern int (* OSSuspendThread)(void *thread); +extern int (* OSIsThreadTerminated)(void *thread); +extern int (* OSIsThreadSuspended)(void *thread); +extern int (* OSJoinThread)(void * thread, int * ret_val); +extern int (* OSSetThreadPriority)(void * thread, int priority); +extern void (* OSDetachThread)(void * thread); +extern void (* OSSleepTicks)(u64 ticks); +extern u64 (* OSGetTick)(void); +extern u64 (* OSGetTime)(void); +extern void (*OSTicksToCalendarTime)(u64 time, OSCalendarTime *calendarTime); + +//!---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//! Mutex functions +//!---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +extern void (* OSInitMutex)(void* mutex); +extern void (* OSLockMutex)(void* mutex); +extern void (* OSUnlockMutex)(void* mutex); +extern int (* OSTryLockMutex)(void* mutex); + +//!---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//! System functions +//!---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +extern u64 (* OSGetTitleID)(void); +extern void (* OSGetArgcArgv)(int* argc, char*** argv); +extern void (* __Exit)(void); +extern void (* OSFatal)(const char* msg); +extern void (* DCFlushRange)(const void *addr, u32 length); +extern void (* DCStoreRange)(const void *addr, u32 length); +extern void (* DCInvalidateRange)(const void *addr, u32 length); +extern void (* ICInvalidateRange)(const void *addr, u32 length); +extern void* (* OSEffectiveToPhysical)(const void*); +extern int (* __os_snprintf)(char* s, int n, const char * format, ...); +extern int * (* __gh_errno_ptr)(void); + +extern void (*OSScreenInit)(void); +extern void (*OSScreenShutdown)(void); +extern unsigned int (*OSScreenGetBufferSizeEx)(unsigned int bufferNum); +extern int (*OSScreenSetBufferEx)(unsigned int bufferNum, void * addr); +extern int (*OSScreenClearBufferEx)(unsigned int bufferNum, unsigned int temp); +extern int (*OSScreenFlipBuffersEx)(unsigned int bufferNum); +extern int (*OSScreenPutFontEx)(unsigned int bufferNum, unsigned int posX, unsigned int posY, const char * buffer); +extern int (*OSScreenEnableEx)(unsigned int bufferNum, int enable); + +typedef unsigned char (*exception_callback)(void * interruptedContext); +extern void (* OSSetExceptionCallback)(u8 exceptionType, exception_callback newCallback); + +extern int (*IOS_Ioctl)(int fd, unsigned int request, void *input_buffer,unsigned int input_buffer_len, void *output_buffer, unsigned int output_buffer_len); +extern int (*IOS_Open)(char *path, unsigned int mode); +extern int (*IOS_Close)(int fd); + +//!---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//! MCP functions +//!---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +extern int (* MCP_Open)(void); +extern int (* MCP_Close)(int handle); +extern int (* MCP_GetOwnTitleInfo)(int handle, void * data); + +#ifdef __cplusplus +} +#endif + +#endif // __OS_FUNCTIONS_H_ diff --git a/src/dynamic_libs/os_types.h b/src/dynamic_libs/os_types.h new file mode 100644 index 0000000..aaa18fe --- /dev/null +++ b/src/dynamic_libs/os_types.h @@ -0,0 +1,27 @@ +#ifndef _OS_TYPES_H_ +#define _OS_TYPES_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +typedef struct _OSCalendarTime { + int sec; + int min; + int hour; + int mday; + int mon; + int year; + int wday; + int yday; + int msec; + int usec; +} OSCalendarTime; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/dynamic_libs/socket_functions.c b/src/dynamic_libs/socket_functions.c new file mode 100644 index 0000000..de2c31f --- /dev/null +++ b/src/dynamic_libs/socket_functions.c @@ -0,0 +1,81 @@ +/**************************************************************************** + * Copyright (C) 2015 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include "os_functions.h" +#include "socket_functions.h" + +u32 hostIpAddress = 0; + +unsigned int nsysnet_handle __attribute__((section(".data"))) = 0; + +EXPORT_DECL(void, socket_lib_init, void); +EXPORT_DECL(int, socket, int domain, int type, int protocol); +EXPORT_DECL(int, socketclose, int s); +EXPORT_DECL(int, connect, int s, void *addr, int addrlen); +EXPORT_DECL(int, bind, s32 s,struct sockaddr *name,s32 namelen); +EXPORT_DECL(int, listen, s32 s,u32 backlog); +EXPORT_DECL(int, accept, s32 s,struct sockaddr *addr,s32 *addrlen); +EXPORT_DECL(int, send, int s, const void *buffer, int size, int flags); +EXPORT_DECL(int, recv, int s, void *buffer, int size, int flags); +EXPORT_DECL(int, recvfrom,int sockfd, void *buf, int len, int flags,struct sockaddr *src_addr, int *addrlen); +EXPORT_DECL(int, sendto, int s, const void *buffer, int size, int flags, const struct sockaddr *dest, int dest_len); +EXPORT_DECL(int, setsockopt, int s, int level, int optname, void *optval, int optlen); +EXPORT_DECL(char *, inet_ntoa, struct in_addr in); +EXPORT_DECL(int, inet_aton, const char *cp, struct in_addr *inp); + +EXPORT_DECL(int, NSSLWrite, int connection, const void* buf, int len,int * written); +EXPORT_DECL(int, NSSLRead, int connection, const void* buf, int len,int * read); +EXPORT_DECL(int, NSSLCreateConnection, int context, const char* host, int hotlen,int options,int sock,int block); + +void InitAcquireSocket(void) +{ + OSDynLoad_Acquire("nsysnet.rpl", &nsysnet_handle); +} + +void InitSocketFunctionPointers(void) +{ + unsigned int *funcPointer = 0; + + InitAcquireSocket(); + + OS_FIND_EXPORT(nsysnet_handle, socket_lib_init); + OS_FIND_EXPORT(nsysnet_handle, socket); + OS_FIND_EXPORT(nsysnet_handle, socketclose); + OS_FIND_EXPORT(nsysnet_handle, connect); + OS_FIND_EXPORT(nsysnet_handle, bind); + OS_FIND_EXPORT(nsysnet_handle, listen); + OS_FIND_EXPORT(nsysnet_handle, accept); + OS_FIND_EXPORT(nsysnet_handle, send); + OS_FIND_EXPORT(nsysnet_handle, recv); + OS_FIND_EXPORT(nsysnet_handle, recvfrom); + OS_FIND_EXPORT(nsysnet_handle, sendto); + OS_FIND_EXPORT(nsysnet_handle, setsockopt); + OS_FIND_EXPORT(nsysnet_handle, inet_ntoa); + OS_FIND_EXPORT(nsysnet_handle, inet_aton); + + OS_FIND_EXPORT(nsysnet_handle, NSSLWrite); + OS_FIND_EXPORT(nsysnet_handle, NSSLRead); + OS_FIND_EXPORT(nsysnet_handle, NSSLCreateConnection); + + socket_lib_init(); +} diff --git a/src/dynamic_libs/socket_functions.h b/src/dynamic_libs/socket_functions.h new file mode 100644 index 0000000..1e4df1a --- /dev/null +++ b/src/dynamic_libs/socket_functions.h @@ -0,0 +1,108 @@ +/**************************************************************************** + * Copyright (C) 2015 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef __SOCKET_FUNCTIONS_H_ +#define __SOCKET_FUNCTIONS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +extern unsigned int nsysnet_handle; + +#include + +#define INADDR_ANY 0 + +#define AF_INET 2 + +#define SOCK_STREAM 1 +#define SOCK_DGRAM 2 + +#define IPPROTO_IP 0 +#define IPPROTO_TCP 6 +#define IPPROTO_UDP 17 + +#define TCP_NODELAY 0x2004 + +#define SOL_SOCKET -1 +#define SO_REUSEADDR 0x0004 +#define SO_NONBLOCK 0x1016 +#define SO_MYADDR 0x1013 +#define SO_RCVTIMEO 0x1006 + +#define SOL_SOCKET -1 +#define MSG_DONTWAIT 32 + +#define htonl(x) x +#define htons(x) x +#define ntohl(x) x +#define ntohs(x) x + + +struct in_addr { + unsigned int s_addr; +}; +struct sockaddr_in { + short sin_family; + unsigned short sin_port; + struct in_addr sin_addr; + char sin_zero[8]; +}; + +struct sockaddr +{ + unsigned short sa_family; + char sa_data[14]; +}; + + +void InitSocketFunctionPointers(void); +void InitAcquireSocket(void); + +extern void (*socket_lib_init)(void); +extern int (*socket)(int domain, int type, int protocol); +extern int (*socketclose)(int s); +extern int (*connect)(int s, void *addr, int addrlen); +extern int (*bind)(s32 s,struct sockaddr *name,s32 namelen); +extern int (*listen)(s32 s,u32 backlog); +extern int (*accept)(s32 s,struct sockaddr *addr,s32 *addrlen); +extern int (*send)(int s, const void *buffer, int size, int flags); +extern int (*recv)(int s, void *buffer, int size, int flags); +extern int (*recvfrom)(int sockfd, void *buf, int len, int flags,struct sockaddr *src_addr, int *addrlen); + +extern int (*sendto)(int s, const void *buffer, int size, int flags, const struct sockaddr *dest, int dest_len); +extern int (*setsockopt)(int s, int level, int optname, void *optval, int optlen); + +extern int (* NSSLWrite)(int connection, const void* buf, int len,int * written); +extern int (* NSSLRead)(int connection, const void* buf, int len,int * read); +extern int (* NSSLCreateConnection)(int context, const char* host, int hotlen,int options,int sock,int block); + +extern char * (*inet_ntoa)(struct in_addr in); +extern int (*inet_aton)(const char *cp, struct in_addr *inp); + +#ifdef __cplusplus +} +#endif + +#endif // __SOCKET_FUNCTIONS_H_ diff --git a/src/dynamic_libs/sys_functions.c b/src/dynamic_libs/sys_functions.c new file mode 100644 index 0000000..2cd44b8 --- /dev/null +++ b/src/dynamic_libs/sys_functions.c @@ -0,0 +1,51 @@ +/**************************************************************************** + * Copyright (C) 2015 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include "os_functions.h" + + unsigned int sysapp_handle __attribute__((section(".data"))) = 0; + +EXPORT_DECL(int, _SYSLaunchTitleByPathFromLauncher, const char* path, int len, int zero); +EXPORT_DECL(int, SYSRelaunchTitle, int argc, char** argv); +EXPORT_DECL(int, SYSLaunchMenu, void); +EXPORT_DECL(int, SYSCheckTitleExists, u64 titleId); +EXPORT_DECL(int, SYSLaunchTitle, u64 titleId); +EXPORT_DECL(int, SYSLaunchSettings, int unk); + +void InitAcquireSys(void) +{ + OSDynLoad_Acquire("sysapp.rpl", &sysapp_handle); +} + +void InitSysFunctionPointers(void) +{ + unsigned int *funcPointer = 0; + InitAcquireSys(); + + OS_FIND_EXPORT(sysapp_handle, _SYSLaunchTitleByPathFromLauncher); + OS_FIND_EXPORT(sysapp_handle, SYSRelaunchTitle); + OS_FIND_EXPORT(sysapp_handle, SYSLaunchMenu); + OS_FIND_EXPORT(sysapp_handle, SYSCheckTitleExists); + OS_FIND_EXPORT(sysapp_handle, SYSLaunchTitle); + OS_FIND_EXPORT(sysapp_handle, SYSLaunchSettings); +} diff --git a/src/dynamic_libs/sys_functions.h b/src/dynamic_libs/sys_functions.h new file mode 100644 index 0000000..64fc2c7 --- /dev/null +++ b/src/dynamic_libs/sys_functions.h @@ -0,0 +1,48 @@ +/**************************************************************************** + * Copyright (C) 2015 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef __SYS_FUNCTIONS_H_ +#define __SYS_FUNCTIONS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +extern unsigned int sysapp_handle; + +void InitSysFunctionPointers(void); +void InitAcquireSys(void); + +extern int(*_SYSLaunchTitleByPathFromLauncher)(const char* path, int len, int zero); +extern int (* SYSRelaunchTitle)(int argc, char** argv); +extern int (* SYSLaunchMenu)(void); +extern int (* SYSCheckTitleExists)(u64 titleId); +extern int (* SYSLaunchTitle)(u64 titleId); +extern int (* SYSLaunchSettings)(int unk); + + +#ifdef __cplusplus +} +#endif + +#endif // __SYS_FUNCTIONS_H_ diff --git a/src/dynamic_libs/vpad_functions.c b/src/dynamic_libs/vpad_functions.c new file mode 100644 index 0000000..201cf34 --- /dev/null +++ b/src/dynamic_libs/vpad_functions.c @@ -0,0 +1,55 @@ +/**************************************************************************** + * Copyright (C) 2015 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include "os_functions.h" +#include "vpad_functions.h" + +unsigned int vpad_handle __attribute__((section(".data"))) = 0; +unsigned int vpadbase_handle __attribute__((section(".data"))) = 0; + +EXPORT_DECL(void, VPADInit, void); +EXPORT_DECL(int, VPADRead, int chan, VPADData *buffer, u32 buffer_size, s32 *error); +EXPORT_DECL(int, VPADGetLcdMode, int padnum, int *lcdmode); +EXPORT_DECL(int, VPADSetLcdMode, int padnum, int lcdmode); +EXPORT_DECL(int, VPADBASEGetMotorOnRemainingCount, int padnum); +EXPORT_DECL(int, VPADBASESetMotorOnRemainingCount, int padnum, int counter); + +void InitAcquireVPad(void) +{ + OSDynLoad_Acquire("vpad.rpl", &vpad_handle); + OSDynLoad_Acquire("vpadbase.rpl", &vpadbase_handle); +} + +void InitVPadFunctionPointers(void) +{ + unsigned int *funcPointer = 0; + + InitAcquireVPad(); + + OS_FIND_EXPORT(vpad_handle, VPADInit); + OS_FIND_EXPORT(vpad_handle, VPADRead); + OS_FIND_EXPORT(vpad_handle, VPADGetLcdMode); + OS_FIND_EXPORT(vpad_handle, VPADSetLcdMode); + OS_FIND_EXPORT(vpadbase_handle, VPADBASEGetMotorOnRemainingCount); + OS_FIND_EXPORT(vpadbase_handle, VPADBASESetMotorOnRemainingCount); +} diff --git a/src/dynamic_libs/vpad_functions.h b/src/dynamic_libs/vpad_functions.h new file mode 100644 index 0000000..4fafda2 --- /dev/null +++ b/src/dynamic_libs/vpad_functions.h @@ -0,0 +1,114 @@ +/**************************************************************************** + * Copyright (C) 2015 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef __VPAD_FUNCTIONS_H_ +#define __VPAD_FUNCTIONS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +extern unsigned int vpad_handle; +extern unsigned int vpadbase_handle; + +#include + +#define VPAD_BUTTON_A 0x8000 +#define VPAD_BUTTON_B 0x4000 +#define VPAD_BUTTON_X 0x2000 +#define VPAD_BUTTON_Y 0x1000 +#define VPAD_BUTTON_LEFT 0x0800 +#define VPAD_BUTTON_RIGHT 0x0400 +#define VPAD_BUTTON_UP 0x0200 +#define VPAD_BUTTON_DOWN 0x0100 +#define VPAD_BUTTON_ZL 0x0080 +#define VPAD_BUTTON_ZR 0x0040 +#define VPAD_BUTTON_L 0x0020 +#define VPAD_BUTTON_R 0x0010 +#define VPAD_BUTTON_PLUS 0x0008 +#define VPAD_BUTTON_MINUS 0x0004 +#define VPAD_BUTTON_HOME 0x0002 +#define VPAD_BUTTON_SYNC 0x0001 +#define VPAD_BUTTON_STICK_R 0x00020000 +#define VPAD_BUTTON_STICK_L 0x00040000 +#define VPAD_BUTTON_TV 0x00010000 + +#define VPAD_STICK_R_EMULATION_LEFT 0x04000000 +#define VPAD_STICK_R_EMULATION_RIGHT 0x02000000 +#define VPAD_STICK_R_EMULATION_UP 0x01000000 +#define VPAD_STICK_R_EMULATION_DOWN 0x00800000 + +#define VPAD_STICK_L_EMULATION_LEFT 0x40000000 +#define VPAD_STICK_L_EMULATION_RIGHT 0x20000000 +#define VPAD_STICK_L_EMULATION_UP 0x10000000 +#define VPAD_STICK_L_EMULATION_DOWN 0x08000000 + +//! Own definitions +#define VPAD_BUTTON_TOUCH 0x00080000 +#define VPAD_MASK_EMULATED_STICKS 0x7F800000 +#define VPAD_MASK_BUTTONS ~VPAD_MASK_EMULATED_STICKS + +typedef struct +{ + f32 x,y; +} Vec2D; + +typedef struct +{ + u16 x, y; /* Touch coordinates */ + u16 touched; /* 1 = Touched, 0 = Not touched */ + u16 invalid; /* 0 = All valid, 1 = X invalid, 2 = Y invalid, 3 = Both invalid? */ +} VPADTPData; + +typedef struct +{ + u32 btns_h; /* Held buttons */ + u32 btns_d; /* Buttons that are pressed at that instant */ + u32 btns_r; /* Released buttons */ + Vec2D lstick, rstick; /* Each contains 4-byte X and Y components */ + char unknown1c[0x52 - 0x1c]; /* Contains accelerometer and gyroscope data somewhere */ + VPADTPData tpdata; /* Normal touchscreen data */ + VPADTPData tpdata1; /* Modified touchscreen data 1 */ + VPADTPData tpdata2; /* Modified touchscreen data 2 */ + char unknown6a[0xa0 - 0x6a]; + uint8_t volume; + uint8_t battery; /* 0 to 6 */ + uint8_t unk_volume; /* One less than volume */ + char unknowna4[0xac - 0xa4]; +} VPADData; + +void InitVPadFunctionPointers(void); +void InitAcquireVPad(void); + +extern int (* VPADRead)(int chan, VPADData *buffer, u32 buffer_size, s32 *error); +extern int (* VPADGetLcdMode)(int padnum, int *lcdmode); +extern int (* VPADSetLcdMode)(int padnum, int lcdmode); +extern void (* VPADInit)(void); +extern int (* VPADBASEGetMotorOnRemainingCount)(int lcdmode); +extern int (* VPADBASESetMotorOnRemainingCount)(int lcdmode,int counter); + +#ifdef __cplusplus +} +#endif + +#endif // __VPAD_FUNCTIONS_H_ diff --git a/src/entry.c b/src/entry.c new file mode 100644 index 0000000..759cee0 --- /dev/null +++ b/src/entry.c @@ -0,0 +1,14 @@ +#include +#include "dynamic_libs/os_functions.h" +#include "dynamic_libs/sys_functions.h" +#include "common/common.h" +#include "utils/utils.h" +#include "main.h" + +int __entry_menu(int argc, char **argv) +{ + //! ******************************************************************* + //! * Jump to our application * + //! ******************************************************************* + return Menu_Main(); +} diff --git a/src/fs/fs_utils.c b/src/fs/fs_utils.c new file mode 100644 index 0000000..efa2e55 --- /dev/null +++ b/src/fs/fs_utils.c @@ -0,0 +1,182 @@ +#include +#include +#include +#include +#include +#include "common/fs_defs.h" +#include "dynamic_libs/fs_functions.h" + + +int MountFS(void *pClient, void *pCmd, char **mount_path) +{ + int result = -1; + + void *mountSrc = malloc(FS_MOUNT_SOURCE_SIZE); + if(!mountSrc) + return -3; + + char* mountPath = (char*) malloc(FS_MAX_MOUNTPATH_SIZE); + if(!mountPath) { + free(mountSrc); + return -4; + } + + memset(mountSrc, 0, FS_MOUNT_SOURCE_SIZE); + memset(mountPath, 0, FS_MAX_MOUNTPATH_SIZE); + + // Mount sdcard + if (FSGetMountSource(pClient, pCmd, FS_SOURCETYPE_EXTERNAL, mountSrc, -1) == 0) + { + result = FSMount(pClient, pCmd, mountSrc, mountPath, FS_MAX_MOUNTPATH_SIZE, -1); + if((result == 0) && mount_path) { + *mount_path = (char*)malloc(strlen(mountPath) + 1); + if(*mount_path) + strcpy(*mount_path, mountPath); + } + } + + free(mountPath); + free(mountSrc); + return result; +} + +int UmountFS(void *pClient, void *pCmd, const char *mountPath) +{ + int result = -1; + result = FSUnmount(pClient, pCmd, mountPath, -1); + + return result; +} + +int LoadFileToMem(const char *filepath, u8 **inbuffer, u32 *size) +{ + //! always initialze input + *inbuffer = NULL; + if(size) + *size = 0; + + int iFd = open(filepath, O_RDONLY); + if (iFd < 0) + return -1; + + u32 filesize = lseek(iFd, 0, SEEK_END); + lseek(iFd, 0, SEEK_SET); + + u8 *buffer = (u8 *) malloc(filesize); + if (buffer == NULL) + { + close(iFd); + return -2; + } + + u32 blocksize = 0x4000; + u32 done = 0; + int readBytes = 0; + + while(done < filesize) + { + if(done + blocksize > filesize) { + blocksize = filesize - done; + } + readBytes = read(iFd, buffer + done, blocksize); + if(readBytes <= 0) + break; + done += readBytes; + } + + close(iFd); + + if (done != filesize) + { + free(buffer); + return -3; + } + + *inbuffer = buffer; + + //! sign is optional input + if(size) + *size = filesize; + + return filesize; +} + +int CheckFile(const char * filepath) +{ + if(!filepath) + return 0; + + struct stat filestat; + + char dirnoslash[strlen(filepath)+2]; + snprintf(dirnoslash, sizeof(dirnoslash), "%s", filepath); + + while(dirnoslash[strlen(dirnoslash)-1] == '/') + dirnoslash[strlen(dirnoslash)-1] = '\0'; + + char * notRoot = strrchr(dirnoslash, '/'); + if(!notRoot) + { + strcat(dirnoslash, "/"); + } + + if (stat(dirnoslash, &filestat) == 0) + return 1; + + return 0; +} + +int CreateSubfolder(const char * fullpath) +{ + if(!fullpath) + return 0; + + int result = 0; + + char dirnoslash[strlen(fullpath)+1]; + strcpy(dirnoslash, fullpath); + + int pos = strlen(dirnoslash)-1; + while(dirnoslash[pos] == '/') + { + dirnoslash[pos] = '\0'; + pos--; + } + + if(CheckFile(dirnoslash)) + { + return 1; + } + else + { + char parentpath[strlen(dirnoslash)+2]; + strcpy(parentpath, dirnoslash); + char * ptr = strrchr(parentpath, '/'); + + if(!ptr) + { + //!Device root directory (must be with '/') + strcat(parentpath, "/"); + struct stat filestat; + if (stat(parentpath, &filestat) == 0) + return 1; + + return 0; + } + + ptr++; + ptr[0] = '\0'; + + result = CreateSubfolder(parentpath); + } + + if(!result) + return 0; + + if (mkdir(dirnoslash, 0777) == -1) + { + return 0; + } + + return 1; +} diff --git a/src/fs/fs_utils.h b/src/fs/fs_utils.h new file mode 100644 index 0000000..7022695 --- /dev/null +++ b/src/fs/fs_utils.h @@ -0,0 +1,23 @@ +#ifndef __FS_UTILS_H_ +#define __FS_UTILS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +int MountFS(void *pClient, void *pCmd, char **mount_path); +int UmountFS(void *pClient, void *pCmd, const char *mountPath); + +int LoadFileToMem(const char *filepath, u8 **inbuffer, u32 *size); + +//! todo: C++ class +int CreateSubfolder(const char * fullpath); +int CheckFile(const char * filepath); + +#ifdef __cplusplus +} +#endif + +#endif // __FS_UTILS_H_ diff --git a/src/fs/sd_fat_devoptab.c b/src/fs/sd_fat_devoptab.c new file mode 100644 index 0000000..f5b278b --- /dev/null +++ b/src/fs/sd_fat_devoptab.c @@ -0,0 +1,1019 @@ +/*************************************************************************** + * Copyright (C) 2015 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include "dynamic_libs/fs_functions.h" +#include "dynamic_libs/os_functions.h" +#include "fs_utils.h" + +#define FS_ALIGNMENT 0x40 +#define FS_ALIGN(x) (((x) + FS_ALIGNMENT - 1) & ~(FS_ALIGNMENT - 1)) + +typedef struct _sd_fat_private_t { + char *mount_path; + void *pClient; + void *pCmd; + void *pMutex; +} sd_fat_private_t; + +typedef struct _sd_fat_file_state_t { + sd_fat_private_t *dev; + int fd; /* File descriptor */ + int flags; /* Opening flags */ + bool read; /* True if allowed to read from file */ + bool write; /* True if allowed to write to file */ + bool append; /* True if allowed to append to file */ + u64 pos; /* Current position within the file (in bytes) */ + u64 len; /* Total length of the file (in bytes) */ + struct _sd_fat_file_state_t *prevOpenFile; /* The previous entry in a double-linked FILO list of open files */ + struct _sd_fat_file_state_t *nextOpenFile; /* The next entry in a double-linked FILO list of open files */ +} sd_fat_file_state_t; + +typedef struct _sd_fat_dir_entry_t { + sd_fat_private_t *dev; + int dirHandle; +} sd_fat_dir_entry_t; + +static sd_fat_private_t *sd_fat_get_device_data(const char *path) +{ + const devoptab_t *devoptab = NULL; + char name[128] = {0}; + int i; + + // Get the device name from the path + strncpy(name, path, 127); + strtok(name, ":/"); + + // Search the devoptab table for the specified device name + // NOTE: We do this manually due to a 'bug' in GetDeviceOpTab + // which ignores names with suffixes and causes names + // like "ntfs" and "ntfs1" to be seen as equals + for (i = 3; i < STD_MAX; i++) { + devoptab = devoptab_list[i]; + if (devoptab && devoptab->name) { + if (strcmp(name, devoptab->name) == 0) { + return (sd_fat_private_t *)devoptab->deviceData; + } + } + } + + return NULL; +} + +static char *sd_fat_real_path (const char *path, sd_fat_private_t *dev) +{ + // Sanity check + if (!path) + return NULL; + + // Move the path pointer to the start of the actual path + if (strchr(path, ':') != NULL) { + path = strchr(path, ':') + 1; + } + + int mount_len = strlen(dev->mount_path); + + char *new_name = (char*)malloc(mount_len + strlen(path) + 1); + if(new_name) { + strcpy(new_name, dev->mount_path); + strcpy(new_name + mount_len, path); + return new_name; + } + return new_name; +} + +static int sd_fat_open_r (struct _reent *r, void *fileStruct, const char *path, int flags, int mode) +{ + sd_fat_private_t *dev = sd_fat_get_device_data(path); + if(!dev) { + r->_errno = ENODEV; + return -1; + } + + sd_fat_file_state_t *file = (sd_fat_file_state_t *)fileStruct; + + file->dev = dev; + // Determine which mode the file is opened for + file->flags = flags; + + const char *mode_str; + + if ((flags & 0x03) == O_RDONLY) { + file->read = true; + file->write = false; + file->append = false; + mode_str = "r"; + } else if ((flags & 0x03) == O_WRONLY) { + file->read = false; + file->write = true; + file->append = (flags & O_APPEND); + mode_str = file->append ? "a" : "w"; + } else if ((flags & 0x03) == O_RDWR) { + file->read = true; + file->write = true; + file->append = (flags & O_APPEND); + mode_str = file->append ? "a+" : "r+"; + } else { + r->_errno = EACCES; + return -1; + } + + int fd = -1; + + OSLockMutex(dev->pMutex); + + char *real_path = sd_fat_real_path(path, dev); + if(!path) { + r->_errno = ENOMEM; + OSUnlockMutex(dev->pMutex); + return -1; + } + + int result = FSOpenFile(dev->pClient, dev->pCmd, real_path, mode_str, &fd, -1); + + free(real_path); + + if(result == 0) + { + FSStat stats; + result = FSGetStatFile(dev->pClient, dev->pCmd, fd, &stats, -1); + if(result != 0) { + FSCloseFile(dev->pClient, dev->pCmd, fd, -1); + r->_errno = result; + OSUnlockMutex(dev->pMutex); + return -1; + } + file->fd = fd; + file->pos = 0; + file->len = stats.size; + OSUnlockMutex(dev->pMutex); + return (int)file; + } + + r->_errno = result; + OSUnlockMutex(dev->pMutex); + return -1; +} + + +static int sd_fat_close_r (struct _reent *r, int fd) +{ + sd_fat_file_state_t *file = (sd_fat_file_state_t *)fd; + if(!file->dev) { + r->_errno = ENODEV; + return -1; + } + + OSLockMutex(file->dev->pMutex); + + int result = FSCloseFile(file->dev->pClient, file->dev->pCmd, file->fd, -1); + + OSUnlockMutex(file->dev->pMutex); + + if(result < 0) + { + r->_errno = result; + return -1; + } + return 0; +} + +static off_t sd_fat_seek_r (struct _reent *r, int fd, off_t pos, int dir) +{ + sd_fat_file_state_t *file = (sd_fat_file_state_t *)fd; + if(!file->dev) { + r->_errno = ENODEV; + return 0; + } + + OSLockMutex(file->dev->pMutex); + + switch(dir) + { + case SEEK_SET: + file->pos = pos; + break; + case SEEK_CUR: + file->pos += pos; + break; + case SEEK_END: + file->pos = file->len + pos; + break; + default: + r->_errno = EINVAL; + return -1; + } + + int result = FSSetPosFile(file->dev->pClient, file->dev->pCmd, file->fd, file->pos, -1); + + OSUnlockMutex(file->dev->pMutex); + + if(result == 0) + { + return file->pos; + } + + return result; +} + +static ssize_t sd_fat_write_r (struct _reent *r, int fd, const char *ptr, size_t len) +{ + sd_fat_file_state_t *file = (sd_fat_file_state_t *)fd; + if(!file->dev) { + r->_errno = ENODEV; + return 0; + } + + if(!file->write) + { + r->_errno = EACCES; + return 0; + } + + OSLockMutex(file->dev->pMutex); + + size_t len_aligned = FS_ALIGN(len); + if(len_aligned > 0x4000) + len_aligned = 0x4000; + + unsigned char *tmpBuf = (unsigned char *)memalign(FS_ALIGNMENT, len_aligned); + if(!tmpBuf) { + r->_errno = ENOMEM; + OSUnlockMutex(file->dev->pMutex); + return 0; + } + + size_t done = 0; + + while(done < len) + { + size_t write_size = (len_aligned < (len - done)) ? len_aligned : (len - done); + memcpy(tmpBuf, ptr + done, write_size); + + int result = FSWriteFile(file->dev->pClient, file->dev->pCmd, tmpBuf, 0x01, write_size, file->fd, 0, -1); + if(result < 0) + { + r->_errno = result; + break; + } + else if(result == 0) + { + if(write_size > 0) + done = 0; + break; + } + else + { + done += result; + file->pos += result; + } + } + + free(tmpBuf); + OSUnlockMutex(file->dev->pMutex); + return done; +} + +static ssize_t sd_fat_read_r (struct _reent *r, int fd, char *ptr, size_t len) +{ + sd_fat_file_state_t *file = (sd_fat_file_state_t *)fd; + if(!file->dev) { + r->_errno = ENODEV; + return 0; + } + + if(!file->read) + { + r->_errno = EACCES; + return 0; + } + + OSLockMutex(file->dev->pMutex); + + size_t len_aligned = FS_ALIGN(len); + if(len_aligned > 0x4000) + len_aligned = 0x4000; + + unsigned char *tmpBuf = (unsigned char *)memalign(FS_ALIGNMENT, len_aligned); + if(!tmpBuf) { + r->_errno = ENOMEM; + OSUnlockMutex(file->dev->pMutex); + return 0; + } + + size_t done = 0; + + while(done < len) + { + size_t read_size = (len_aligned < (len - done)) ? len_aligned : (len - done); + + int result = FSReadFile(file->dev->pClient, file->dev->pCmd, tmpBuf, 0x01, read_size, file->fd, 0, -1); + if(result < 0) + { + r->_errno = result; + done = 0; + break; + } + else if(result == 0) + { + //! TODO: error on read_size > 0 + break; + } + else + { + memcpy(ptr + done, tmpBuf, read_size); + done += result; + file->pos += result; + } + } + + free(tmpBuf); + OSUnlockMutex(file->dev->pMutex); + return done; +} + + +static int sd_fat_fstat_r (struct _reent *r, int fd, struct stat *st) +{ + sd_fat_file_state_t *file = (sd_fat_file_state_t *)fd; + if(!file->dev) { + r->_errno = ENODEV; + return -1; + } + + OSLockMutex(file->dev->pMutex); + + // Zero out the stat buffer + memset(st, 0, sizeof(struct stat)); + + FSStat stats; + int result = FSGetStatFile(file->dev->pClient, file->dev->pCmd, file->fd, &stats, -1); + if(result != 0) { + r->_errno = result; + OSUnlockMutex(file->dev->pMutex); + return -1; + } + + st->st_mode = S_IFREG; + st->st_size = stats.size; + st->st_blocks = (stats.size + 511) >> 9; + st->st_nlink = 1; + + // Fill in the generic entry stats + st->st_dev = stats.ent_id; + st->st_uid = stats.owner_id; + st->st_gid = stats.group_id; + st->st_ino = stats.ent_id; + st->st_atime = stats.mtime; + st->st_ctime = stats.ctime; + st->st_mtime = stats.mtime; + OSUnlockMutex(file->dev->pMutex); + return 0; +} + +static int sd_fat_ftruncate_r (struct _reent *r, int fd, off_t len) +{ + sd_fat_file_state_t *file = (sd_fat_file_state_t *)fd; + if(!file->dev) { + r->_errno = ENODEV; + return -1; + } + + OSLockMutex(file->dev->pMutex); + + int result = FSTruncateFile(file->dev->pClient, file->dev->pCmd, file->fd, -1); + + OSUnlockMutex(file->dev->pMutex); + + if(result < 0) { + r->_errno = result; + return -1; + } + + return 0; +} + +static int sd_fat_fsync_r (struct _reent *r, int fd) +{ + sd_fat_file_state_t *file = (sd_fat_file_state_t *)fd; + if(!file->dev) { + r->_errno = ENODEV; + return -1; + } + + OSLockMutex(file->dev->pMutex); + + int result = FSFlushFile(file->dev->pClient, file->dev->pCmd, file->fd, -1); + + OSUnlockMutex(file->dev->pMutex); + + if(result < 0) { + r->_errno = result; + return -1; + } + + return 0; +} + +static int sd_fat_stat_r (struct _reent *r, const char *path, struct stat *st) +{ + sd_fat_private_t *dev = sd_fat_get_device_data(path); + if(!dev) { + r->_errno = ENODEV; + return -1; + } + + OSLockMutex(dev->pMutex); + + // Zero out the stat buffer + memset(st, 0, sizeof(struct stat)); + + char *real_path = sd_fat_real_path(path, dev); + if(!real_path) { + r->_errno = ENOMEM; + OSUnlockMutex(dev->pMutex); + return -1; + } + + FSStat stats; + + int result = FSGetStat(dev->pClient, dev->pCmd, real_path, &stats, -1); + + free(real_path); + + if(result < 0) { + r->_errno = result; + OSUnlockMutex(dev->pMutex); + return -1; + } + + // mark root also as directory + st->st_mode = ((stats.flag & 0x80000000) || (strlen(dev->mount_path) + 1 == strlen(real_path)))? S_IFDIR : S_IFREG; + st->st_nlink = 1; + st->st_size = stats.size; + st->st_blocks = (stats.size + 511) >> 9; + // Fill in the generic entry stats + st->st_dev = stats.ent_id; + st->st_uid = stats.owner_id; + st->st_gid = stats.group_id; + st->st_ino = stats.ent_id; + st->st_atime = stats.mtime; + st->st_ctime = stats.ctime; + st->st_mtime = stats.mtime; + + OSUnlockMutex(dev->pMutex); + + return 0; +} + +static int sd_fat_link_r (struct _reent *r, const char *existing, const char *newLink) +{ + r->_errno = ENOTSUP; + return -1; +} + +static int sd_fat_unlink_r (struct _reent *r, const char *name) +{ + sd_fat_private_t *dev = sd_fat_get_device_data(name); + if(!dev) { + r->_errno = ENODEV; + return -1; + } + + OSLockMutex(dev->pMutex); + + char *real_path = sd_fat_real_path(name, dev); + if(!real_path) { + r->_errno = ENOMEM; + OSUnlockMutex(dev->pMutex); + return -1; + } + + + int result = FSRemove(dev->pClient, dev->pCmd, real_path, -1); + + free(real_path); + + OSUnlockMutex(dev->pMutex); + + if(result < 0) { + r->_errno = result; + return -1; + } + + return 0; +} + +static int sd_fat_chdir_r (struct _reent *r, const char *name) +{ + sd_fat_private_t *dev = sd_fat_get_device_data(name); + if(!dev) { + r->_errno = ENODEV; + return -1; + } + + OSLockMutex(dev->pMutex); + + char *real_path = sd_fat_real_path(name, dev); + if(!real_path) { + r->_errno = ENOMEM; + OSUnlockMutex(dev->pMutex); + return -1; + } + + int result = FSChangeDir(dev->pClient, dev->pCmd, real_path, -1); + + free(real_path); + + OSUnlockMutex(dev->pMutex); + + if(result < 0) { + r->_errno = result; + return -1; + } + + return 0; +} + +static int sd_fat_rename_r (struct _reent *r, const char *oldName, const char *newName) +{ + sd_fat_private_t *dev = sd_fat_get_device_data(oldName); + if(!dev) { + r->_errno = ENODEV; + return -1; + } + + OSLockMutex(dev->pMutex); + + char *real_oldpath = sd_fat_real_path(oldName, dev); + if(!real_oldpath) { + r->_errno = ENOMEM; + OSUnlockMutex(dev->pMutex); + return -1; + } + char *real_newpath = sd_fat_real_path(newName, dev); + if(!real_newpath) { + r->_errno = ENOMEM; + free(real_oldpath); + OSUnlockMutex(dev->pMutex); + return -1; + } + + int result = FSRename(dev->pClient, dev->pCmd, real_oldpath, real_newpath, -1); + + free(real_oldpath); + free(real_newpath); + + OSUnlockMutex(dev->pMutex); + + if(result < 0) { + r->_errno = result; + return -1; + } + + return 0; + +} + +static int sd_fat_mkdir_r (struct _reent *r, const char *path, int mode) +{ + sd_fat_private_t *dev = sd_fat_get_device_data(path); + if(!dev) { + r->_errno = ENODEV; + return -1; + } + + OSLockMutex(dev->pMutex); + + char *real_path = sd_fat_real_path(path, dev); + if(!real_path) { + r->_errno = ENOMEM; + OSUnlockMutex(dev->pMutex); + return -1; + } + + int result = FSMakeDir(dev->pClient, dev->pCmd, real_path, -1); + + free(real_path); + + OSUnlockMutex(dev->pMutex); + + if(result < 0) { + r->_errno = result; + return -1; + } + + return 0; +} + +static int sd_fat_statvfs_r (struct _reent *r, const char *path, struct statvfs *buf) +{ + sd_fat_private_t *dev = sd_fat_get_device_data(path); + if(!dev) { + r->_errno = ENODEV; + return -1; + } + + OSLockMutex(dev->pMutex); + + // Zero out the stat buffer + memset(buf, 0, sizeof(struct statvfs)); + + char *real_path = sd_fat_real_path(path, dev); + if(!real_path) { + r->_errno = ENOMEM; + OSUnlockMutex(dev->pMutex); + return -1; + } + + u64 size; + + int result = FSGetFreeSpaceSize(dev->pClient, dev->pCmd, real_path, &size, -1); + + free(real_path); + + if(result < 0) { + r->_errno = result; + OSUnlockMutex(dev->pMutex); + return -1; + } + + // File system block size + buf->f_bsize = 512; + + // Fundamental file system block size + buf->f_frsize = 512; + + // Total number of blocks on file system in units of f_frsize + buf->f_blocks = size >> 9; // this is unknown + + // Free blocks available for all and for non-privileged processes + buf->f_bfree = buf->f_bavail = size >> 9; + + // Number of inodes at this point in time + buf->f_files = 0xffffffff; + + // Free inodes available for all and for non-privileged processes + buf->f_ffree = 0xffffffff; + + // File system id + buf->f_fsid = (int)dev; + + // Bit mask of f_flag values. + buf->f_flag = 0; + + // Maximum length of filenames + buf->f_namemax = 255; + + OSUnlockMutex(dev->pMutex); + + return 0; +} + +static DIR_ITER *sd_fat_diropen_r (struct _reent *r, DIR_ITER *dirState, const char *path) +{ + sd_fat_private_t *dev = sd_fat_get_device_data(path); + if(!dev) { + r->_errno = ENODEV; + return NULL; + } + + sd_fat_dir_entry_t *dirIter = (sd_fat_dir_entry_t *)dirState->dirStruct; + + OSLockMutex(dev->pMutex); + + char *real_path = sd_fat_real_path(path, dev); + if(!real_path) { + r->_errno = ENOMEM; + OSUnlockMutex(dev->pMutex); + return NULL; + } + + int dirHandle; + + int result = FSOpenDir(dev->pClient, dev->pCmd, real_path, &dirHandle, -1); + + free(real_path); + + OSUnlockMutex(dev->pMutex); + + if(result < 0) + { + r->_errno = result; + return NULL; + } + + dirIter->dev = dev; + dirIter->dirHandle = dirHandle; + + return dirState; +} + +static int sd_fat_dirclose_r (struct _reent *r, DIR_ITER *dirState) +{ + sd_fat_dir_entry_t *dirIter = (sd_fat_dir_entry_t *)dirState->dirStruct; + if(!dirIter->dev) { + r->_errno = ENODEV; + return -1; + } + + OSLockMutex(dirIter->dev->pMutex); + + int result = FSCloseDir(dirIter->dev->pClient, dirIter->dev->pCmd, dirIter->dirHandle, -1); + + OSUnlockMutex(dirIter->dev->pMutex); + + if(result < 0) + { + r->_errno = result; + return -1; + } + return 0; +} + +static int sd_fat_dirreset_r (struct _reent *r, DIR_ITER *dirState) +{ + sd_fat_dir_entry_t *dirIter = (sd_fat_dir_entry_t *)dirState->dirStruct; + if(!dirIter->dev) { + r->_errno = ENODEV; + return -1; + } + + OSLockMutex(dirIter->dev->pMutex); + + int result = FSRewindDir(dirIter->dev->pClient, dirIter->dev->pCmd, dirIter->dirHandle, -1); + + OSUnlockMutex(dirIter->dev->pMutex); + + if(result < 0) + { + r->_errno = result; + return -1; + } + return 0; +} + +static int sd_fat_dirnext_r (struct _reent *r, DIR_ITER *dirState, char *filename, struct stat *st) +{ + sd_fat_dir_entry_t *dirIter = (sd_fat_dir_entry_t *)dirState->dirStruct; + if(!dirIter->dev) { + r->_errno = ENODEV; + return -1; + } + + OSLockMutex(dirIter->dev->pMutex); + + FSDirEntry * dir_entry = malloc(sizeof(FSDirEntry)); + + int result = FSReadDir(dirIter->dev->pClient, dirIter->dev->pCmd, dirIter->dirHandle, dir_entry, -1); + if(result < 0) + { + free(dir_entry); + r->_errno = result; + OSUnlockMutex(dirIter->dev->pMutex); + return -1; + } + + // Fetch the current entry + strcpy(filename, dir_entry->name); + + if(st) + { + memset(st, 0, sizeof(struct stat)); + st->st_mode = (dir_entry->stat.flag & 0x80000000) ? S_IFDIR : S_IFREG; + st->st_nlink = 1; + st->st_size = dir_entry->stat.size; + st->st_blocks = (dir_entry->stat.size + 511) >> 9; + st->st_dev = dir_entry->stat.ent_id; + st->st_uid = dir_entry->stat.owner_id; + st->st_gid = dir_entry->stat.group_id; + st->st_ino = dir_entry->stat.ent_id; + st->st_atime = dir_entry->stat.mtime; + st->st_ctime = dir_entry->stat.ctime; + st->st_mtime = dir_entry->stat.mtime; + } + + free(dir_entry); + OSUnlockMutex(dirIter->dev->pMutex); + return 0; +} + +// NTFS device driver devoptab +static const devoptab_t devops_sd_fat = { + NULL, /* Device name */ + sizeof (sd_fat_file_state_t), + sd_fat_open_r, + sd_fat_close_r, + sd_fat_write_r, + sd_fat_read_r, + sd_fat_seek_r, + sd_fat_fstat_r, + sd_fat_stat_r, + sd_fat_link_r, + sd_fat_unlink_r, + sd_fat_chdir_r, + sd_fat_rename_r, + sd_fat_mkdir_r, + sizeof (sd_fat_dir_entry_t), + sd_fat_diropen_r, + sd_fat_dirreset_r, + sd_fat_dirnext_r, + sd_fat_dirclose_r, + sd_fat_statvfs_r, + sd_fat_ftruncate_r, + sd_fat_fsync_r, + NULL, /* sd_fat_chmod_r */ + NULL, /* sd_fat_fchmod_r */ + NULL /* Device data */ +}; + +static int sd_fat_add_device (const char *name, const char *mount_path, void *pClient, void *pCmd) +{ + devoptab_t *dev = NULL; + char *devname = NULL; + char *devpath = NULL; + int i; + + // Sanity check + if (!name) { + errno = EINVAL; + return -1; + } + + // Allocate a devoptab for this device + dev = (devoptab_t *) malloc(sizeof(devoptab_t) + strlen(name) + 1); + if (!dev) { + errno = ENOMEM; + return -1; + } + + // Use the space allocated at the end of the devoptab for storing the device name + devname = (char*)(dev + 1); + strcpy(devname, name); + + // create private data + sd_fat_private_t *priv = (sd_fat_private_t *)malloc(sizeof(sd_fat_private_t) + strlen(mount_path) + 1); + if(!priv) { + free(dev); + errno = ENOMEM; + return -1; + } + + devpath = (char*)(priv+1); + strcpy(devpath, mount_path); + + // setup private data + priv->mount_path = devpath; + priv->pClient = pClient; + priv->pCmd = pCmd; + priv->pMutex = malloc(OS_MUTEX_SIZE); + + if(!priv->pMutex) { + free(dev); + free(priv); + errno = ENOMEM; + return -1; + } + + OSInitMutex(priv->pMutex); + + // Setup the devoptab + memcpy(dev, &devops_sd_fat, sizeof(devoptab_t)); + dev->name = devname; + dev->deviceData = priv; + + // Add the device to the devoptab table (if there is a free slot) + for (i = 3; i < STD_MAX; i++) { + if (devoptab_list[i] == devoptab_list[0]) { + devoptab_list[i] = dev; + return 0; + } + } + + // failure, free all memory + free(priv); + free(dev); + + // If we reach here then there are no free slots in the devoptab table for this device + errno = EADDRNOTAVAIL; + return -1; +} + +static int sd_fat_remove_device (const char *path, void **pClient, void **pCmd, char **mountPath) +{ + const devoptab_t *devoptab = NULL; + char name[128] = {0}; + int i; + + // Get the device name from the path + strncpy(name, path, 127); + strtok(name, ":/"); + + // Find and remove the specified device from the devoptab table + // NOTE: We do this manually due to a 'bug' in RemoveDevice + // which ignores names with suffixes and causes names + // like "ntfs" and "ntfs1" to be seen as equals + for (i = 3; i < STD_MAX; i++) { + devoptab = devoptab_list[i]; + if (devoptab && devoptab->name) { + if (strcmp(name, devoptab->name) == 0) { + devoptab_list[i] = devoptab_list[0]; + + if(devoptab->deviceData) + { + sd_fat_private_t *priv = (sd_fat_private_t *)devoptab->deviceData; + *pClient = priv->pClient; + *pCmd = priv->pCmd; + *mountPath = (char*) malloc(strlen(priv->mount_path)+1); + if(*mountPath) + strcpy(*mountPath, priv->mount_path); + if(priv->pMutex) + free(priv->pMutex); + free(devoptab->deviceData); + } + + free((devoptab_t*)devoptab); + return 0; + } + } + } + + return -1; +} + +int mount_sd_fat(const char *path) +{ + int result = -1; + + // get command and client + void* pClient = malloc(FS_CLIENT_SIZE); + void* pCmd = malloc(FS_CMD_BLOCK_SIZE); + + if(!pClient || !pCmd) { + // just in case free if not 0 + if(pClient) + free(pClient); + if(pCmd) + free(pCmd); + return -2; + } + + FSInit(); + FSInitCmdBlock(pCmd); + FSAddClientEx(pClient, 0, -1); + + char *mountPath = NULL; + + if(MountFS(pClient, pCmd, &mountPath) == 0) { + result = sd_fat_add_device(path, mountPath, pClient, pCmd); + free(mountPath); + } + + return result; +} + +int unmount_sd_fat(const char *path) +{ + void *pClient = 0; + void *pCmd = 0; + char *mountPath = 0; + + int result = sd_fat_remove_device(path, &pClient, &pCmd, &mountPath); + if(result == 0) + { + UmountFS(pClient, pCmd, mountPath); + FSDelClient(pClient); + free(pClient); + free(pCmd); + free(mountPath); + //FSShutdown(); + } + return result; +} diff --git a/src/fs/sd_fat_devoptab.h b/src/fs/sd_fat_devoptab.h new file mode 100644 index 0000000..8df487a --- /dev/null +++ b/src/fs/sd_fat_devoptab.h @@ -0,0 +1,38 @@ +/*************************************************************************** + * Copyright (C) 2015 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef __SD_FAT_DEVOPTAB_H_ +#define __SD_FAT_DEVOPTAB_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +int mount_sd_fat(const char *path); +int unmount_sd_fat(const char *path); + +#ifdef __cplusplus +} +#endif + +#endif // __SD_FAT_DEVOPTAB_H_ diff --git a/src/link.ld b/src/link.ld new file mode 100644 index 0000000..fc569d1 --- /dev/null +++ b/src/link.ld @@ -0,0 +1,40 @@ +OUTPUT(ftpiiu.elf); + +/* Tell linker where our application entry is so the garbage collect can work correct */ +ENTRY(__entry_menu); + +SECTIONS { + . = 0x00802000; + .text : { + *(.text*); + } + .rodata : { + *(.rodata*); + } + .data : { + *(.data*); + + __sdata_start = .; + *(.sdata*); + __sdata_end = .; + + __sdata2_start = .; + *(.sdata2*); + __sdata2_end = .; + } + .bss : { + __bss_start = .; + *(.bss*); + *(.sbss*); + *(COMMON); + __bss_end = .; + } + __CODE_END = .; + + /DISCARD/ : { + *(*); + } +} + +/******************************************************** FS ********************************************************/ +/* coreinit.rpl difference in addresses 0xFE3C00 */ diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..a71d859 --- /dev/null +++ b/src/main.c @@ -0,0 +1,475 @@ +#include +#include +#include +#include +#include +#include +#include +#include "dynamic_libs/os_functions.h" +#include "dynamic_libs/fs_functions.h" +#include "dynamic_libs/gx2_functions.h" +#include "dynamic_libs/sys_functions.h" +#include "dynamic_libs/vpad_functions.h" +#include "dynamic_libs/socket_functions.h" +#include "fs/fs_utils.h" +#include "fs/sd_fat_devoptab.h" +#include "system/memory.h" +#include "utils/logger.h" +#include "utils/utils.h" +#include "common/common.h" +#include "menu.h" +#include "main.h" + +#define ALIGN4(x) (((x) + 3) & ~3) + +#define CHAIN_START 0x1016AD40 +#define SHUTDOWN 0x1012EE4C +#define SIMPLE_RETURN 0x101014E4 +#define SOURCE (0x120000) +#define IOS_CREATETHREAD 0x1012EABC +#define ARM_CODE_BASE 0x08135000 +#define REPLACE_SYSCALL 0x081298BC + +extern const u8 launch_image_tga[]; +extern const u32 launch_image_tga_size; + +static void uhs_exploit_init(int uhs_handle, cfw_config_t * config); +static int uhs_write32(int uhs_handle, int arm_addr, int val); + +/* YOUR ARM CODE HERE (starts at ARM_CODE_BASE) */ +#include "../ios_kernel/ios_kernel.bin.h" +#include "../ios_usb/ios_usb.bin.h" +#include "../ios_fs/ios_fs.bin.h" +#include "../ios_bsp/ios_bsp.bin.h" +#include "../ios_mcp/ios_mcp.bin.h" + + +/* ROP CHAIN STARTS HERE (0x1015BD78) */ +static const int final_chain[] = { + 0x101236f3, // 0x00 POP {R1-R7,PC} + 0x0, // 0x04 arg + 0x0812974C, // 0x08 stackptr CMP R3, #1; STREQ R1, [R12]; BX LR + 0x68, // 0x0C stacksize + 0x10101638, // 0x10 + 0x0, // 0x14 + 0x0, // 0x18 + 0x0, // 0x1C + 0x1010388C, // 0x20 CMP R3, #0; MOV R0, R4; LDMNEFD SP!, {R4,R5,PC} + 0x0, // 0x24 + 0x0, // 0x28 + 0x1012CFEC, // 0x2C MOV LR, R0; MOV R0, LR; ADD SP, SP, #8; LDMFD SP!, {PC} + 0x0, // 0x30 + 0x0, // 0x34 + IOS_CREATETHREAD, // 0x38 + 0x1, // 0x3C + 0x2, // 0x40 + 0x10123a9f, // 0x44 POP {R0,R1,R4,PC} + REPLACE_SYSCALL + 0x00, // 0x48 address: the beginning of syscall_0x1a (IOS_GetUpTime64) + 0xE92D4010, // 0x4C value: PUSH {R4,LR} + 0x0, // 0x50 + 0x10123a8b, // 0x54 POP {R3,R4,PC} + 0x1, // 0x58 R3 must be 1 for the arbitrary write + 0x0, // 0x5C + 0x1010CD18, // 0x60 MOV R12, R0; MOV R0, R12; ADD SP, SP, #8; LDMFD SP!, {PC} + 0x0, // 0x64 + 0x0, // 0x68 + 0x1012EE64, // 0x6C set_panic_behavior (arbitrary write) + 0x0, // 0x70 + 0x0, // 0x74 + 0x10123a9f, // 0x78 POP {R0,R1,R4,PC} + REPLACE_SYSCALL + 0x04, // 0x7C address: the beginning of syscall_0x1a (IOS_GetUpTime64) + 0xE1A04000, // 0x80 value: MOV R4, R0 + 0x0, // 0x84 + 0x10123a8b, // 0x88 POP {R3,R4,PC} + 0x1, // 0x8C R3 must be 1 for the arbitrary write + 0x0, // 0x90 + 0x1010CD18, // 0x94 MOV R12, R0; MOV R0, R12; ADD SP, SP, #8; LDMFD SP!, {PC} + 0x0, // 0x98 + 0x0, // 0x9C + 0x1012EE64, // 0xA0 set_panic_behavior (arbitrary write) + 0x0, // 0xA4 + 0x0, // 0xA8 + 0x10123a9f, // 0xAC POP {R0,R1,R4,PC} + REPLACE_SYSCALL + 0x08, // 0xB0 address: the beginning of syscall_0x1a (IOS_GetUpTime64) + 0xE3E00000, // 0xB4 value: MOV R0, #0xFFFFFFFF + 0x0, // 0xB8 + 0x10123a8b, // 0xBC POP {R3,R4,PC} + 0x1, // 0xC0 R3 must be 1 for the arbitrary write + 0x0, // 0xC4 + 0x1010CD18, // 0xC8 MOV R12, R0; MOV R0, R12; ADD SP, SP, #8; LDMFD SP!, {PC} + 0x0, // 0xCC + 0x0, // 0xD0 + 0x1012EE64, // 0xD4 set_panic_behavior (arbitrary write) + 0x0, // 0xD8 + 0x0, // 0xDC + 0x10123a9f, // 0xE0 POP {R0,R1,R4,PC} + REPLACE_SYSCALL + 0x0C, // 0xE4 address: the beginning of syscall_0x1a (IOS_GetUpTime64) + 0xEE030F10, // 0xE8 value: MCR P15, #0, R0, C3, C0, #0 (set dacr to R0) + 0x0, // 0xEC + 0x10123a8b, // 0xF0 POP {R3,R4,PC} + 0x1, // 0xF4 R3 must be 1 for the arbitrary write + 0x0, // 0xF8 + 0x1010CD18, // 0xFC MOV R12, R0; MOV R0, R12; ADD SP, SP, #8; LDMFD SP!, {PC} + 0x0, // 0x100 + 0x0, // 0x104 + 0x1012EE64, // 0x108 set_panic_behavior (arbitrary write) + 0x0, // 0x10C + 0x0, // 0x110 + 0x10123a9f, // 0x114 POP {R0,R1,R4,PC} + REPLACE_SYSCALL + 0x10, // 0x118 address: the beginning of syscall_0x1a (IOS_GetUpTime64) + 0xE1A00004, // 0x11C value: MOV R0, R4 + 0x0, // 0x120 + 0x10123a8b, // 0x124 POP {R3,R4,PC} + 0x1, // 0x128 R3 must be 1 for the arbitrary write + 0x0, // 0x12C + 0x1010CD18, // 0x130 MOV R12, R0; MOV R0, R12; ADD SP, SP, #8; LDMFD SP!, {PC} + 0x0, // 0x134 + 0x0, // 0x138 + 0x1012EE64, // 0x13C set_panic_behavior (arbitrary write) + 0x0, // 0x140 + 0x0, // 0x144 + 0x10123a9f, // 0x148 POP {R0,R1,R4,PC} + REPLACE_SYSCALL + 0x14, // 0x14C address: the beginning of syscall_0x1a (IOS_GetUpTime64) + 0xE12FFF33, // 0x150 value: BLX R3 KERNEL_MEMCPY + 0x0, // 0x154 + 0x10123a8b, // 0x158 POP {R3,R4,PC} + 0x1, // 0x15C R3 must be 1 for the arbitrary write + 0x0, // 0x160 + 0x1010CD18, // 0x164 MOV R12, R0; MOV R0, R12; ADD SP, SP, #8; LDMFD SP!, {PC} + 0x0, // 0x168 + 0x0, // 0x16C + 0x1012EE64, // 0x170 set_panic_behavior (arbitrary write) + 0x0, // 0x174 + 0x0, // 0x178 + 0x10123a9f, // 0x148 POP {R0,R1,R4,PC} + REPLACE_SYSCALL + 0x18, // 0x14C address: the beginning of syscall_0x1a (IOS_GetUpTime64) + 0x00000000, // 0x150 value: NOP + 0x0, // 0x154 + 0x10123a8b, // 0x158 POP {R3,R4,PC} + 0x1, // 0x15C R3 must be 1 for the arbitrary write + 0x0, // 0x160 + 0x1010CD18, // 0x164 MOV R12, R0; MOV R0, R12; ADD SP, SP, #8; LDMFD SP!, {PC} + 0x0, // 0x168 + 0x0, // 0x16C + 0x1012EE64, // 0x170 set_panic_behavior (arbitrary write) + 0x0, // 0x174 + 0x0, // 0x178 + 0x10123a9f, // 0x148 POP {R0,R1,R4,PC} + REPLACE_SYSCALL + 0x1C, // 0x14C address: the beginning of syscall_0x1a (IOS_GetUpTime64) + 0xEE17FF7A, // 0x150 value: clean_loop: MRC p15, 0, r15, c7, c10, 3 + 0x0, // 0x154 + 0x10123a8b, // 0x158 POP {R3,R4,PC} + 0x1, // 0x15C R3 must be 1 for the arbitrary write + 0x0, // 0x160 + 0x1010CD18, // 0x164 MOV R12, R0; MOV R0, R12; ADD SP, SP, #8; LDMFD SP!, {PC} + 0x0, // 0x168 + 0x0, // 0x16C + 0x1012EE64, // 0x170 set_panic_behavior (arbitrary write) + 0x0, // 0x174 + 0x0, // 0x178 + 0x10123a9f, // 0x148 POP {R0,R1,R4,PC} + REPLACE_SYSCALL + 0x20, // 0x14C address: the beginning of syscall_0x1a (IOS_GetUpTime64) + 0x1AFFFFFD, // 0x150 value: BNE clean_loop + 0x0, // 0x154 + 0x10123a8b, // 0x158 POP {R3,R4,PC} + 0x1, // 0x15C R3 must be 1 for the arbitrary write + 0x0, // 0x160 + 0x1010CD18, // 0x164 MOV R12, R0; MOV R0, R12; ADD SP, SP, #8; LDMFD SP!, {PC} + 0x0, // 0x168 + 0x0, // 0x16C + 0x1012EE64, // 0x170 set_panic_behavior (arbitrary write) + 0x0, // 0x174 + 0x0, // 0x178 + 0x10123a9f, // 0x148 POP {R0,R1,R4,PC} + REPLACE_SYSCALL + 0x24, // 0x14C address: the beginning of syscall_0x1a (IOS_GetUpTime64) + 0xEE070F9A, // 0x150 value: MCR p15, 0, R0, c7, c10, 4 + 0x0, // 0x154 + 0x10123a8b, // 0x158 POP {R3,R4,PC} + 0x1, // 0x15C R3 must be 1 for the arbitrary write + 0x0, // 0x160 + 0x1010CD18, // 0x164 MOV R12, R0; MOV R0, R12; ADD SP, SP, #8; LDMFD SP!, {PC} + 0x0, // 0x168 + 0x0, // 0x16C + 0x1012EE64, // 0x170 set_panic_behavior (arbitrary write) + 0x0, // 0x174 + 0x0, // 0x178 + 0x10123a9f, // 0x17C POP {R0,R1,R4,PC} + REPLACE_SYSCALL + 0x28, // 0x180 address: the beginning of syscall_0x1a (IOS_GetUpTime64) + 0xE1A03004, // 0x184 value: MOV R3, R4 + 0x0, // 0x188 + 0x10123a8b, // 0x18C POP {R3,R4,PC} + 0x1, // 0x190 R3 must be 1 for the arbitrary write + 0x0, // 0x194 + 0x1010CD18, // 0x198 MOV R12, R0; MOV R0, R12; ADD SP, SP, #8; LDMFD SP!, {PC} + 0x0, // 0x19C + 0x0, // 0x1A0 + 0x1012EE64, // 0x1A4 set_panic_behavior (arbitrary write) + 0x0, // 0x1A8 + 0x0, // 0x1AC + 0x10123a9f, // 0x17C POP {R0,R1,R4,PC} + REPLACE_SYSCALL + 0x2C, // 0x180 address: the beginning of syscall_0x1a (IOS_GetUpTime64) + 0xE8BD4010, // 0x184 value: POP {R4,LR} + 0x0, // 0x188 + 0x10123a8b, // 0x18C POP {R3,R4,PC} + 0x1, // 0x190 R3 must be 1 for the arbitrary write + 0x0, // 0x194 + 0x1010CD18, // 0x198 MOV R12, R0; MOV R0, R12; ADD SP, SP, #8; LDMFD SP!, {PC} + 0x0, // 0x19C + 0x0, // 0x1A0 + 0x1012EE64, // 0x1A4 set_panic_behavior (arbitrary write) + 0x0, // 0x1A8 + 0x0, // 0x1AC + 0x10123a9f, // 0x1B0 POP {R0,R1,R4,PC} + REPLACE_SYSCALL + 0x30, // 0x1B4 address: the beginning of syscall_0x1a (IOS_GetUpTime64) + 0xE12FFF13, // 0x1B8 value: BX R3 our code :-) + 0x0, // 0x1BC + 0x10123a8b, // 0x1C0 POP {R3,R4,PC} + 0x1, // 0x1C4 R3 must be 1 for the arbitrary write + 0x0, // 0x1C8 + 0x1010CD18, // 0x1CC MOV R12, R0; MOV R0, R12; ADD SP, SP, #8; LDMFD SP!, {PC} + 0x0, // 0x1D0 + 0x0, // 0x1D4 + 0x1012EE64, // 0x1D8 set_panic_behavior (arbitrary write) + 0x0, // 0x1DC + 0x0, // 0x1E0 + 0x10123a9f, // 0x1E4 POP {R0,R1,R4,PC} + REPLACE_SYSCALL, // 0x1DC start of syscall IOS_GetUpTime64 + 0x4001, // 0x1E0 on > 0x4000 it flushes all data caches + 0x0, // 0x1E0 + 0x1012ED4C, // 0x1E4 IOS_FlushDCache(void *ptr, unsigned int len) + 0x0, // 0x1DC + 0x0, // 0x1E0 + 0x10123a9f, // 0x1E4 POP {R0,R1,R4,PC} + ARM_CODE_BASE, // 0x1E8 our code destination address + 0x0, // 0x1EC + 0x0, // 0x1F0 + 0x101063db, // 0x1F4 POP {R1,R2,R5,PC} + 0x0, // 0x1F8 + sizeof(ios_kernel_bin), // 0x1FC our code size + 0x0, // 0x200 + 0x10123983, // 0x204 POP {R1,R3,R4,R6,PC} + 0x00140000, // 0x208 our code source location + 0x08131D04, // 0x20C KERNEL_MEMCPY address + 0x0, // 0x210 + 0x0, // 0x214 + 0x1012EBB4, // 0x218 IOS_GetUpTime64 (privileged stack pivot) + 0x0, + 0x0, + 0x101312D0, +}; + +static const int second_chain[] = { + 0x10123a9f, // 0x00 POP {R0,R1,R4,PC} + CHAIN_START + 0x14 + 0x4 + 0x20 - 0xF000, // 0x04 destination + 0x0, // 0x08 + 0x0, // 0x0C + 0x101063db, // 0x10 POP {R1,R2,R5,PC} + 0x00130000, // 0x14 source + sizeof(final_chain), // 0x18 length + 0x0, // 0x1C + 0x10106D4C, // 0x20 BL MEMCPY; MOV R0, #0; LDMFD SP!, {R4,R5,PC} + 0x0, // 0x24 + 0x0, // 0x28 + 0x101236f3, // 0x2C POP {R1-R7,PC} + 0x0, // 0x30 arg + 0x101001DC, // 0x34 stackptr + 0x68, // 0x38 stacksize + 0x10101634, // 0x3C proc: ADD SP, SP, #8; LDMFD SP!, {R4,R5,PC} + 0x0, // 0x40 + 0x0, // 0x44 + 0x0, // 0x48 + 0x1010388C, // 0x4C CMP R3, #0; MOV R0, R4; LDMNEFD SP!, {R4,R5,PC} + 0x0, // 0x50 + 0x0, // 0x54 + 0x1012CFEC, // 0x58 MOV LR, R0; MOV R0, LR; ADD SP, SP, #8; LDMFD SP!, {PC} + 0x0, // 0x5C + 0x0, // 0x60 + IOS_CREATETHREAD, // 0x64 + 0x1, // 0x68 priority + 0x2, // 0x6C flags + 0x0, // 0x70 + 0x0, // 0x74 + 0x101063db, // 0x78 POP {R1,R2,R5,PC} + 0x0, // 0x7C + -(0x240 + 0x18 + 0xF000), // 0x80 stack offset + 0x0, // 0x84 + 0x101141C0, // 0x88 MOV R0, R9; ADD SP, SP, #0xC; LDMFD SP!, {R4-R11,PC} + 0x0, + 0x0, + 0x0, + 0x00110000 - 0x44, // 0x8C + 0x00110010, // 0x90 + 0x0, // 0x94 + 0x0, // 0x98 + 0x0, // 0x9C + 0x0, // 0xA0 + 0x0, // 0xA4 + 0x4, // 0xA8 R11 must equal 4 in order to pivot the stack + 0x101088F4, // STR R0, [R4,#0x44]; MOVEQ R0, R5; STRNE R3, [R5]; LDMFD SP!, {R4,R5,PC} + 0x0, + 0x0, + 0x1012EA68, // 0xAC stack pivot +}; + +int Menu_Main(void) +{ + //!---------INIT--------- + InitOSFunctionPointers(); + InitSysFunctionPointers(); + InitFSFunctionPointers(); + InitVPadFunctionPointers(); + + VPADInit(); + int forceMenu = 0; + + { + VPADData vpad; + int vpadError = -1; + VPADRead(0, &vpad, 1, &vpadError); + + if(vpadError == 0) + { + forceMenu = (vpad.btns_d | vpad.btns_h) & VPAD_BUTTON_B; + } + } + + mount_sd_fat("sd"); + + cfw_config_t config; + default_config(&config); + read_config(&config); + + int launch = 1; + + if(forceMenu || config.directLaunch == 0) + { + launch = ShowMenu(&config); + } + + if(!launch) + { + unmount_sd_fat("sd"); + return 0; + } + + int iosuhaxFd = IOS_Open("/dev/iosuhax", 0); + if(iosuhaxFd < 0) + { + //! execute exploit + int dev_uhs_0_handle = IOS_Open("/dev/uhs/0", 0); + if(dev_uhs_0_handle < 0) + { + unmount_sd_fat("sd"); + return 0; + } + + uhs_exploit_init(dev_uhs_0_handle, &config); + uhs_write32(dev_uhs_0_handle, CHAIN_START + 0x14, CHAIN_START + 0x14 + 0x4 + 0x20); + uhs_write32(dev_uhs_0_handle, CHAIN_START + 0x10, 0x1011814C); + uhs_write32(dev_uhs_0_handle, CHAIN_START + 0xC, SOURCE); + + uhs_write32(dev_uhs_0_handle, CHAIN_START, 0x1012392b); // pop {R4-R6,PC} + + IOS_Close(dev_uhs_0_handle); + } + else + { + //! do not run patches again as that will most likely crash + //! because the wupserver and the iosuhax dev node are still running + //! just relaunch IOS with new configuration + IOS_Close(iosuhaxFd); + } + + unmount_sd_fat("sd"); + OSForceFullRelaunch(); + SYSLaunchMenu(); + return EXIT_RELAUNCH_ON_LOAD; +} + +//!------Variables used in exploit------ +static int *pretend_root_hub = (int*)0xF5003ABC; +static int *ayylmao = (int*)0xF4500000; +//!------------------------------------- + +typedef struct +{ + u32 size; + u8 data[0]; +} payload_info_t; + +static void uhs_exploit_init(int dev_uhs_0_handle, cfw_config_t * config) +{ + ayylmao[5] = 1; + ayylmao[8] = 0x500000; + + memcpy((char*)(0xF4120000), second_chain, sizeof(second_chain)); + memcpy((char*)(0xF4130000), final_chain, sizeof(final_chain)); + memcpy((char*)(0xF4140000), ios_kernel_bin, sizeof(ios_kernel_bin)); + + payload_info_t *payloads = (payload_info_t*)0xF4148000; + + payloads->size = sizeof(cfw_config_t); + memcpy(payloads->data, config, payloads->size); + payloads = (payload_info_t*)( ((char*)payloads) + ALIGN4(sizeof(payload_info_t) + payloads->size) ); + + payloads->size = sizeof(ios_usb_bin); + memcpy(payloads->data, ios_usb_bin, payloads->size); + payloads = (payload_info_t*)( ((char*)payloads) + ALIGN4(sizeof(payload_info_t) + payloads->size) ); + + if(config->redNAND) + { + payloads->size = sizeof(ios_fs_bin); + memcpy(payloads->data, ios_fs_bin, payloads->size); + payloads = (payload_info_t*)( ((char*)payloads) + ALIGN4(sizeof(payload_info_t) + payloads->size) ); + + if(config->seeprom_red) + { + payloads->size = sizeof(ios_bsp_bin); + memcpy(payloads->data, ios_bsp_bin, payloads->size); + payloads = (payload_info_t*)( ((char*)payloads) + ALIGN4(sizeof(payload_info_t) + payloads->size) ); + } + } + + payloads->size = sizeof(ios_mcp_bin); + memcpy(payloads->data, ios_mcp_bin, payloads->size); + payloads = (payload_info_t*)( ((char*)payloads) + ALIGN4(sizeof(payload_info_t) + payloads->size) ); + + if(config->launchImage) + { + FILE *pFile = fopen(APP_PATH "/launch_image.tga", "rb"); + if(pFile) + { + fseek(pFile, 0, SEEK_END); + payloads->size = ftell(pFile); + fseek(pFile, 0, SEEK_SET); + fread(payloads->data, 1, payloads->size, pFile); + fclose(pFile); + payloads = (payload_info_t*)( ((char*)payloads) + ALIGN4(sizeof(payload_info_t) + payloads->size) ); + } + else + { + payloads->size = launch_image_tga_size; + memcpy(payloads->data, launch_image_tga, payloads->size); + payloads = (payload_info_t*)( ((char*)payloads) + ALIGN4(sizeof(payload_info_t) + payloads->size) ); + } + } + + pretend_root_hub[33] = 0x500000; + pretend_root_hub[78] = 0; + + DCStoreRange(pretend_root_hub + 33, 200); + DCStoreRange((void*)0xF4120000, sizeof(second_chain)); + DCStoreRange((void*)0xF4130000, sizeof(final_chain)); + DCStoreRange((void*)0xF4140000, sizeof(ios_kernel_bin)); + DCStoreRange((void*)0xF4148000, ((u32)payloads) - 0xF4148000); +} + +static int uhs_write32(int dev_uhs_0_handle, int arm_addr, int val) +{ + ayylmao[520] = arm_addr - 24; //! The address to be overwritten, minus 24 bytes + DCStoreRange(ayylmao, 521 * 4); //! Make CPU fetch new data (with updated adress) + OSSleepTicks(0x200000); //! Improves stability + int request_buffer[] = { -(0xBEA2C), val }; //! -(0xBEA2C) gets IOS_USB to read from the middle of MEM1 + int output_buffer[32]; + return IOS_Ioctl(dev_uhs_0_handle, 0x15, request_buffer, sizeof(request_buffer), output_buffer, sizeof(output_buffer)); +} diff --git a/src/main.h b/src/main.h new file mode 100644 index 0000000..0ee1b7b --- /dev/null +++ b/src/main.h @@ -0,0 +1,20 @@ +//Main.h +#ifndef _MAIN_H_ +#define _MAIN_H_ + +#include "common/types.h" +#include "dynamic_libs/os_functions.h" + +/* Main */ +#ifdef __cplusplus +extern "C" { +#endif + +//! C wrapper for our C++ functions +int Menu_Main(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/menu.c b/src/menu.c new file mode 100644 index 0000000..927cfd9 --- /dev/null +++ b/src/menu.c @@ -0,0 +1,240 @@ +/*************************************************************************** + * Copyright (C) 2016 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include "dynamic_libs/os_functions.h" +#include "dynamic_libs/fs_functions.h" +#include "dynamic_libs/gx2_functions.h" +#include "dynamic_libs/sys_functions.h" +#include "dynamic_libs/vpad_functions.h" +#include "dynamic_libs/socket_functions.h" +#include "cfw_config.h" + +#define MAX_CONFIG_SETTINGS 7 + +#define TEXT_SEL(x, text1, text2) ((x) ? (text1) : (text2)) + +struct { + const char *option; + const char *enabled; + const char *disabled; +} selection_options[] = +{ + { "Config view mode", "expert", "default" }, + { "Skip this menu on launch", "on", "off" }, + { "Show launch image", "on", "off" }, + { "redNAND", "on", "off" }, + { "SEEPROM redirection", "on", "off" }, + { "OTP redirection", "on", "off" }, + { "Use syshax.xml (coldboothax)", "on", "off" }, +}; + +static void console_print_pos(int x, int y, const char *format, ...) +{ + char * tmp = NULL; + + va_list va; + va_start(va, format); + if((vasprintf(&tmp, format, va) >= 0) && tmp) + { + if(strlen(tmp) > 79) + tmp[79] = 0; + + OSScreenPutFontEx(0, x, y, tmp); + OSScreenPutFontEx(1, x, y, tmp); + + } + va_end(va); + + if(tmp) + free(tmp); +} + +int ShowMenu(cfw_config_t * currentConfig) +{ + // Init screen and screen buffers + OSScreenInit(); + u32 screen_buf0_size = OSScreenGetBufferSizeEx(0); + u32 screen_buf1_size = OSScreenGetBufferSizeEx(1); + u8 * screenBuffer = (u8*) memalign(0x100, screen_buf0_size + screen_buf1_size); + OSScreenSetBufferEx(0, (void *)screenBuffer); + OSScreenSetBufferEx(1, (void *)(screenBuffer + screen_buf0_size)); + + OSScreenEnableEx(0, 1); + OSScreenEnableEx(1, 1); + + // Clear screens + OSScreenClearBufferEx(0, 0); + OSScreenClearBufferEx(1, 0); + + // Flip buffers + OSScreenFlipBuffersEx(0); + OSScreenFlipBuffersEx(1); + + VPADData vpad; + int vpadError; + int x_offset = -2; + int initScreen = 1; + int selected = 0; + int launch = 0; + cfw_config_t config; + memcpy(&config, currentConfig, sizeof(cfw_config_t)); + + int max_config_item = config.viewMode ? MAX_CONFIG_SETTINGS : 4; + + while(1) + { + //! update only at 50 Hz, thats more than enough + vpadError = -1; + VPADRead(0, &vpad, 1, &vpadError); + + if(vpadError == 0) + { + if(vpad.btns_d & VPAD_BUTTON_HOME) + { + break; + } + else if(vpad.btns_d & VPAD_BUTTON_A) + { + launch = 1; + break; + } + else if(vpad.btns_d & VPAD_BUTTON_DOWN) + { + selected++; + if(selected >= max_config_item) + selected = 0; + + initScreen = 1; + } + else if(vpad.btns_d & VPAD_BUTTON_UP) + { + selected--; + if(selected < 0) + selected = max_config_item - 1; + + initScreen = 1; + } + else if(vpad.btns_d & (VPAD_BUTTON_LEFT | VPAD_BUTTON_RIGHT)) + { + switch(selected) + { + case 0: + config.viewMode = !config.viewMode; + max_config_item = config.viewMode ? MAX_CONFIG_SETTINGS : 4; + break; + case 1: + config.directLaunch = !config.directLaunch; + break; + case 2: + config.launchImage = !config.launchImage; + break; + case 3: + config.redNAND = !config.redNAND; + break; + case 4: + config.seeprom_red = !config.seeprom_red; + break; + case 5: + config.otp_red = !config.otp_red; + break; + case 6: + config.syshaxXml = !config.syshaxXml; + break; + default: + break; + } + + if(!config.viewMode) + { + config.syshaxXml = 0; + + if(config.redNAND) + { + config.seeprom_red = 1; + config.otp_red = 1; + } + } + if(config.redNAND == 0) + { + config.seeprom_red = 0; + config.otp_red = 0; + } + + initScreen = 1; + } + } + + if(initScreen) + { + OSScreenClearBufferEx(0, 0); + OSScreenClearBufferEx(1, 0); + + console_print_pos(x_offset, 1, " -- MOCHA CFW %s by Dimok --", APP_VERSION); + + console_print_pos(x_offset, 3, "Select your options and press A to launch."); + console_print_pos(x_offset, 4, "Press HOME to exit back to HBL."); + console_print_pos(x_offset, 5, "Hold B on start to force enter this menu"); + + int y_offset = 7; + int option_count = sizeof(selection_options) / sizeof(selection_options[0]); + int idx; + int * configPtr = &config.viewMode; + + for(idx = 0; idx < option_count && idx < max_config_item; idx++) + { + console_print_pos(x_offset, y_offset++, "%s %-29s : %s%s%s %s%s%s", TEXT_SEL((selected == idx), "--->", " "), selection_options[idx].option, + TEXT_SEL(configPtr[idx], "<", " "), selection_options[idx].enabled, TEXT_SEL(configPtr[idx], ">", " "), + TEXT_SEL(configPtr[idx], " ", "<"), selection_options[idx].disabled, TEXT_SEL(configPtr[idx], " ", ">")); + } + + console_print_pos(x_offset, 16, "Credits go to everyone who contributed to Wii U scene publicly."); + console_print_pos(x_offset, 17, "Special thanks to smealum, plutoo, yellows8, naehrwert and derrek."); + + // Flip buffers + OSScreenFlipBuffersEx(0); + OSScreenFlipBuffersEx(1); + + initScreen = 0; + } + + usleep(20000); + } + + OSScreenShutdown(); + free(screenBuffer); + + if(memcmp(currentConfig, &config, sizeof(cfw_config_t)) != 0) + { + memcpy(currentConfig, &config, sizeof(cfw_config_t)); + write_config(currentConfig); + } + + return launch; +} diff --git a/src/menu.h b/src/menu.h new file mode 100644 index 0000000..9e76131 --- /dev/null +++ b/src/menu.h @@ -0,0 +1,8 @@ +#ifndef _MENU_H_ +#define _MENU_H_ + +#include "cfw_config.h" + +int ShowMenu(cfw_config_t * config); + +#endif diff --git a/src/system/exception_handler.c b/src/system/exception_handler.c new file mode 100644 index 0000000..53ef0b3 --- /dev/null +++ b/src/system/exception_handler.c @@ -0,0 +1,172 @@ +#include +#include "dynamic_libs/os_functions.h" +#include "utils/logger.h" +#include "exception_handler.h" + +#define OS_EXCEPTION_MODE_GLOBAL_ALL_CORES 4 + +#define OS_EXCEPTION_DSI 2 +#define OS_EXCEPTION_ISI 3 +#define OS_EXCEPTION_PROGRAM 6 + +/* Exceptions */ +typedef struct OSContext +{ + /* OSContext identifier */ + uint32_t tag1; + uint32_t tag2; + + /* GPRs */ + uint32_t gpr[32]; + + /* Special registers */ + uint32_t cr; + uint32_t lr; + uint32_t ctr; + uint32_t xer; + + /* Initial PC and MSR */ + uint32_t srr0; + uint32_t srr1; + + /* Only valid during DSI exception */ + uint32_t exception_specific0; + uint32_t exception_specific1; + + /* There is actually a lot more here but we don't need the rest*/ +} OSContext; + +#define CPU_STACK_TRACE_DEPTH 10 +#define __stringify(rn) #rn + +#define mfspr(_rn) \ +({ register uint32_t _rval = 0; \ + asm volatile("mfspr %0," __stringify(_rn) \ + : "=r" (_rval));\ + _rval; \ +}) + +typedef struct _framerec { + struct _framerec *up; + void *lr; +} frame_rec, *frame_rec_t; + +static const char *exception_names[] = { + "DSI", + "ISI", + "PROGRAM" +}; + +static const char exception_print_formats[18][45] = { + "Exception type %s occurred!\n", // 0 + "GPR00 %08X GPR08 %08X GPR16 %08X GPR24 %08X\n", // 1 + "GPR01 %08X GPR09 %08X GPR17 %08X GPR25 %08X\n", // 2 + "GPR02 %08X GPR10 %08X GPR18 %08X GPR26 %08X\n", // 3 + "GPR03 %08X GPR11 %08X GPR19 %08X GPR27 %08X\n", // 4 + "GPR04 %08X GPR12 %08X GPR20 %08X GPR28 %08X\n", // 5 + "GPR05 %08X GPR13 %08X GPR21 %08X GPR29 %08X\n", // 6 + "GPR06 %08X GPR14 %08X GPR22 %08X GPR30 %08X\n", // 7 + "GPR07 %08X GPR15 %08X GPR23 %08X GPR31 %08X\n", // 8 + "LR %08X SRR0 %08x SRR1 %08x\n", // 9 + "DAR %08X DSISR %08X\n", // 10 + "\nSTACK DUMP:", // 11 + " --> ", // 12 + " -->\n", // 13 + "\n", // 14 + "%p", // 15 + "\nCODE DUMP:\n", // 16 + "%p: %08X %08X %08X %08X\n", // 17 +}; + +static unsigned char exception_cb(void * c, unsigned char exception_type) { + char buf[850]; + int pos = 0; + + OSContext *context = (OSContext *) c; + /* + * This part is mostly from libogc. Thanks to the devs over there. + */ + pos += sprintf(buf + pos, exception_print_formats[0], exception_names[exception_type]); + pos += sprintf(buf + pos, exception_print_formats[1], context->gpr[0], context->gpr[8], context->gpr[16], context->gpr[24]); + pos += sprintf(buf + pos, exception_print_formats[2], context->gpr[1], context->gpr[9], context->gpr[17], context->gpr[25]); + pos += sprintf(buf + pos, exception_print_formats[3], context->gpr[2], context->gpr[10], context->gpr[18], context->gpr[26]); + pos += sprintf(buf + pos, exception_print_formats[4], context->gpr[3], context->gpr[11], context->gpr[19], context->gpr[27]); + pos += sprintf(buf + pos, exception_print_formats[5], context->gpr[4], context->gpr[12], context->gpr[20], context->gpr[28]); + pos += sprintf(buf + pos, exception_print_formats[6], context->gpr[5], context->gpr[13], context->gpr[21], context->gpr[29]); + pos += sprintf(buf + pos, exception_print_formats[7], context->gpr[6], context->gpr[14], context->gpr[22], context->gpr[30]); + pos += sprintf(buf + pos, exception_print_formats[8], context->gpr[7], context->gpr[15], context->gpr[23], context->gpr[31]); + pos += sprintf(buf + pos, exception_print_formats[9], context->lr, context->srr0, context->srr1); + + //if(exception_type == OS_EXCEPTION_DSI) { + pos += sprintf(buf + pos, exception_print_formats[10], context->exception_specific1, context->exception_specific0); // this freezes + //} + + void *pc = (void*)context->srr0; + void *lr = (void*)context->lr; + void *r1 = (void*)context->gpr[1]; + register uint32_t i = 0; + register frame_rec_t l,p = (frame_rec_t)lr; + + l = p; + p = r1; + if(!p) + asm volatile("mr %0,%%r1" : "=r"(p)); + + pos += sprintf(buf + pos, exception_print_formats[11]); + + for(i = 0; i < CPU_STACK_TRACE_DEPTH-1 && p->up; p = p->up, i++) { + if(i % 4) + pos += sprintf(buf + pos, exception_print_formats[12]); + else { + if(i > 0) + pos += sprintf(buf + pos, exception_print_formats[13]); + else + pos += sprintf(buf + pos, exception_print_formats[14]); + } + + switch(i) { + case 0: + if(pc) + pos += sprintf(buf + pos, exception_print_formats[15],pc); + break; + case 1: + if(!l) + l = (frame_rec_t)mfspr(8); + pos += sprintf(buf + pos, exception_print_formats[15],(void*)l); + break; + default: + pos += sprintf(buf + pos, exception_print_formats[15],(void*)(p->up->lr)); + break; + } + } + + //if(exception_type == OS_EXCEPTION_DSI) { + uint32_t *pAdd = (uint32_t*)context->srr0; + pos += sprintf(buf + pos, exception_print_formats[16]); + // TODO by Dimok: this was actually be 3 instead of 2 lines in libogc .... but there is just no more space anymore on the screen + for (i = 0; i < 8; i += 4) + pos += sprintf(buf + pos, exception_print_formats[17], &(pAdd[i]),pAdd[i], pAdd[i+1], pAdd[i+2], pAdd[i+3]); + //} + #if DEBUG_LOGGER == 1 + log_print(buf); + #endif + + OSFatal(buf); + return 1; +} + +static unsigned char dsi_exception_cb(void * context) { + return exception_cb(context, 0); +} +static unsigned char isi_exception_cb(void * context) { + return exception_cb(context, 1); +} +static unsigned char program_exception_cb(void * context) { + return exception_cb(context, 2); +} + +void setup_os_exceptions(void) { + OSSetExceptionCallback(OS_EXCEPTION_DSI, &dsi_exception_cb); + OSSetExceptionCallback(OS_EXCEPTION_ISI, &isi_exception_cb); + OSSetExceptionCallback(OS_EXCEPTION_PROGRAM, &program_exception_cb); +} diff --git a/src/system/exception_handler.h b/src/system/exception_handler.h new file mode 100644 index 0000000..7626f92 --- /dev/null +++ b/src/system/exception_handler.h @@ -0,0 +1,14 @@ +#ifndef __EXCEPTION_HANDLER_H_ +#define __EXCEPTION_HANDLER_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +void setup_os_exceptions(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/system/memory.c b/src/system/memory.c new file mode 100644 index 0000000..91f5392 --- /dev/null +++ b/src/system/memory.c @@ -0,0 +1,198 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 . + ****************************************************************************/ +#include +#include +#include "dynamic_libs/os_functions.h" +#include "common/common.h" +#include "memory.h" + +#define MEMORY_ARENA_1 0 +#define MEMORY_ARENA_2 1 +#define MEMORY_ARENA_3 2 +#define MEMORY_ARENA_4 3 +#define MEMORY_ARENA_5 4 +#define MEMORY_ARENA_6 5 +#define MEMORY_ARENA_7 6 +#define MEMORY_ARENA_8 7 +#define MEMORY_ARENA_FG_BUCKET 8 + +//!---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//! Memory functions +//! This is the only place where those are needed so lets keep them more or less private +//!---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +extern unsigned int * pMEMAllocFromDefaultHeapEx; +extern unsigned int * pMEMAllocFromDefaultHeap; +extern unsigned int * pMEMFreeToDefaultHeap; + +extern int (* MEMGetBaseHeapHandle)(int mem_arena); +extern unsigned int (* MEMGetAllocatableSizeForFrmHeapEx)(int heap, int align); +extern void *(* MEMAllocFromFrmHeapEx)(int heap, unsigned int size, int align); +extern void (* MEMFreeToFrmHeap)(int heap, int mode); +extern void *(* MEMAllocFromExpHeapEx)(int heap, unsigned int size, int align); +extern int (* MEMCreateExpHeapEx)(void* address, unsigned int size, unsigned short flags); +extern void *(* MEMDestroyExpHeap)(int heap); +extern void (* MEMFreeToExpHeap)(int heap, void* ptr); + +static int mem1_heap = -1; +static int bucket_heap = -1; + +void memoryInitialize(void) +{ + int mem1_heap_handle = MEMGetBaseHeapHandle(MEMORY_ARENA_1); + unsigned int mem1_allocatable_size = MEMGetAllocatableSizeForFrmHeapEx(mem1_heap_handle, 4); + void *mem1_memory = MEMAllocFromFrmHeapEx(mem1_heap_handle, mem1_allocatable_size, 4); + if(mem1_memory) + mem1_heap = MEMCreateExpHeapEx(mem1_memory, mem1_allocatable_size, 0); + + int bucket_heap_handle = MEMGetBaseHeapHandle(MEMORY_ARENA_FG_BUCKET); + unsigned int bucket_allocatable_size = MEMGetAllocatableSizeForFrmHeapEx(bucket_heap_handle, 4); + void *bucket_memory = MEMAllocFromFrmHeapEx(bucket_heap_handle, bucket_allocatable_size, 4); + if(bucket_memory) + bucket_heap = MEMCreateExpHeapEx(bucket_memory, bucket_allocatable_size, 0); +} + +void memoryRelease(void) +{ + MEMDestroyExpHeap(mem1_heap); + MEMFreeToFrmHeap(MEMGetBaseHeapHandle(MEMORY_ARENA_1), 3); + mem1_heap = -1; + + MEMDestroyExpHeap(bucket_heap); + MEMFreeToFrmHeap(MEMGetBaseHeapHandle(MEMORY_ARENA_FG_BUCKET), 3); + bucket_heap = -1; +} + +//!------------------------------------------------------------------------------------------- +//! wraps +//!------------------------------------------------------------------------------------------- +void *__wrap_malloc(size_t size) +{ + // pointer to a function resolve + return ((void * (*)(size_t))(*pMEMAllocFromDefaultHeap))(size); +} + +void *__wrap_memalign(size_t align, size_t size) +{ + if (align < 4) + align = 4; + + // pointer to a function resolve + return ((void * (*)(size_t, size_t))(*pMEMAllocFromDefaultHeapEx))(size, align); +} + +void __wrap_free(void *p) +{ + // pointer to a function resolve + if(p != 0) + ((void (*)(void *))(*pMEMFreeToDefaultHeap))(p); +} + +void *__wrap_calloc(size_t n, size_t size) +{ + void *p = __wrap_malloc(n * size); + if (p != 0) { + memset(p, 0, n * size); + } + return p; +} + +size_t __wrap_malloc_usable_size(void *p) +{ + //! TODO: this is totally wrong and needs to be addressed + return 0x7FFFFFFF; +} + +void *__wrap_realloc(void *p, size_t size) +{ + void *new_ptr = __wrap_malloc(size); + if (new_ptr != 0) + { + memcpy(new_ptr, p, __wrap_malloc_usable_size(p) < size ? __wrap_malloc_usable_size(p) : size); + __wrap_free(p); + } + return new_ptr; +} + +//!------------------------------------------------------------------------------------------- +//! reent versions +//!------------------------------------------------------------------------------------------- +void *__wrap__malloc_r(struct _reent *r, size_t size) +{ + return __wrap_malloc(size); +} + +void *__wrap__calloc_r(struct _reent *r, size_t n, size_t size) +{ + return __wrap_calloc(n, size); +} + +void *__wrap__memalign_r(struct _reent *r, size_t align, size_t size) +{ + return __wrap_memalign(align, size); +} + +void __wrap__free_r(struct _reent *r, void *p) +{ + __wrap_free(p); +} + +size_t __wrap__malloc_usable_size_r(struct _reent *r, void *p) +{ + return __wrap_malloc_usable_size(p); +} + +void *__wrap__realloc_r(struct _reent *r, void *p, size_t size) +{ + return __wrap_realloc(p, size); +} + +//!------------------------------------------------------------------------------------------- +//! some wrappers +//!------------------------------------------------------------------------------------------- +void * MEM2_alloc(unsigned int size, unsigned int align) +{ + return __wrap_memalign(align, size); +} + +void MEM2_free(void *ptr) +{ + __wrap_free(ptr); +} + +void * MEM1_alloc(unsigned int size, unsigned int align) +{ + if (align < 4) + align = 4; + return MEMAllocFromExpHeapEx(mem1_heap, size, align); +} + +void MEM1_free(void *ptr) +{ + MEMFreeToExpHeap(mem1_heap, ptr); +} + +void * MEMBucket_alloc(unsigned int size, unsigned int align) +{ + if (align < 4) + align = 4; + return MEMAllocFromExpHeapEx(bucket_heap, size, align); +} + +void MEMBucket_free(void *ptr) +{ + MEMFreeToExpHeap(bucket_heap, ptr); +} diff --git a/src/system/memory.h b/src/system/memory.h new file mode 100644 index 0000000..59764d0 --- /dev/null +++ b/src/system/memory.h @@ -0,0 +1,42 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 . + ****************************************************************************/ +#ifndef __MEMORY_H_ +#define __MEMORY_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +void memoryInitialize(void); +void memoryRelease(void); + +void * MEM2_alloc(unsigned int size, unsigned int align); +void MEM2_free(void *ptr); + +void * MEM1_alloc(unsigned int size, unsigned int align); +void MEM1_free(void *ptr); + +void * MEMBucket_alloc(unsigned int size, unsigned int align); +void MEMBucket_free(void *ptr); + +#ifdef __cplusplus +} +#endif + +#endif // __MEMORY_H_ diff --git a/src/utils/logger.c b/src/utils/logger.c new file mode 100644 index 0000000..f4795b4 --- /dev/null +++ b/src/utils/logger.c @@ -0,0 +1,89 @@ +#include +#include +#include +#include +#include +#include "common/common.h" +#include "dynamic_libs/os_functions.h" +#include "dynamic_libs/socket_functions.h" +#include "logger.h" + +#ifdef DEBUG_LOGGER +static int log_socket = -1; +static volatile int log_lock = 0; + + +void log_init(const char * ipString) +{ + log_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (log_socket < 0) + return; + + struct sockaddr_in connect_addr; + memset(&connect_addr, 0, sizeof(connect_addr)); + connect_addr.sin_family = AF_INET; + connect_addr.sin_port = 4405; + inet_aton(ipString, &connect_addr.sin_addr); + + if(connect(log_socket, (struct sockaddr*)&connect_addr, sizeof(connect_addr)) < 0) + { + socketclose(log_socket); + log_socket = -1; + } +} + +void log_deinit(void) +{ + if(log_socket >= 0) + { + socketclose(log_socket); + log_socket = -1; + } +} + +void log_print(const char *str) +{ + // socket is always 0 initially as it is in the BSS + if(log_socket < 0) { + return; + } + + while(log_lock) + usleep(1000); + log_lock = 1; + + int len = strlen(str); + int ret; + while (len > 0) { + int block = len < 1400 ? len : 1400; // take max 1400 bytes per UDP packet + ret = send(log_socket, str, block, 0); + if(ret < 0) + break; + + len -= ret; + str += ret; + } + + log_lock = 0; +} + +void log_printf(const char *format, ...) +{ + if(log_socket < 0) { + return; + } + + char * tmp = NULL; + + va_list va; + va_start(va, format); + if((vasprintf(&tmp, format, va) >= 0) && tmp) + { + log_print(tmp); + } + va_end(va); + + if(tmp) + free(tmp); +} +#endif diff --git a/src/utils/logger.h b/src/utils/logger.h new file mode 100644 index 0000000..dd7cc71 --- /dev/null +++ b/src/utils/logger.h @@ -0,0 +1,26 @@ +#ifndef __LOGGER_H_ +#define __LOGGER_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#define DEBUG_LOGGER 1 + +#ifdef DEBUG_LOGGER +void log_init(const char * ip); +void log_deinit(void); +void log_print(const char *str); +void log_printf(const char *format, ...); +#else +#define log_init(x) +#define log_deinit() +#define log_print(x) +#define log_printf(x, ...) +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/utils/utils.h b/src/utils/utils.h new file mode 100644 index 0000000..c460fa2 --- /dev/null +++ b/src/utils/utils.h @@ -0,0 +1,47 @@ +#ifndef __UTILS_H_ +#define __UTILS_H_ + +#include +#include "../common/types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define FlushBlock(addr) asm volatile("dcbf %0, %1\n" \ + "icbi %0, %1\n" \ + "sync\n" \ + "eieio\n" \ + "isync\n" \ + : \ + :"r"(0), "r"(((addr) & ~31)) \ + :"memory", "ctr", "lr", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12" \ + ); + +#define LIMIT(x, min, max) \ + ({ \ + typeof( x ) _x = x; \ + typeof( min ) _min = min; \ + typeof( max ) _max = max; \ + ( ( ( _x ) < ( _min ) ) ? ( _min ) : ( ( _x ) > ( _max ) ) ? ( _max) : ( _x ) ); \ + }) + +#define DegToRad(a) ( (a) * 0.01745329252f ) +#define RadToDeg(a) ( (a) * 57.29577951f ) + +#define ALIGN4(x) (((x) + 3) & ~3) +#define ALIGN32(x) (((x) + 31) & ~31) + +// those work only in powers of 2 +#define ROUNDDOWN(val, align) ((val) & ~(align-1)) +#define ROUNDUP(val, align) ROUNDDOWN(((val) + (align-1)), align) + +#define le16(i) ((((u16) ((i) & 0xFF)) << 8) | ((u16) (((i) & 0xFF00) >> 8))) +#define le32(i) ((((u32)le16((i) & 0xFFFF)) << 16) | ((u32)le16(((i) & 0xFFFF0000) >> 16))) +#define le64(i) ((((u64)le32((i) & 0xFFFFFFFFLL)) << 32) | ((u64)le32(((i) & 0xFFFFFFFF00000000LL) >> 32))) + +#ifdef __cplusplus +} +#endif + +#endif // __UTILS_H_