From 2acb1029970dd32bb5af0d77065dfbd6d5246f8b Mon Sep 17 00:00:00 2001 From: chaoskagami Date: Mon, 6 Jun 2016 04:00:02 -0400 Subject: [PATCH] Multiple things (again) * EmuNAND support (only one right now, but all I need is a menu/option for more) * This is both normal layout (RedNAND) and gateway layout (header at back) * Loader now has three different rel options for text, data, and ro * Screeninit. --- external/Makefile | 23 +++- external/loader/source/interp.h | 5 +- external/loader/source/loader.c | 6 +- external/loader/source/patcher.c | 23 ++-- external/loader/source/patcher.h | 7 +- external/screeninit/Makefile | 47 ++++++++ external/screeninit/linker.ld | 12 ++ external/screeninit/source/main.c | 106 +++++++++++++++++ external/screeninit/source/start.s | 10 ++ external/screeninit/source/types.h | 13 +++ external/svc/Makefile | 2 +- external/svc/emunand.s | 45 +++++++ external/svc/patches.s | 77 ++++++++++++ host/bytecode_asm.py | 4 + source/config.h | 3 + source/fatfs/ff.c | 50 ++++++++ source/fatfs/ff.h | 1 + source/fatfs/sdmmc.c | 13 +-- source/interp.c | 55 +++++---- source/main.c | 9 +- source/menu.c | 4 + source/patch/emunand.c | 181 +++++++++++++++++++++++++++++ source/patch/emunand.h | 8 ++ source/patch_format.h | 5 + source/patcher.c | 11 ++ source/screeninit.c | 26 +++++ source/screeninit.h | 7 ++ source/std/draw.c | 6 +- source/std/fs.c | 21 ++++ source/std/fs.h | 2 + source/std/types.h | 1 - 31 files changed, 716 insertions(+), 67 deletions(-) create mode 100755 external/screeninit/Makefile create mode 100755 external/screeninit/linker.ld create mode 100755 external/screeninit/source/main.c create mode 100644 external/screeninit/source/start.s create mode 100755 external/screeninit/source/types.h create mode 100644 external/svc/emunand.s create mode 100644 external/svc/patches.s create mode 100644 source/patch/emunand.c create mode 100644 source/patch/emunand.h create mode 100644 source/screeninit.c create mode 100644 source/screeninit.h diff --git a/external/Makefile b/external/Makefile index 68c70ee..f30799a 100644 --- a/external/Makefile +++ b/external/Makefile @@ -1,12 +1,15 @@ .PHONY: all -all: loader svc +all: loader svc screeninit mkdir -p ../out/corbenik/module mkdir -p ../out/corbenik/svc + mkdir -p ../out/corbenik/bits cp loader/loader.cxi ../out/corbenik/module/loader.cxi cp svc/7b.bin ../out/corbenik/svc/7b.bin + cp svc/emunand.bin ../out/corbenik/bits/emunand.bin + cp screeninit/build/screeninit.bin ../out/corbenik/bits/screeninit.bin .PHONY: clean -clean: clean_loader clean_svc +clean: clean_loader clean_svc clean_screeninit rm -rf ../out/corbenik/svc rm -rf ../out/corbenik/module @@ -14,14 +17,22 @@ clean: clean_loader clean_svc loader: make -C loader -.PHONY: clean_loader -clean_loader: - make -C loader clean - .PHONY: svc svc: make -C svc +.PHONY: screeninit +screeninit: + make -C screeninit + +.PHONY: clean_loader +clean_loader: + make -C loader clean + .PHONY: clean_svc clean_svc: make -C svc clean + +.PHONY: clean_screeninit +screeninit_clean: + make -C screeninit clean diff --git a/external/loader/source/interp.h b/external/loader/source/interp.h index 091b4c1..4399324 100644 --- a/external/loader/source/interp.h +++ b/external/loader/source/interp.h @@ -1,6 +1,9 @@ #ifndef __INTERP_H #define __INTERP_H -int execb(uint64_t tid, uint16_t ver, uint8_t *search_mem, uint32_t search_len); +int execb(uint64_t tid, uint16_t ver, + uint8_t *text_mem, uint32_t text_len, + uint8_t *data_mem, uint32_t data_size, + uint8_t *ro_mem, uint32_t ro_size); #endif diff --git a/external/loader/source/loader.c b/external/loader/source/loader.c index 1b76653..960764f 100644 --- a/external/loader/source/loader.c +++ b/external/loader/source/loader.c @@ -95,9 +95,9 @@ load_code(u64 progid, u16 progver, prog_addrs_t *shared, prog_addrs_t *original, } // Patch segments - patch_text(progid, progver, (u8 *)shared->text_addr, shared->text_size << 12, original->text_size << 12); - patch_data(progid, progver, (u8 *)shared->data_addr, shared->data_size << 12, original->data_size << 12); - patch_ro(progid, progver, (u8 *)shared->ro_addr, shared->ro_size << 12, original->ro_size << 12); + patch_exe (progid, progver, (u8 *)shared->text_addr, shared->text_size << 12, original->text_size << 12, + (u8 *)shared->data_addr, shared->data_size << 12, original->data_size << 12, + (u8 *)shared->ro_addr, shared->ro_size << 12, original->ro_size << 12); return 0; } diff --git a/external/loader/source/patcher.c b/external/loader/source/patcher.c index 598a072..4551a4a 100644 --- a/external/loader/source/patcher.c +++ b/external/loader/source/patcher.c @@ -307,28 +307,19 @@ overlay_patch(u64 progId, u8 *code, u32 size) // TODO - Implement. Needs some thought. This should allow usage of files off SD rather than RomFS. } -// This is only for the .data segment. -void -patch_data(u64 progId, u16 progver, u8 *data, u32 size, u32 orig_size) -{ -} - -// This is only for the .ro segment. -void -patch_ro(u64 progId, u16 progver, u8 *ro, u32 size, u32 orig_size) -{ -} - // This is only for the .code segment. void -patch_text(u64 progId, u16 progver, u8 *text, u32 size, u32 orig_size) +patch_exe(u64 progId, u16 progver, + u8 *text, u32 text_size, u32 orig_text, + u8* data, u32 data_size, u32 orig_data, + u8* ro, u32 ro_size, u32 orig_ro) { if (progId == 0x0004013000008002LL) - adjust_cpu_settings(progId, text, orig_size); + adjust_cpu_settings(progId, text, orig_text); - execb(progId, progver, text, orig_size); + execb(progId, progver, text, orig_text, data, orig_data, ro, orig_ro); - language_emu(progId, text, orig_size); + language_emu(progId, text, orig_text); } // Gets how many bytes .text must be extended by for patches to fit. diff --git a/external/loader/source/patcher.h b/external/loader/source/patcher.h index 44a6223..460b3d9 100644 --- a/external/loader/source/patcher.h +++ b/external/loader/source/patcher.h @@ -3,9 +3,10 @@ #include <3ds/types.h> -void patch_text(u64 progId, u16 progver, u8 *text, u32 size, u32 orig_size); -void patch_data(u64 progId, u16 progver, u8 *data, u32 size, u32 orig_size); -void patch_ro(u64 progId, u16 progver, u8 *ro, u32 size, u32 orig_size); +void patch_exe(u64 progId, u16 progver, + u8 *text, u32 text_size, u32 orig_text, + u8* data, u32 data_size, u32 orig_data, + u8* ro, u32 ro_size, u32 orig_ro); u32 get_text_extend(u64 progId, u16 progver, u32 size_orig); u32 get_ro_extend(u64 progId, u16 progver, u32 size_orig); diff --git a/external/screeninit/Makefile b/external/screeninit/Makefile new file mode 100755 index 0000000..745782b --- /dev/null +++ b/external/screeninit/Makefile @@ -0,0 +1,47 @@ +rwildcard = $(foreach d, $(wildcard $1*), $(filter $(subst *, %, $2), $d) $(call rwildcard, $d/, $2)) + +ifeq ($(strip $(DEVKITARM)),) +$(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") +endif + +include $(DEVKITARM)/3ds_rules + +CC := arm-none-eabi-gcc +AS := arm-none-eabi-as +LD := arm-none-eabi-ld +OC := arm-none-eabi-objcopy + +name := $(shell basename $(CURDIR)) + +dir_source := source +dir_build := build + +ASFLAGS := -mcpu=mpcore -mfloat-abi=hard +CFLAGS := -Wall -Wextra -MMD -MP -mthumb -mthumb-interwork $(ASFLAGS) -fno-builtin -std=c11 -Wno-main -O2 -flto -ffast-math +LDFLAGS := -nostdlib + +objects = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \ + $(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \ + $(call rwildcard, $(dir_source), *.s *.c))) + +.PHONY: all +all: $(dir_build)/$(name).bin + +.PHONY: clean +clean: + @rm -rf $(dir_build) + +$(dir_build)/$(name).bin: $(dir_build)/$(name).elf + $(OC) -S -O binary $< $@ + +$(dir_build)/$(name).elf: $(objects) + $(LINK.o) -T linker.ld $(OUTPUT_OPTION) $^ + +$(dir_build)/%.o: $(dir_source)/%.c + @mkdir -p "$(@D)" + $(COMPILE.c) $(OUTPUT_OPTION) $< + +$(dir_build)/%.o: $(dir_source)/%.s + @mkdir -p "$(@D)" + $(COMPILE.s) $(OUTPUT_OPTION) $< +include $(call rwildcard, $(dir_build), *.d) diff --git a/external/screeninit/linker.ld b/external/screeninit/linker.ld new file mode 100755 index 0000000..9ae0eaa --- /dev/null +++ b/external/screeninit/linker.ld @@ -0,0 +1,12 @@ +ENTRY(_start) +SECTIONS +{ + . = 0x24FFFC00; + .text.start : { *(.text.start) } + .text : { *(.text) } + .data : { *(.data) } + .bss : { *(.bss COMMON) } + .rodata : { *(.rodata) } + . = ALIGN(4); +} + diff --git a/external/screeninit/source/main.c b/external/screeninit/source/main.c new file mode 100755 index 0000000..318911a --- /dev/null +++ b/external/screeninit/source/main.c @@ -0,0 +1,106 @@ +#include "types.h" + +void main(void) +{ + // FIXME - We could use some serious macros here... + + u32 brightnessLevel = *(vu32 *)0x24FFFC08; + vu32 *const arm11 = (u32 *)0x1FFFFFF8; + + *(vu32 *)0x10141200 = 0x1007F; + *(vu32 *)0x10202014 = 0x00000001; + *(vu32 *)0x1020200C &= 0xFFFEFFFE; + *(vu32 *)0x10202240 = brightnessLevel; // Alteration; directly read brightness. + *(vu32 *)0x10202A40 = brightnessLevel; + *(vu32 *)0x10202244 = 0x1023E; + *(vu32 *)0x10202A44 = 0x1023E; + + // Top screen + *(vu32 *)0x10400400 = 0x000001c2; + *(vu32 *)0x10400404 = 0x000000d1; + *(vu32 *)0x10400408 = 0x000001c1; + *(vu32 *)0x1040040c = 0x000001c1; + *(vu32 *)0x10400410 = 0x00000000; + *(vu32 *)0x10400414 = 0x000000cf; + *(vu32 *)0x10400418 = 0x000000d1; + *(vu32 *)0x1040041c = 0x01c501c1; + *(vu32 *)0x10400420 = 0x00010000; + *(vu32 *)0x10400424 = 0x0000019d; + *(vu32 *)0x10400428 = 0x00000002; + *(vu32 *)0x1040042c = 0x00000192; + *(vu32 *)0x10400430 = 0x00000192; + *(vu32 *)0x10400434 = 0x00000192; + *(vu32 *)0x10400438 = 0x00000001; + *(vu32 *)0x1040043c = 0x00000002; + *(vu32 *)0x10400440 = 0x01960192; + *(vu32 *)0x10400444 = 0x00000000; + *(vu32 *)0x10400448 = 0x00000000; + *(vu32 *)0x1040045C = 0x00f00190; + *(vu32 *)0x10400460 = 0x01c100d1; + *(vu32 *)0x10400464 = 0x01920002; + *(vu32 *)0x10400468 = 0x18300000; + *(vu32 *)0x10400470 = 0x80341; + *(vu32 *)0x10400474 = 0x00010501; + *(vu32 *)0x10400478 = 0; + *(vu32 *)0x10400490 = 0x000002D0; + *(vu32 *)0x1040049C = 0x00000000; + + // Disco register + for(u32 i = 0; i < 256; i++) + *(vu32 *)0x10400484 = 0x10101 * i; + + // Bottom screen + *(vu32 *)0x10400500 = 0x000001c2; + *(vu32 *)0x10400504 = 0x000000d1; + *(vu32 *)0x10400508 = 0x000001c1; + *(vu32 *)0x1040050c = 0x000001c1; + *(vu32 *)0x10400510 = 0x000000cd; + *(vu32 *)0x10400514 = 0x000000cf; + *(vu32 *)0x10400518 = 0x000000d1; + *(vu32 *)0x1040051c = 0x01c501c1; + *(vu32 *)0x10400520 = 0x00010000; + *(vu32 *)0x10400524 = 0x0000019d; + *(vu32 *)0x10400528 = 0x00000052; + *(vu32 *)0x1040052c = 0x00000192; + *(vu32 *)0x10400530 = 0x00000192; + *(vu32 *)0x10400534 = 0x0000004f; + *(vu32 *)0x10400538 = 0x00000050; + *(vu32 *)0x1040053c = 0x00000052; + *(vu32 *)0x10400540 = 0x01980194; + *(vu32 *)0x10400544 = 0x00000000; + *(vu32 *)0x10400548 = 0x00000011; + *(vu32 *)0x1040055C = 0x00f00140; + *(vu32 *)0x10400560 = 0x01c100d1; + *(vu32 *)0x10400564 = 0x01920052; + *(vu32 *)0x10400568 = 0x18300000 + 0x46500; + *(vu32 *)0x10400570 = 0x80301; + *(vu32 *)0x10400574 = 0x00010501; + *(vu32 *)0x10400578 = 0; + *(vu32 *)0x10400590 = 0x000002D0; + *(vu32 *)0x1040059C = 0x00000000; + + // Disco register + for(u32 i = 0; i < 256; i++) + *(vu32 *)0x10400584 = 0x10101 * i; + + *(vu32 *)0x10400468 = 0x18300000; + *(vu32 *)0x1040046c = 0x18300000; + *(vu32 *)0x10400494 = 0x18300000; + *(vu32 *)0x10400498 = 0x18300000; + *(vu32 *)0x10400568 = 0x18346500; + *(vu32 *)0x1040056c = 0x18346500; + + //Set CakeBrah framebuffers + *((vu32 *)0x23FFFE00) = 0x18300000; + *((vu32 *)0x23FFFE04) = 0x18300000; + *((vu32 *)0x23FFFE08) = 0x18346500; + + //Clear ARM11 entry offset + *arm11 = 0; + + //Wait for the entry to be set + while(!*arm11); + + //Jump to it + ((void (*)())*arm11)(); +} diff --git a/external/screeninit/source/start.s b/external/screeninit/source/start.s new file mode 100644 index 0000000..40392d1 --- /dev/null +++ b/external/screeninit/source/start.s @@ -0,0 +1,10 @@ +.section .text.start +.align 4 +.global _start +_start: + @ Disable interrupts + CPSID aif + + b main + + .word 0 diff --git a/external/screeninit/source/types.h b/external/screeninit/source/types.h new file mode 100755 index 0000000..d27412b --- /dev/null +++ b/external/screeninit/source/types.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +//Common data types +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef uint64_t u64; +typedef volatile u8 vu8; +typedef volatile u16 vu16; +typedef volatile u32 vu32; +typedef volatile u64 vu64; \ No newline at end of file diff --git a/external/svc/Makefile b/external/svc/Makefile index 3e2acda..243b4c8 100644 --- a/external/svc/Makefile +++ b/external/svc/Makefile @@ -1,6 +1,6 @@ PATH := $(PATH):$(DEVKITARM)/bin -all: 7b.bin stub.bin +all: 7b.bin stub.bin emunand.bin %.o: %.s arm-none-eabi-as -o $@ $< diff --git a/external/svc/emunand.s b/external/svc/emunand.s new file mode 100644 index 0000000..0655d25 --- /dev/null +++ b/external/svc/emunand.s @@ -0,0 +1,45 @@ +.section .text +.global _start +_start: + // Original code that still needs to be executed. + mov r4, r0 + mov r5, r1 + mov r7, r2 + mov r6, r3 + +main: + // If we're already trying to access the SD, return. + ldr r2, [r0, #4] + ldr r1, sdmmc // In armips this instruction uses pc-releative loading + cmp r2, r1 + beq nand_sd_ret + + str r1, [r0, #4] // Set object to be SD + ldr r2, [r0, #8] // Get sector to read + cmp r2, #0 // Gateway compat + + ldr r3, nand_offset // ^ see above + add r2, r3 // Add the offset to the NAND in the SD. + + ldreq r3, ncsd_offset // ^ see above + addeq r2, r3 + + str r2, [r0, #8] // Store sector to read + + nand_sd_ret: + // Restore registers. + mov r0, r4 + mov r1, r5 + mov r2, r7 + mov r3, r6 + + // Return 4 bytes behind where we got called, + // due to the offset of this function being stored there. + mov r0, lr + add r0, #4 + bx r0 + +sdmmc: .ascii "SDMC" // The offset of the sdmmc object. +nand_offset: .ascii "NAND" // The starting offset of the emuNAND on the SD. +ncsd_offset: .ascii "NCSD" // Location of the NCSD header relative to nand_offset + diff --git a/external/svc/patches.s b/external/svc/patches.s new file mode 100644 index 0000000..44eaf6f --- /dev/null +++ b/external/svc/patches.s @@ -0,0 +1,77 @@ +.arm.little + +.create "patch1.bin", 0 +.arm +nand_sd: + ; Original code that still needs to be executed. + mov r4, r0 + mov r5, r1 + mov r7, r2 + mov r6, r3 + ; End. + + ; If we're already trying to access the SD, return. + ldr r2, [r0, #4] + ldr r1, [sdmmc] + cmp r2, r1 + beq nand_sd_ret + + str r1, [r0, #4] ; Set object to be SD + ldr r2, [r0, #8] ; Get sector to read + cmp r2, #0 ; For GW compatibility, see if we're trying to read the ncsd header (sector 0) + + ldr r3, [nand_offset] + add r2, r3 ; Add the offset to the NAND in the SD. + + ldreq r3, [ncsd_header_offset] + addeq r2, r3 ; If we're reading the ncsd header, add the offset of that sector. + + str r2, [r0, #8] ; Store sector to read + + nand_sd_ret: + ; Restore registers. + mov r1, r5 + mov r2, r7 + mov r3, r6 + + ; Return 4 bytes behind where we got called, + ; due to the offset of this function being stored there. + mov r0, lr + add r0, #4 + bx r0 +.pool +nand_offset: .ascii "NAND" ; The starting offset of the emuNAND on the SD. +ncsd_header_offset: .ascii "NCSD" ; The offset of the first emuNAND sector relative to the start of the emuNAND (Used for when the first sector is placed at the end). +sdmmc: .ascii "sdmmc" ; The offset of the sdmmc object. +.close + +.create "patch2.bin", 0 +.arm + .word 0x360003 + .word 0x10100000 + .word 0x1000001 + .word 0x360003 + .word 0x20000000 + .word 0x1010101 + .word 0x200603 + .word 0x8000000 + .word 0x1010101 + .word 0x1C0603 + .word 0x8020000 +.close + +.create "patch3.bin", 0 +.thumb + ldr r4, [_nand_sd_write] + blx r4 +.align 4 +_nand_sd_write: .ascii "mem" +.close + +.create "patch4.bin", 0 +.thumb + ldr r4, [_nand_sd_read] + blx r4 +.align 4 +_nand_sd_read: .ascii "mem" +.close diff --git a/host/bytecode_asm.py b/host/bytecode_asm.py index a963501..a97c541 100755 --- a/host/bytecode_asm.py +++ b/host/bytecode_asm.py @@ -48,6 +48,10 @@ def rel_name(x): 'twl_s1' : "0F", 'twl_s2' : "10", 'twl_s3' : "11", + + 'exe_text' : "12", + 'exe_data' : "13", + 'exe_ro' : "14", }.get(x, "-1") name = "NO NAME" diff --git a/source/config.h b/source/config.h index e612267..7095b4a 100644 --- a/source/config.h +++ b/source/config.h @@ -96,6 +96,9 @@ struct options_s // Allow enabling patches which are marked as 'incompatible'. Chances are there's a reason. #define IGNORE_BROKEN_SHIT 15 +// Whether to use an EmuNAND +#define OPTION_EMUNAND 16 + // Save log files during boot and from loader. // This will slow things down a bit. #define OPTION_SAVE_LOGS 253 diff --git a/source/fatfs/ff.c b/source/fatfs/ff.c index df502b9..ad5cb7e 100644 --- a/source/fatfs/ff.c +++ b/source/fatfs/ff.c @@ -2729,6 +2729,56 @@ f_open(FIL *fp, /* Pointer to the blank file object */ LEAVE_FF(dj.fs, res); } +/*-----------------------------------------------------------------------*/ +/* Read File */ +/*-----------------------------------------------------------------------*/ + + +FRESULT +f_getsector(FIL *fp, /* Pointer to the file object */ + UINT *sec /* Pointer to uint which will contain the sector */ + ) +{ + FRESULT res; + DWORD clst = 0, sect = 0; + BYTE csect; + + res = validate(fp); /* Check validity */ + + if (res != FR_OK) + LEAVE_FF(fp->fs, res); + if (fp->err) /* Check error */ + LEAVE_FF(fp->fs, (FRESULT)fp->err); + if (!(fp->flag & FA_READ)) /* Check access mode */ + LEAVE_FF(fp->fs, FR_DENIED); + + if ((fp->fptr % SS(fp->fs)) == 0) { /* On the sector boundary? */ + csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1)); /* Sector offset in the cluster */ + if (!csect) { /* On the cluster boundary? */ + if (fp->fptr == 0) { /* On the top of the file? */ + clst = fp->sclust; /* Follow from the origin */ + } else { /* Middle or end of the file */ + clst = get_fat(fp->fs, fp->clust); /* Follow cluster chain on the FAT */ + } + + if (clst < 2) + ABORT(fp->fs, FR_INT_ERR); + if (clst == 0xFFFFFFFF) + ABORT(fp->fs, FR_DISK_ERR); + } + + sect = clust2sect(fp->fs, clst); /* Get current sector */ + if (!sect) + ABORT(fp->fs, FR_INT_ERR); + sect += csect; + } + + *sec = sect; + + return 0; +} + + /*-----------------------------------------------------------------------*/ /* Read File */ /*-----------------------------------------------------------------------*/ diff --git a/source/fatfs/ff.h b/source/fatfs/ff.h index 40c9ffc..0bbe5bb 100644 --- a/source/fatfs/ff.h +++ b/source/fatfs/ff.h @@ -225,6 +225,7 @@ FRESULT f_setlabel(const TCHAR *label); FRESULT f_mount(FATFS *fs, const TCHAR *path, BYTE opt); /* Mount/Unmount a logical drive */ FRESULT f_mkfs(const TCHAR *path, BYTE sfd, UINT au); /* Create a file system on the volume */ FRESULT f_fdisk(BYTE pdrv, const DWORD szt[], void *work); /* Divide a physical drive into some partitions */ +FRESULT f_getsector(FIL *fp, UINT *sec); int f_putc(TCHAR c, FIL *fp); /* Put a character to the file */ int f_puts(const TCHAR *str, FIL *cp); /* Put a string to the file */ int f_printf(FIL *fp, const TCHAR *str, ...); /* Put a formatted string to the file */ diff --git a/source/fatfs/sdmmc.c b/source/fatfs/sdmmc.c index f2fd67e..34c4a60 100644 --- a/source/fatfs/sdmmc.c +++ b/source/fatfs/sdmmc.c @@ -22,15 +22,14 @@ * along with this program. If not, see http://www.gnu.org/licenses/. */ +// LEGAL - Note that despite the above notice, it must be used under +// MPL 2.0 here. GPLv2 and GPLv3 are not compatible, and his software +// delcares specifically GPLv2. We have to treat it as MPL 2.0 to +// not violate any licensing. + #include -#include -#include +#include #include -#include -#include -#include -#include -#include #include "sdmmc.h" //#include "DrawCharacter.h" diff --git a/source/interp.c b/source/interp.c index ad1fb77..141af48 100644 --- a/source/interp.c +++ b/source/interp.c @@ -42,8 +42,7 @@ struct mode uint8_t *memory; uint32_t size; }; - -struct mode modes[19]; +struct mode modes[21]; int init_bytecode = 0; int @@ -71,48 +70,45 @@ exec_bytecode(uint8_t *bytecode, uint16_t ver, uint32_t len, int debug) modes[5].size = firm_p9_exefs->fileHeaders[0].size; // NATIVE_FIRM Sect 0 - modes[6].memory = (uint8_t *)&firm_loc->section[0] + firm_loc->section[0].offset; + modes[6].memory = (uint8_t *)firm_loc + firm_loc->section[0].offset; modes[6].size = firm_loc->section[0].size; // NATIVE_FIRM Sect 1 - modes[7].memory = (uint8_t *)&firm_loc->section[1] + firm_loc->section[1].offset; + modes[7].memory = (uint8_t *)firm_loc + firm_loc->section[1].offset; modes[7].size = firm_loc->section[1].size; // NATIVE_FIRM Sect 2 - modes[8].memory = (uint8_t *)&firm_loc->section[2] + firm_loc->section[2].offset; + modes[8].memory = (uint8_t *)firm_loc + firm_loc->section[2].offset; modes[8].size = firm_loc->section[2].size; // NATIVE_FIRM Sect 3 - modes[9].memory = (uint8_t *)&firm_loc->section[3] + firm_loc->section[3].offset; + modes[9].memory = (uint8_t *)firm_loc + firm_loc->section[3].offset; modes[9].size = firm_loc->section[3].size; // AGB_FIRM Sect 0 - modes[10].memory = (uint8_t *)&agb_firm_loc->section[0] + agb_firm_loc->section[0].offset; + modes[10].memory = (uint8_t *)agb_firm_loc + agb_firm_loc->section[0].offset; modes[10].size = agb_firm_loc->section[0].size; // AGB_FIRM Sect 1 - modes[11].memory = (uint8_t *)&agb_firm_loc->section[1] + agb_firm_loc->section[1].offset; + modes[11].memory = (uint8_t *)agb_firm_loc + agb_firm_loc->section[1].offset; modes[11].size = agb_firm_loc->section[1].size; // AGB_FIRM Sect 2 - modes[12].memory = (uint8_t *)&agb_firm_loc->section[2] + agb_firm_loc->section[2].offset; + modes[12].memory = (uint8_t *)agb_firm_loc + agb_firm_loc->section[2].offset; modes[12].size = agb_firm_loc->section[2].size; // AGB_FIRM Sect 3 - modes[13].memory = (uint8_t *)&agb_firm_loc->section[3] + agb_firm_loc->section[3].offset; + modes[13].memory = (uint8_t *)agb_firm_loc + agb_firm_loc->section[3].offset; modes[13].size = agb_firm_loc->section[3].size; // TWL_FIRM Sect 0 - modes[14].memory = (uint8_t *)&twl_firm_loc->section[0] + twl_firm_loc->section[0].offset; + modes[14].memory = (uint8_t *)twl_firm_loc + twl_firm_loc->section[0].offset; modes[14].size = twl_firm_loc->section[0].size; // TWL_FIRM Sect 1 - modes[15].memory = (uint8_t *)&twl_firm_loc->section[1] + twl_firm_loc->section[1].offset; + modes[15].memory = (uint8_t *)twl_firm_loc + twl_firm_loc->section[1].offset; modes[15].size = twl_firm_loc->section[1].size; // TWL_FIRM Sect 2 - modes[16].memory = (uint8_t *)&twl_firm_loc->section[2] + twl_firm_loc->section[2].offset; + modes[16].memory = (uint8_t *)twl_firm_loc + twl_firm_loc->section[2].offset; modes[16].size = twl_firm_loc->section[2].size; // TWL_FIRM Sect 3 - modes[17].memory = (uint8_t *)&twl_firm_loc->section[3] + twl_firm_loc->section[3].offset; + modes[17].memory = (uint8_t *)twl_firm_loc + twl_firm_loc->section[3].offset; modes[17].size = twl_firm_loc->section[3].size; #endif - // Loader (not valid in bootmode) - // modes[18] = { 0, 0 }; - init_bytecode = 1; } @@ -139,10 +135,6 @@ exec_bytecode(uint8_t *bytecode, uint16_t ver, uint32_t len, int debug) test_was_false = 0; break; case OP_REL: // Change relativity. -#ifdef LOADER - // Loader doesn't support this. Just treat it like a two-byte NOP. - code += 2; -#else if (debug) log("rel\n"); code++; @@ -152,7 +144,6 @@ exec_bytecode(uint8_t *bytecode, uint16_t ver, uint32_t len, int debug) test_was_false = 0; set_mode = *code; code++; -#endif break; case OP_FIND: // Find pattern. if (debug) @@ -319,6 +310,9 @@ exec_bytecode(uint8_t *bytecode, uint16_t ver, uint32_t len, int debug) #ifndef LOADER set_mode = 3; current_mode = &modes[set_mode]; +#else + set_mode = 18; + current_mode = &modes[set_mode]; #endif offset = 0; test_was_false = 0; @@ -351,7 +345,10 @@ exec_bytecode(uint8_t *bytecode, uint16_t ver, uint32_t len, int debug) #ifdef LOADER int -execb(uint64_t tid, uint16_t ver, uint8_t *search_mem, uint32_t search_len) +execb(uint64_t tid, uint16_t ver, + uint8_t *text_mem, uint32_t text_len, + uint8_t* data_mem, uint32_t data_len, + uint8_t* ro_mem, uint32_t ro_len) { #else int @@ -413,8 +410,16 @@ execb(char *filename, int build_cache) FSFILE_Close(file); // Done reading in. // Set memory. - modes[18].memory = search_mem; - modes[18].size = search_len; + modes[18].memory = text_mem; + modes[18].size = text_len; + + // Set memory. + modes[19].memory = data_mem; + modes[19].size = data_len; + + // Set memory. + modes[20].memory = ro_mem; + modes[20].size = ro_len; log(" exec\n"); diff --git a/source/main.c b/source/main.c index eaecc1d..6c6a0f0 100644 --- a/source/main.c +++ b/source/main.c @@ -2,6 +2,8 @@ #include "firm/firm.h" #include "input.h" #include "config.h" +#include "screeninit.h" +#include "std/abort.h" int menu_handler(); @@ -11,9 +13,12 @@ void shut_up(); int main() { - if (fmount()) { + int c = fmount(); + screen_init(); + + if (c) { // Failed to mount SD. Bomb out. - fprintf(BOTTOM_SCREEN, "%pFailed to mount SD card.\n", COLOR(RED, BLACK)); + abort("Failed to mount SD card.\n"); } load_config(); // Load configuration. diff --git a/source/menu.c b/source/menu.c index e02f36d..f9d05be 100644 --- a/source/menu.c +++ b/source/menu.c @@ -32,6 +32,10 @@ static struct options_s options[] = { { 0, "", "", not_option, 0, 0 }, + { OPTION_EMUNAND, "EmuNAND", "Redirects NAND write/read to EmuNAND #0. Right now, only one is supported (but the work is done)", boolean_val, 0, 0 }, + + { 0, "", "", not_option, 0, 0 }, + { OPTION_AUTOBOOT, "Autoboot", "Boot the system automatically, unless the R key is held.", boolean_val, 0, 0 }, { OPTION_SILENCE, " Silent mode", "Suppress all debug output during autoboot. You'll see the screen turn on, then off.", boolean_val, 0, 0 }, diff --git a/source/patch/emunand.c b/source/patch/emunand.c new file mode 100644 index 0000000..dfeab0a --- /dev/null +++ b/source/patch/emunand.c @@ -0,0 +1,181 @@ +/* +* emunand.c +*/ + +#include "emunand.h" +#include "../std/memory.h" +#include "../std/draw.h" +#include "../std/fs.h" +#include "../std/abort.h" +#include "../firm/firm.h" +#include "../firm/fcram.h" +#include "../fatfs/sdmmc.h" +#include "../firm/headers.h" +#include "../patch_format.h" + +uint8_t *temp = (uint8_t*)FCRAM_JUNK_LOC; + +void verify_loop_emunand(char* filename) { + // FIXME - This won't work unless the NAND file is completely contiguous on disk, sadly. + // Technically speaking if I were to defrag my SD this would work, I suspect. + + uint32_t offset = get_file_sector(filename); // Get the sector of the file + + // Check for RedNAND image on SD + if(!sdmmc_sdcard_readsectors(offset, 1, temp) && *(uint32_t *)(temp + 0x100) == NCSD_MAGIC) { + fprintf(stderr, "emunand: found NCSD magic\n"); + } else { + abort("emunand: selected NAND image is not valid.\n"); + } +} + +void verify_emunand(uint32_t index, uint32_t* off, uint32_t* head) { + uint32_t nandSize = getMMCDevice(0)->total_size; + + uint32_t offset; + if (nandSize > 0x200000) + offset = 0x400000 * index; + else + offset = 0x200000 * index; + + // Check for RedNAND/Normal physical layout on SD + if(!sdmmc_sdcard_readsectors(offset + 1, 1, temp) && *(uint32_t *)(temp + 0x100) == NCSD_MAGIC) { + *off = offset + 1; + *head = offset + 1; + + fprintf(stderr, "emunand: found NCSD magic for #%u\n", index); + fprintf(stderr, "emunand: layout is normal\n"); + } + // Check for GW EmuNAND on SD + else if(!sdmmc_sdcard_readsectors(offset + nandSize, 1, temp) && *(uint32_t *)(temp + 0x100) == NCSD_MAGIC) { + *off = offset; + *head = offset + nandSize; + + fprintf(stderr, "emunand: found NCSD magic for %u\n", index); + fprintf(stderr, "emunand: layout is gateway\n"); + } else { + abort("emunand: selected NAND image is not valid.\n"); + } +} + +static void *getEmuCode(uint8_t *pos, uint32_t size) +{ + const uint8_t pattern[] = {0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00}; + + //Looking for the last free space before Process9 + void* ret = memfind(pos + 0x13500, size - 0x13500, pattern, 6) + 0x455; + + if (ret) { + fprintf(stderr, "emunand: free space @ %x\n", ret); + fprintf(stderr, "emunand: size is %u bytes\n", (uint8_t*)ret - pos); + } + + return ret; +} + +static uint32_t getSDMMC(uint8_t *pos, uint32_t size) +{ + //Look for struct code + const uint8_t pattern[] = {0x21, 0x20, 0x18, 0x20}; + const uint8_t *off = memfind(pos, size, pattern, 4); + + uint32_t ret = *(uint32_t *)(off + 9) + *(uint32_t *)(off + 0xD); + + fprintf(stderr, "emunand: SDMMC code @ %x\n", ret); + + return ret; +} + +static void patchNANDRW(uint8_t *pos, uint32_t size, uint32_t branchOffset) +{ + const uint16_t nandRedir[2] = {0x4C00, 0x47A0}; + + //Look for read/write code + const uint8_t pattern[] = {0x1E, 0x00, 0xC8, 0x05}; + + uint16_t *readOffset = (uint16_t *)memfind(pos, size, pattern, 4) - 3; + uint16_t *writeOffset = (uint16_t *)memfind((uint8_t *)(readOffset + 5), 0x100, pattern, 4) - 3; + + *readOffset = nandRedir[0]; + readOffset[1] = nandRedir[1]; + ((uint32_t *)readOffset)[1] = branchOffset; + + *writeOffset = nandRedir[0]; + writeOffset[1] = nandRedir[1]; + ((uint32_t *)writeOffset)[1] = branchOffset; + + fprintf(stderr, "emunand: write @ %x\n", writeOffset); + fprintf(stderr, "emunand: read @ %x\n", readOffset); +} + +static void patchMPU(uint8_t *pos, uint32_t size) +{ + const uint32_t mpuPatch[3] = {0x00360003, 0x00200603, 0x001C0603}; + + //Look for MPU pattern + const uint8_t pattern[] = {0x03, 0x00, 0x24, 0x00}; + + uint32_t *off = (uint32_t *)memfind(pos, size, pattern, 4); + + off[0] = mpuPatch[0]; + off[6] = mpuPatch[1]; + off[9] = mpuPatch[2]; + + fprintf(stderr, "emunand: mpu @ %x\n", off); +} + +void patch_emunand(uint32_t index) { + //uint8_t *arm9Section, uint32_t arm9SectionSize, uint8_t *process9Offset, uint32_t process9Size, uint32_t emuOffset, uint32_t emuHeader, uint32_t branchAdditive) + + // ARM9 section. + uint8_t* arm9Section = (uint8_t*)firm_loc + firm_loc->section[2].offset; + uint32_t arm9SectionSize = firm_loc->section[2].size; + + uint8_t* process9Offset = (uint8_t *)firm_p9_exefs + sizeof(exefs_h) + firm_p9_exefs->fileHeaders[0].offset; + uint32_t process9Size = firm_p9_exefs->fileHeaders[0].size; + + //Copy emuNAND code + void *emuCodeOffset = getEmuCode(arm9Section, arm9SectionSize); + if (!emuCodeOffset) + abort("emunand: code missing from arm9?\n"); + + FILE* f = fopen(PATH_EMUNAND_CODE, "r"); + if (!f) + abort("emunand: code not found on SD.\n"); + + uint32_t emunand_size = fsize(f); + fread(emuCodeOffset, 1, emunand_size, f); + fclose(f); + + uint32_t branchOffset = (uint32_t)emuCodeOffset - ((uint32_t)firm_loc + firm_loc->section[2].offset - firm_loc->section[2].address); + + fprintf(stderr, "emunand: read in emunand code - %x\n", emuCodeOffset); + + //Add the data of the found emuNAND + uint32_t *pos_offset = (uint32_t *)memfind(emuCodeOffset, emunand_size, "NAND", 4), + *pos_head = (uint32_t *)memfind(emuCodeOffset, emunand_size, "NCSD", 4), + *pos_sdmmc = (uint32_t *)memfind(emuCodeOffset, emunand_size, "SDMC", 4); + + verify_emunand(index, pos_offset, pos_head); + + fprintf(stderr, "emunand: nand is on sector %u\n", *pos_offset); + fprintf(stderr, "emunand: head is on sector %u\n", *pos_head); + + if (!pos_offset || !pos_head || !pos_sdmmc) + abort("emunand: couldn't find pattern in hook?\n"); + + //Add emuNAND hooks + patchNANDRW(process9Offset, process9Size, branchOffset); + + fprintf(stderr, "emunand: patched read/write calls\n"); + + //Find and add the SDMMC struct + + *pos_sdmmc = getSDMMC(process9Offset, process9Size); + + //Set MPU for emu code region + patchMPU(arm9Section, arm9SectionSize); + + fprintf(stderr, "emunand: patched MPU settings\n"); +} + diff --git a/source/patch/emunand.h b/source/patch/emunand.h new file mode 100644 index 0000000..35b3c56 --- /dev/null +++ b/source/patch/emunand.h @@ -0,0 +1,8 @@ +#ifndef __EMUNAND_H +#define __EMUNAND_H + +#include + +void patch_emunand(uint32_t size); + +#endif diff --git a/source/patch_format.h b/source/patch_format.h index c9af51b..ea1a420 100644 --- a/source/patch_format.h +++ b/source/patch_format.h @@ -46,6 +46,11 @@ // additionally the root if not found. #define PATH_EXEFS PATH_CFW "/exe" // ExeFS overrides, named like '.exefs' - NYI +#define PATH_BITS PATH_CFW "/bits" // Path to misc bits we need (emunand code, reboot code, etc) + +#define PATH_EMUNAND_CODE PATH_BITS "/emunand.bin" // Emunand hook. +#define PATH_SCREENINIT_CODE PATH_BITS "/screeninit.bin" // Screeninit code (ARM11) + #define PATH_NATIVE_F PATH_FIRMWARES "/native" #define PATH_AGB_F PATH_FIRMWARES "/agb" #define PATH_TWL_F PATH_FIRMWARES "/twl" diff --git a/source/patcher.c b/source/patcher.c index b8ae1ed..1dd98d8 100644 --- a/source/patcher.c +++ b/source/patcher.c @@ -5,6 +5,7 @@ #include "config.h" #include "common.h" #include "interp.h" +#include "patch/emunand.h" // TODO - Basically all this needs to move to patcher programs. @@ -84,5 +85,15 @@ patch_firm_all() wait(); } + // Use loopback EmuNAND? + if (config.options[OPTION_EMUNAND]) { + // Yes. + patch_emunand(0); +// patch_loop_emunand("/nand.bin"); + + // FIXME - NYI + wait(); + } + return 0; } diff --git a/source/screeninit.c b/source/screeninit.c new file mode 100644 index 0000000..9ce3eac --- /dev/null +++ b/source/screeninit.c @@ -0,0 +1,26 @@ +#include "std/fs.h" +#include "i2c.h" +#include "patch_format.h" + +#define PDN_GPU_CNT (*(volatile uint8_t *)0x10141200) + +static volatile uint32_t *const a11_entry = (volatile uint32_t *)0x1FFFFFF8; + +void screen_init() { + if (PDN_GPU_CNT == 1) { + uint32_t* screenInitAddress = (uint32_t*)0x24FFFC00; + + FILE* f = fopen(PATH_SCREENINIT_CODE, "r"); + fread(screenInitAddress, 1, fsize(f), f); // Read in the screeninit payload. + fclose(f); + + //Write brightness level for the stub to pick up + screenInitAddress[2] = 0x5F; + *a11_entry = (uint32_t)screenInitAddress; + + while(*a11_entry); + + //Turn on backlight + i2cWriteRegister(I2C_DEV_MCU, 0x22, 0x2A); + } +} diff --git a/source/screeninit.h b/source/screeninit.h new file mode 100644 index 0000000..5105774 --- /dev/null +++ b/source/screeninit.h @@ -0,0 +1,7 @@ +#ifndef __SCREENINIT_H +#define __SCREENINIT_H + +// Inits the screen if needed. +void screen_init(); + +#endif diff --git a/source/std/draw.c b/source/std/draw.c index 08f6283..3dc565a 100644 --- a/source/std/draw.c +++ b/source/std/draw.c @@ -51,8 +51,10 @@ clear_disp(uint8_t *screen) fseek(f, 0, SEEK_END); for (int i = 0; i < TEXT_BOTTOM_HEIGHT; i++) { char *text = text_buffer_bottom + (TEXT_BOTTOM_WIDTH * i); - if (text[0] == 0) - break; + for(int j = 0; j < TEXT_BOTTOM_WIDTH; j++) { + if (text[j] == 0) + text[j] = ' '; + } fwrite(text, 1, strnlen(text, TEXT_BOTTOM_WIDTH), f); fwrite("\n", 1, 1, f); } diff --git a/source/std/fs.c b/source/std/fs.c index 1b1db70..38ee108 100644 --- a/source/std/fs.c +++ b/source/std/fs.c @@ -229,3 +229,24 @@ read_file(void *data, char *path, size_t size) return read; } + +// DWORD fptr; /* File read/write pointer (Zeroed on file open) */ +// DWORD fsize; /* File size */ +// DWORD sclust; /* File start cluster (0:no cluster chain, always 0 when fsize is 0) */ +// DWORD clust; /* Current cluster of fpter (not valid when fprt is 0) */ +// DWORD dsect; /* Sector number appearing in buf[] (0:invalid) */ + +size_t get_file_sector(char* path) { + FILE* temp = fopen(path, "r"); + + if (!temp || !temp->is_open) + return 0; + + UINT sector; + + f_getsector(& temp->handle, §or); + + fclose(temp); + + return sector; +} diff --git a/source/std/fs.h b/source/std/fs.h index 852a389..5aac569 100644 --- a/source/std/fs.h +++ b/source/std/fs.h @@ -43,4 +43,6 @@ size_t fread(void *buffer, size_t elementSize, size_t elementCnt, FILE *fp); size_t write_file(void *data, char *path, size_t size); size_t read_file(void *data, char *path, size_t size); +size_t get_file_sector(char* path); + #endif diff --git a/source/std/types.h b/source/std/types.h index 290a10d..99a085b 100644 --- a/source/std/types.h +++ b/source/std/types.h @@ -2,7 +2,6 @@ #define __STD_TYPES_H #include -#include #define CFG_BOOTENV *(volatile uint32_t *)0x10010000 #define HID ~*(volatile uint32_t *)0x10146000