Do the same for large patches (emunand, reboot). This greatly simplifies logic.
This commit is contained in:
parent
c0bd69309a
commit
0c9365bcb7
17
Makefile
17
Makefile
@ -38,7 +38,6 @@ ifeq ($(strip $(shell git describe --tags --match v[0-9]* | grep -)),)
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
dir_source := source
|
dir_source := source
|
||||||
dir_patches := patches
|
|
||||||
dir_arm11 := arm11
|
dir_arm11 := arm11
|
||||||
dir_k11_extension := k11_extension
|
dir_k11_extension := k11_extension
|
||||||
dir_sysmodules := sysmodules
|
dir_sysmodules := sysmodules
|
||||||
@ -57,8 +56,6 @@ objects = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \
|
|||||||
$(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \
|
$(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \
|
||||||
$(call rwildcard, $(dir_source), *.s *.c)))
|
$(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
|
modules = $(dir_build)/loader.cxi $(dir_build)/rosalina.cxi $(dir_build)/sm.cxi $(dir_build)/pxi.cxi
|
||||||
|
|
||||||
define bin2o
|
define bin2o
|
||||||
@ -110,7 +107,7 @@ $(dir_build)/arm11.elf: $(dir_arm11)
|
|||||||
@mkdir -p "$(@D)"
|
@mkdir -p "$(@D)"
|
||||||
@$(MAKE) -C $<
|
@$(MAKE) -C $<
|
||||||
|
|
||||||
$(dir_build)/main.elf: $(bundled) $(objects)
|
$(dir_build)/main.elf: $(objects)
|
||||||
$(LINK.o) -T linker.ld $(OUTPUT_OPTION) $^
|
$(LINK.o) -T linker.ld $(OUTPUT_OPTION) $^
|
||||||
|
|
||||||
$(dir_build)/k11_extension.bin: $(dir_k11_extension)
|
$(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
|
$(dir_build)/%.bin.o: $(dir_build)/%.bin
|
||||||
@$(bin2o)
|
@$(bin2o)
|
||||||
|
|
||||||
$(dir_build)/%.bin: $(dir_patches)/%.s
|
|
||||||
@mkdir -p "$(@D)"
|
|
||||||
@armips $<
|
|
||||||
|
|
||||||
$(dir_build)/memory.o $(dir_build)/strings.o: CFLAGS += -O3
|
$(dir_build)/memory.o $(dir_build)/strings.o: CFLAGS += -O3
|
||||||
$(dir_build)/config.o: CFLAGS += -DCONFIG_TITLE="\"$(name) $(revision) configuration\""
|
$(dir_build)/config.o: CFLAGS += -DCONFIG_TITLE="\"$(name) $(revision) configuration\""
|
||||||
$(dir_build)/patches.o: CFLAGS += -DVERSION_MAJOR="$(version_major)" -DVERSION_MINOR="$(version_minor)"\
|
$(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: $(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)/firm.o: CFLAGS += -DLUMA_SECTION0_SIZE="$(shell wc -c $(dir_build)/modules.bin | tr -d [:space:][:alpha:][:punct:])"
|
||||||
|
|
||||||
$(dir_build)/bundled.h: $(bundled)
|
$(dir_build)/%.o: $(dir_source)/%.c
|
||||||
@$(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
|
|
||||||
@mkdir -p "$(@D)"
|
@mkdir -p "$(@D)"
|
||||||
$(COMPILE.c) $(OUTPUT_OPTION) $<
|
$(COMPILE.c) $(OUTPUT_OPTION) $<
|
||||||
|
|
||||||
|
@ -138,6 +138,7 @@ SECTIONS
|
|||||||
{
|
{
|
||||||
*(.data)
|
*(.data)
|
||||||
*(.data.*)
|
*(.data.*)
|
||||||
|
KEEP (*(.large_patch*))
|
||||||
*(.gnu.linkonce.d*)
|
*(.gnu.linkonce.d*)
|
||||||
CONSTRUCTORS
|
CONSTRUCTORS
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
|
@ -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
|
|
207
patches/reboot.s
207
patches/reboot.s
@ -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
|
|
@ -33,7 +33,7 @@
|
|||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "fatfs/sdmmc/sdmmc.h"
|
#include "fatfs/sdmmc/sdmmc.h"
|
||||||
#include "../build/bundled.h"
|
#include "large_patches.h"
|
||||||
|
|
||||||
u32 emuOffset,
|
u32 emuOffset,
|
||||||
emuHeader;
|
emuHeader;
|
||||||
@ -109,8 +109,8 @@ static inline bool getFreeK9Space(u8 *pos, u32 size, u8 **freeK9Space)
|
|||||||
//Looking for the last free space before Process9
|
//Looking for the last free space before Process9
|
||||||
*freeK9Space = memsearch(pos, pattern, size, sizeof(pattern));
|
*freeK9Space = memsearch(pos, pattern, size, sizeof(pattern));
|
||||||
|
|
||||||
if(*freeK9Space == NULL || (u32)(pos + size - *freeK9Space) < 0x455 + emunand_bin_size ||
|
if(*freeK9Space == NULL || (u32)(pos + size - *freeK9Space) < 0x455 + emunandPatchSize ||
|
||||||
*(u32 *)(*freeK9Space + 0x455 + emunand_bin_size - 4) != 0xFFFFFFFF) return false;
|
*(u32 *)(*freeK9Space + 0x455 + emunandPatchSize - 4) != 0xFFFFFFFF) return false;
|
||||||
|
|
||||||
*freeK9Space += 0x455;
|
*freeK9Space += 0x455;
|
||||||
|
|
||||||
@ -195,20 +195,17 @@ u32 patchEmuNand(u8 *arm9Section, u32 kernel9Size, u8 *process9Offset, u32 proce
|
|||||||
|
|
||||||
u32 ret = 0;
|
u32 ret = 0;
|
||||||
|
|
||||||
//Copy EmuNAND code
|
|
||||||
memcpy(freeK9Space, emunand_bin, emunand_bin_size);
|
|
||||||
|
|
||||||
//Add the data of the found EmuNAND
|
//Add the data of the found EmuNAND
|
||||||
u32 *posOffset = (u32 *)memsearch(freeK9Space, "NAND", emunand_bin_size, 4),
|
emunandPatchNandOffset = emuOffset;
|
||||||
*posHeader = (u32 *)memsearch(freeK9Space, "NCSD", emunand_bin_size, 4);
|
emunandPatchNcsdHeaderOffset = emuHeader;
|
||||||
*posOffset = emuOffset;
|
|
||||||
*posHeader = emuHeader;
|
|
||||||
|
|
||||||
//Find and add the SDMMC struct
|
//Find and add the SDMMC struct
|
||||||
u32 *posSdmmc = (u32 *)memsearch(freeK9Space, "SDMC", emunand_bin_size, 4);
|
|
||||||
u32 sdmmc;
|
u32 sdmmc;
|
||||||
ret += !ISN3DS && firmVersion < 0x25 ? getOldSdmmc(&sdmmc, firmVersion) : getSdmmc(process9Offset, process9Size, &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
|
//Add EmuNAND hooks
|
||||||
u32 branchOffset = (u32)(freeK9Space - arm9Section + kernel9Address);
|
u32 branchOffset = (u32)(freeK9Space - arm9Section + kernel9Address);
|
||||||
|
@ -38,7 +38,6 @@
|
|||||||
#include "screen.h"
|
#include "screen.h"
|
||||||
#include "fmt.h"
|
#include "fmt.h"
|
||||||
#include "chainloader.h"
|
#include "chainloader.h"
|
||||||
#include "../build/bundled.h"
|
|
||||||
|
|
||||||
static Firm *firm = (Firm *)0x20001000;
|
static Firm *firm = (Firm *)0x20001000;
|
||||||
|
|
||||||
|
@ -37,7 +37,6 @@
|
|||||||
#include "buttons.h"
|
#include "buttons.h"
|
||||||
#include "firm.h"
|
#include "firm.h"
|
||||||
#include "crypto.h"
|
#include "crypto.h"
|
||||||
#include "../build/bundled.h"
|
|
||||||
|
|
||||||
static FATFS sdFs,
|
static FATFS sdFs,
|
||||||
nandFs;
|
nandFs;
|
||||||
|
38
source/large_patches.h
Normal file
38
source/large_patches.h
Normal 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
291
source/large_patches.s
Normal 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
|
@ -40,7 +40,7 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "arm9_exception_handlers.h"
|
#include "arm9_exception_handlers.h"
|
||||||
#include "../build/bundled.h"
|
#include "large_patches.h"
|
||||||
|
|
||||||
u8 *getProcess9Info(u8 *pos, u32 size, u32 *process9Size, u32 *process9MemAddr)
|
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
|
//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);
|
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
|
//Put the fOpen offset in the right location
|
||||||
u32 *pos_fopen = (u32 *)memsearch(off, "OPEN", reboot_bin_size, 4);
|
rebootPatchFopenPtr = fOpenOffset;
|
||||||
*pos_fopen = fOpenOffset;
|
|
||||||
|
|
||||||
u16 *fname = (u16 *)memsearch(off, "FILE", reboot_bin_size, 8);
|
//Copy the launched path
|
||||||
memcpy(fname, launchedPath, 2 * (1 + pathLen));
|
memcpy(rebootPatchFileName, launchedPath, 2 * (1 + pathLen));
|
||||||
|
|
||||||
|
//Copy firmlaunch code
|
||||||
|
memcpy(off, rebootPatch, rebootPatchSize);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user