Do the same for large patches (emunand, reboot). This greatly simplifies logic.

This commit is contained in:
TuxSH 2018-05-22 22:55:04 +02:00
parent c0bd69309a
commit 0c9365bcb7
10 changed files with 348 additions and 292 deletions

View File

@ -38,7 +38,6 @@ ifeq ($(strip $(shell git describe --tags --match v[0-9]* | grep -)),)
endif
dir_source := source
dir_patches := patches
dir_arm11 := arm11
dir_k11_extension := k11_extension
dir_sysmodules := sysmodules
@ -57,8 +56,6 @@ objects = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \
$(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \
$(call rwildcard, $(dir_source), *.s *.c)))
bundled = $(dir_build)/reboot.bin.o $(dir_build)/emunand.bin.o
modules = $(dir_build)/loader.cxi $(dir_build)/rosalina.cxi $(dir_build)/sm.cxi $(dir_build)/pxi.cxi
define bin2o
@ -110,7 +107,7 @@ $(dir_build)/arm11.elf: $(dir_arm11)
@mkdir -p "$(@D)"
@$(MAKE) -C $<
$(dir_build)/main.elf: $(bundled) $(objects)
$(dir_build)/main.elf: $(objects)
$(LINK.o) -T linker.ld $(OUTPUT_OPTION) $^
$(dir_build)/k11_extension.bin: $(dir_k11_extension)
@ -136,10 +133,6 @@ $(dir_build)/pxi.cxi: $(dir_pxi)
$(dir_build)/%.bin.o: $(dir_build)/%.bin
@$(bin2o)
$(dir_build)/%.bin: $(dir_patches)/%.s
@mkdir -p "$(@D)"
@armips $<
$(dir_build)/memory.o $(dir_build)/strings.o: CFLAGS += -O3
$(dir_build)/config.o: CFLAGS += -DCONFIG_TITLE="\"$(name) $(revision) configuration\""
$(dir_build)/patches.o: CFLAGS += -DVERSION_MAJOR="$(version_major)" -DVERSION_MINOR="$(version_minor)"\
@ -147,13 +140,7 @@ $(dir_build)/patches.o: CFLAGS += -DVERSION_MAJOR="$(version_major)" -DVERSION_M
$(dir_build)/firm.o: $(dir_build)/modules.bin
$(dir_build)/firm.o: CFLAGS += -DLUMA_SECTION0_SIZE="$(shell wc -c $(dir_build)/modules.bin | tr -d [:space:][:alpha:][:punct:])"
$(dir_build)/bundled.h: $(bundled)
@$(foreach f, $(bundled),\
echo "extern const u8" `(echo $(basename $(notdir $(f))) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"[];" >> $@;\
echo "extern const u32" `(echo $(basename $(notdir $(f)))| sed -e 's/^\([0-9]\)/_\1/' | tr . _)`_size";" >> $@;\
)
$(dir_build)/%.o: $(dir_source)/%.c $(dir_build)/bundled.h
$(dir_build)/%.o: $(dir_source)/%.c
@mkdir -p "$(@D)"
$(COMPILE.c) $(OUTPUT_OPTION) $<

View File

@ -138,6 +138,7 @@ SECTIONS
{
*(.data)
*(.data.*)
KEEP (*(.large_patch*))
*(.gnu.linkonce.d*)
CONSTRUCTORS
. = ALIGN(4);

View File

@ -1,48 +0,0 @@
; Code by Normmatt
.arm.little
.create "build/emunand.bin", 0
.arm
; 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 out
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
out:
; 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
sdmmc: .ascii "SDMC"
nand_offset: .ascii "NAND" ; For rednand this should be 1
ncsd_header_offset: .ascii "NCSD" ; Depends on nand manufacturer + emunand type (GW/RED)
.close

View File

@ -1,207 +0,0 @@
; Code originally from delebile and mid-kid
.arm.little
copy_launch_stub_stack_top equ 0x01FFB800
copy_launch_stub_stack_bottom equ 0x01FFA800
copy_launch_stub_addr equ 0x01FF9000
argv_addr equ (copy_launch_stub_stack_bottom - 0x100)
fname_addr equ (copy_launch_stub_stack_bottom - 0x200)
low_tid_addr equ (copy_launch_stub_stack_bottom - 0x300)
firm_addr equ 0x20001000
firm_maxsize equ 0x07FFF000
.create "build/reboot.bin", 0
.arm
; Interesting registers and locations to keep in mind, set just before this code is ran:
; - r1: FIRM path in exefs.
; - r7 (or r8): pointer to file object
; - *r7: vtable
; - *(vtable + 0x28): fread function
; - *(r7 + 8): file handle
sub r7, r0, #8
mov r8, r1
pxi_wait_recv:
ldr r2, =0x44846
ldr r0, =0x10008000
readPxiLoop1:
ldrh r1, [r0, #4]
lsls r1, #0x17
bmi readPxiLoop1
ldr r0, [r0, #0xC]
cmp r0, r2
bne pxi_wait_recv
; Open file
add r0, r7, #8
adr r1, fname
mov r2, #1
ldr r6, [fopen]
orr r6, 1
blx r6
cmp r0, #0
bne panic
; Read file
mov r0, r7
adr r1, bytes_read
ldr r2, =firm_addr
ldr r3, =firm_maxsize
ldr r6, [r7]
ldr r6, [r6, #0x28]
blx r6
; Copy the low TID (in UTF-16) of the wanted firm
ldr r0, =low_tid_addr
add r1, r8, #0x1A
mov r2, #0x10
bl memcpy16
; Copy argv[0]
ldr r0, =fname_addr
adr r1, fname
mov r2, #82
bl memcpy16
ldr r0, =argv_addr
ldr r1, =fname_addr
ldr r2, =low_tid_addr
stmia r0, {r1, r2}
; Set kernel state
mov r0, #0
mov r1, #0
mov r2, #0
mov r3, #0
swi 0x7C
goto_reboot:
; Jump to reboot code
ldr r0, =(kernelcode_start - goto_reboot - 12)
add r0, pc ; pc is two instructions ahead of the instruction being executed (12 = 2*4 + 4)
swi 0x7B
die:
b die
memcpy16:
cmp r2, #0
bxeq lr
add r2, r0, r2
copy_loop16:
ldrh r3, [r1], #2
strh r3, [r0], #2
cmp r0, r2
blo copy_loop16
bx lr
panic:
mov r1, r0 ; unused register
mov r0, #0
swi 0x3C ; svcBreak(USERBREAK_PANIC)
b die
bytes_read: .word 0
fopen: .ascii "OPEN"
.pool
.area 2*(80+1), 0
fname: .ascii "FILE"
.endarea
.align 4
kernelcode_start:
msr cpsr_cxsf, #0xD3 ; disable interrupts and clear flags
ldr sp, =copy_launch_stub_stack_top
ldr r0, =copy_launch_stub_addr
adr r1, copy_launch_stub
mov r2, #(copy_launch_stub_end - copy_launch_stub)
bl memcpy32
; Disable MPU
ldr r0, =0x42078 ; alt vector select, enable itcm
mcr p15, 0, r0, c1, c0, 0
bl flushCaches
ldr r0, =copy_launch_stub_addr
bx r0
copy_launch_stub:
ldr r4, =firm_addr
mov r5, #0
load_section_loop:
; Such checks. Very ghetto. Wow.
add r3, r4, #0x40
add r3, r5,lsl #5
add r3, r5,lsl #4
ldmia r3, {r6-r8}
cmp r8, #0
movne r0, r7
addne r1, r4, r6
movne r2, r8
blne memcpy32
add r5, #1
cmp r5, #4
blo load_section_loop
mov r0, #2 ; argc
ldr r1, =argv_addr ; argv
ldr r2, =0xBABE ; magic word
mov r5, #0x20000000
ldr r6, [r4, #0x08]
str r6, [r5, #-4] ; store arm11 entrypoint
ldr lr, [r4, #0x0c]
bx lr
memcpy32:
add r2, r0, r2
copy_loop32:
ldr r3, [r1], #4
str r3, [r0], #4
cmp r0, r2
blo copy_loop32
bx lr
.pool
copy_launch_stub_end:
flushCaches:
; Clean and flush data cache
mov r1, #0 ; segment counter
outer_loop:
mov r0, #0 ; line counter
inner_loop:
orr r2, r1, r0 ; generate segment and line address
mcr p15, 0, r2, c7, c14, 2 ; clean and flush the line
add r0, #0x20 ; increment to next line
cmp r0, #0x400
bne inner_loop
add r1, #0x40000000
cmp r1, #0
bne outer_loop
; Drain write buffer
mcr p15, 0, r1, c7, c10, 4
; Flush instruction cache
mcr p15, 0, r1, c7, c5, 0
bx lr
.close

View File

@ -33,7 +33,7 @@
#include "memory.h"
#include "utils.h"
#include "fatfs/sdmmc/sdmmc.h"
#include "../build/bundled.h"
#include "large_patches.h"
u32 emuOffset,
emuHeader;
@ -109,8 +109,8 @@ static inline bool getFreeK9Space(u8 *pos, u32 size, u8 **freeK9Space)
//Looking for the last free space before Process9
*freeK9Space = memsearch(pos, pattern, size, sizeof(pattern));
if(*freeK9Space == NULL || (u32)(pos + size - *freeK9Space) < 0x455 + emunand_bin_size ||
*(u32 *)(*freeK9Space + 0x455 + emunand_bin_size - 4) != 0xFFFFFFFF) return false;
if(*freeK9Space == NULL || (u32)(pos + size - *freeK9Space) < 0x455 + emunandPatchSize ||
*(u32 *)(*freeK9Space + 0x455 + emunandPatchSize - 4) != 0xFFFFFFFF) return false;
*freeK9Space += 0x455;
@ -195,20 +195,17 @@ u32 patchEmuNand(u8 *arm9Section, u32 kernel9Size, u8 *process9Offset, u32 proce
u32 ret = 0;
//Copy EmuNAND code
memcpy(freeK9Space, emunand_bin, emunand_bin_size);
//Add the data of the found EmuNAND
u32 *posOffset = (u32 *)memsearch(freeK9Space, "NAND", emunand_bin_size, 4),
*posHeader = (u32 *)memsearch(freeK9Space, "NCSD", emunand_bin_size, 4);
*posOffset = emuOffset;
*posHeader = emuHeader;
emunandPatchNandOffset = emuOffset;
emunandPatchNcsdHeaderOffset = emuHeader;
//Find and add the SDMMC struct
u32 *posSdmmc = (u32 *)memsearch(freeK9Space, "SDMC", emunand_bin_size, 4);
u32 sdmmc;
ret += !ISN3DS && firmVersion < 0x25 ? getOldSdmmc(&sdmmc, firmVersion) : getSdmmc(process9Offset, process9Size, &sdmmc);
if(!ret) *posSdmmc = sdmmc;
if(!ret) emunandPatchSdmmcStructPtr = sdmmc;
//Copy EmuNAND code
memcpy(freeK9Space, emunandPatch, emunandPatchSize);
//Add EmuNAND hooks
u32 branchOffset = (u32)(freeK9Space - arm9Section + kernel9Address);

View File

@ -38,7 +38,6 @@
#include "screen.h"
#include "fmt.h"
#include "chainloader.h"
#include "../build/bundled.h"
static Firm *firm = (Firm *)0x20001000;

View File

@ -37,7 +37,6 @@
#include "buttons.h"
#include "firm.h"
#include "crypto.h"
#include "../build/bundled.h"
static FATFS sdFs,
nandFs;

38
source/large_patches.h Normal file
View File

@ -0,0 +1,38 @@
/*
* This file is part of Luma3DS
* Copyright (C) 2016-2017 Aurora Wright, TuxSH
*
* 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 <http://www.gnu.org/licenses/>.
*
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
* * Requiring preservation of specified reasonable legal notices or
* author attributions in that material or in the Appropriate Legal
* Notices displayed by works containing it.
* * Prohibiting misrepresentation of the origin of that material,
* or requiring that modified versions of such material be marked in
* reasonable ways as different from the original version.
*/
#pragma once
#include "types.h"
extern const u8 emunandPatch[];
extern const u32 emunandPatchSize;
extern u32 emunandPatchSdmmcStructPtr, emunandPatchNandOffset, emunandPatchNcsdHeaderOffset;
extern const u8 rebootPatch[];
extern const u32 rebootPatchSize;
extern u32 rebootPatchFopenPtr;
extern u16 rebootPatchFileName[80+1];

291
source/large_patches.s Normal file
View File

@ -0,0 +1,291 @@
.section .large_patch.emunand, "aw", %progbits
.arm
.align 4
@ Code originally by Normmatt
.global emunandPatch
emunandPatch:
@ 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, emunandPatchSdmmcStructPtr
cmp r2, r1
beq out
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, emunandPatchNandOffset
add r2, r3 @ Add the offset to the NAND in the SD
ldreq r3, emunandPatchNcsdHeaderOffset
addeq r2, r3 @ If we're reading the ncsd header, add the offset of that sector
str r2, [r0, #8] @ Store sector to read
out:
@ 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
.global emunandPatchSdmmcStructPtr
.global emunandPatchNandOffset
.global emunandPatchNcsdHeaderOffset
emunandPatchSdmmcStructPtr: .word 0 @ Pointer to sdmmc struct
emunandPatchNandOffset: .word 0 @ For rednand this should be 1
emunandPatchNcsdHeaderOffset: .word 0 @ Depends on nand manufacturer + emunand type (GW/RED)
.pool
.balign 4
_emunandPatchEnd:
.global emunandPatchSize
emunandPatchSize:
.word _emunandPatchEnd - emunandPatch
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ Code originally from delebile and mid-kid
.section .large_patch.reboot, "aw", %progbits
.arm
.align 4
.set copy_launch_stub_stack_top, 0x01FFB800
.set copy_launch_stub_stack_bottom, 0x01FFA800
.set copy_launch_stub_addr, 0x01FF9000
.set argv_addr, (copy_launch_stub_stack_bottom - 0x100)
.set fname_addr, (copy_launch_stub_stack_bottom - 0x200)
.set low_tid_addr, (copy_launch_stub_stack_bottom - 0x300)
.set firm_addr, 0x20001000
.set firm_maxsize, 0x07FFF000
.global rebootPatch
rebootPatch:
@ Interesting registers and locations to keep in mind, set just before this code is ran:
@ - r1: FIRM path in exefs.
@ - r7 (or r8): pointer to file object
@ - *r7: vtable
@ - *(vtable + 0x28): fread function
@ - *(r7 + 8): file handle
sub r7, r0, #8
mov r8, r1
pxi_wait_recv:
ldr r2, =0x44846
ldr r0, =0x10008000
readPxiLoop1:
ldrh r1, [r0, #4]
lsls r1, #0x17
bmi readPxiLoop1
ldr r0, [r0, #0xC]
cmp r0, r2
bne pxi_wait_recv
@ Open file
add r0, r7, #8
adr r1, rebootPatchFileName
mov r2, #1
adr r6, rebootPatchFopenPtr
ldr r6, [r6]
orr r6, #1
blx r6
cmp r0, #0
bne panic
@ Read file
mov r0, r7
adr r1, bytes_read
ldr r2, =firm_addr
ldr r3, =firm_maxsize
ldr r6, [r7]
ldr r6, [r6, #0x28]
blx r6
@ Copy the low TID (in UTF-16) of the wanted firm
ldr r0, =low_tid_addr
add r1, r8, #0x1A
mov r2, #0x10
bl memcpy16
@ Copy argv[0]
ldr r0, =fname_addr
adr r1, rebootPatchFileName
mov r2, #82
bl memcpy16
ldr r0, =argv_addr
ldr r1, =fname_addr
ldr r2, =low_tid_addr
stmia r0, {r1, r2}
@ Set kernel state
mov r0, #0
mov r1, #0
mov r2, #0
mov r3, #0
swi 0x7C
goto_reboot:
@ Jump to reboot code
ldr r0, kernel_func_displ
add r0, pc @ pc is two instructions ahead of the instruction being executed (12 = 2*4 + 4)
swi 0x7B
die:
b die
memcpy16:
cmp r2, #0
bxeq lr
add r2, r0, r2
copy_loop16:
ldrh r3, [r1], #2
strh r3, [r0], #2
cmp r0, r2
blo copy_loop16
bx lr
panic:
mov r1, r0 @ unused register
mov r0, #0
swi 0x3C @ svcBreak(USERBREAK_PANIC)
b die
kernel_func_displ:
.word kernelcode_start - goto_reboot - 12
bytes_read:
.word 0
.global rebootPatchFopenPtr
rebootPatchFopenPtr:
.word 0
.pool
.global rebootPatchFileName
rebootPatchFileName:
.skip 2*(80+1)
.balign 4
kernelcode_start:
msr cpsr_cxsf, #0xD3 @ disable interrupts and clear flags
ldr sp, =copy_launch_stub_stack_top
ldr r0, =copy_launch_stub_addr
adr r1, copy_launch_stub
mov r2, #(copy_launch_stub_end - copy_launch_stub)
bl memcpy32
@ Disable MPU
ldr r0, =0x42078 @ alt vector select, enable itcm
mcr p15, 0, r0, c1, c0, 0
bl flushCaches
ldr r0, =copy_launch_stub_addr
bx r0
copy_launch_stub:
ldr r4, =firm_addr
mov r5, #0
load_section_loop:
@ Such checks. Very ghetto. Wow.
add r3, r4, #0x40
add r3, r5,lsl #5
add r3, r5,lsl #4
ldmia r3, {r6-r8}
cmp r8, #0
movne r0, r7
addne r1, r4, r6
movne r2, r8
blne memcpy32
add r5, #1
cmp r5, #4
blo load_section_loop
mov r0, #2 @ argc
ldr r1, =argv_addr @ argv
ldr r2, =0xBABE @ magic word
mov r5, #0x20000000
ldr r6, [r4, #0x08]
str r6, [r5, #-4] @ store arm11 entrypoint
ldr lr, [r4, #0x0c]
bx lr
memcpy32:
add r2, r0, r2
copy_loop32:
ldr r3, [r1], #4
str r3, [r0], #4
cmp r0, r2
blo copy_loop32
bx lr
.pool
copy_launch_stub_end:
flushCaches:
@ Clean and flush data cache
mov r1, #0 @ segment counter
outer_loop:
mov r0, #0 @ line counter
inner_loop:
orr r2, r1, r0 @ generate segment and line address
mcr p15, 0, r2, c7, c14, 2 @ clean and flush the line
add r0, #0x20 @ increment to next line
cmp r0, #0x400
bne inner_loop
add r1, #0x40000000
cmp r1, #0
bne outer_loop
@ Drain write buffer
mcr p15, 0, r1, c7, c10, 4
@ Flush instruction cache
mcr p15, 0, r1, c7, c5, 0
bx lr
.pool
.balign 4
_rebootPatchEnd:
.global rebootPatchSize
rebootPatchSize:
.word _rebootPatchEnd - rebootPatch

View File

@ -40,7 +40,7 @@
#include "config.h"
#include "utils.h"
#include "arm9_exception_handlers.h"
#include "../build/bundled.h"
#include "large_patches.h"
u8 *getProcess9Info(u8 *pos, u32 size, u32 *process9Size, u32 *process9MemAddr)
{
@ -316,15 +316,14 @@ u32 patchFirmlaunches(u8 *pos, u32 size, u32 process9MemAddr)
//Firmlaunch function offset - offset in BLX opcode (A4-16 - ARM DDI 0100E) + 1
u32 fOpenOffset = (u32)(off + 9 - (-((*(u32 *)off & 0x00FFFFFF) << 2) & (0xFFFFFF << 2)) - pos + process9MemAddr);
//Copy firmlaunch code
memcpy(off, reboot_bin, reboot_bin_size);
//Put the fOpen offset in the right location
u32 *pos_fopen = (u32 *)memsearch(off, "OPEN", reboot_bin_size, 4);
*pos_fopen = fOpenOffset;
rebootPatchFopenPtr = fOpenOffset;
u16 *fname = (u16 *)memsearch(off, "FILE", reboot_bin_size, 8);
memcpy(fname, launchedPath, 2 * (1 + pathLen));
//Copy the launched path
memcpy(rebootPatchFileName, launchedPath, 2 * (1 + pathLen));
//Copy firmlaunch code
memcpy(off, rebootPatch, rebootPatchSize);
return 0;
}