Remove A9LH & Brahma support altogether, use FIRM format instead
This commit is contained in:
parent
1d4245e582
commit
ab14e77b50
13
Makefile
13
Makefile
@ -36,13 +36,13 @@ define bin2o
|
|||||||
endef
|
endef
|
||||||
|
|
||||||
.PHONY: all
|
.PHONY: all
|
||||||
all: a9lh
|
all: firm
|
||||||
|
|
||||||
.PHONY: release
|
.PHONY: release
|
||||||
release: $(dir_out)/$(name)$(revision).7z
|
release: $(dir_out)/$(name)$(revision).7z
|
||||||
|
|
||||||
.PHONY: a9lh
|
.PHONY: firm
|
||||||
a9lh: $(dir_out)/arm9loaderhax.bin
|
firm: $(dir_out)/boot.firm
|
||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
clean:
|
clean:
|
||||||
@ -63,12 +63,9 @@ $(dir_out)/$(name)$(revision).7z: all
|
|||||||
@mkdir -p "$(@D)"
|
@mkdir -p "$(@D)"
|
||||||
@7z a -mx $@ ./$(@D)/* ./$(dir_exceptions)/exception_dump_parser.py
|
@7z a -mx $@ ./$(@D)/* ./$(dir_exceptions)/exception_dump_parser.py
|
||||||
|
|
||||||
$(dir_out)/arm9loaderhax.bin: $(dir_build)/main.bin
|
$(dir_out)/boot.firm: $(dir_build)/main.elf
|
||||||
@mkdir -p "$(@D)"
|
@mkdir -p "$(@D)"
|
||||||
@cp -a $(dir_build)/main.bin $@
|
@firmtool build $@ -e 0 -D $^ -C NDMA
|
||||||
|
|
||||||
$(dir_build)/main.bin: $(dir_build)/main.elf
|
|
||||||
$(OBJCOPY) -S -O binary $< $@
|
|
||||||
|
|
||||||
$(dir_build)/main.elf: $(bundled) $(objects)
|
$(dir_build)/main.elf: $(bundled) $(objects)
|
||||||
$(LINK.o) -T linker.ld $(OUTPUT_OPTION) $^
|
$(LINK.o) -T linker.ld $(OUTPUT_OPTION) $^
|
||||||
|
@ -28,7 +28,6 @@ enum singleOptions
|
|||||||
AUTOBOOTEMU = 0,
|
AUTOBOOTEMU = 0,
|
||||||
USEEMUFIRM,
|
USEEMUFIRM,
|
||||||
LOADEXTFIRMSANDMODULES,
|
LOADEXTFIRMSANDMODULES,
|
||||||
USECUSTOMPATH,
|
|
||||||
PATCHGAMES,
|
PATCHGAMES,
|
||||||
PATCHVERSTRING,
|
PATCHVERSTRING,
|
||||||
SHOWGBABOOT,
|
SHOWGBABOOT,
|
||||||
|
@ -22,15 +22,20 @@
|
|||||||
|
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include "cache.h"
|
#include "cache.h"
|
||||||
|
#include "firm.h"
|
||||||
|
|
||||||
void main(u32 payloadSize)
|
void main(int argc __attribute__((unused)), char **argv)
|
||||||
{
|
{
|
||||||
void *payloadAddress = (void *)0x23F00000;
|
Firm *firm = (Firm *)0x24000000;
|
||||||
|
char absPath[92];
|
||||||
|
|
||||||
memcpy(payloadAddress, (void *)0x24000000, payloadSize);
|
u32 i;
|
||||||
|
for(i = 0; i < 91 && argv[1] != 0; i++)
|
||||||
|
absPath[i] = argv[1][i];
|
||||||
|
for(; i < 91; i++)
|
||||||
|
absPath[i] = 0;
|
||||||
|
|
||||||
//Ensure that all memory transfers have completed and that the caches have been flushed
|
char *argvPassed[1] = {absPath};
|
||||||
flushCaches();
|
|
||||||
|
|
||||||
((void (*)())payloadAddress)();
|
launchFirm(firm, 1, argvPassed);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
@ This file is part of Luma3DS
|
@ This file is part of Luma3DS
|
||||||
@ Copyright (C) 2016 Aurora Wright, TuxSH
|
@ Copyright (C) 2017 Aurora Wright, TuxSH
|
||||||
@
|
@
|
||||||
@ This program is free software: you can redistribute it and/or modify
|
@ 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
|
@ it under the terms of the GNU General Public License as published by
|
||||||
|
117
patches/reboot.s
117
patches/reboot.s
@ -2,9 +2,15 @@
|
|||||||
|
|
||||||
.arm.little
|
.arm.little
|
||||||
|
|
||||||
payload_addr equ 0x23F00000 ; Brahma payload address
|
argv_addr equ 0x27FFDF00
|
||||||
payload_maxsize equ 0x100000 ; Maximum size for the payload (maximum that CakeBrah supports)
|
fname_addr equ 0x27FFDF80
|
||||||
|
low_tid_addr equ 0x27FFDFE0
|
||||||
|
copy_launch_stub_addr equ 0x27FFE000
|
||||||
|
|
||||||
|
firm_addr equ 0x24000000
|
||||||
|
firm_maxsize equ (copy_launch_stub_addr - 0x1000 - firm_addr)
|
||||||
|
|
||||||
|
arm11_entrypoint_addr equ 0x1FFFFFFC
|
||||||
.create "build/reboot.bin", 0
|
.create "build/reboot.bin", 0
|
||||||
.arm
|
.arm
|
||||||
; Interesting registers and locations to keep in mind, set just before this code is ran:
|
; Interesting registers and locations to keep in mind, set just before this code is ran:
|
||||||
@ -28,9 +34,6 @@ payload_maxsize equ 0x100000 ; Maximum size for the payload (maximum that CakeB
|
|||||||
cmp r0, r2
|
cmp r0, r2
|
||||||
bne pxi_wait_recv
|
bne pxi_wait_recv
|
||||||
|
|
||||||
mov r4, #2
|
|
||||||
|
|
||||||
open_payload:
|
|
||||||
; Open file
|
; Open file
|
||||||
add r0, r7, #8
|
add r0, r7, #8
|
||||||
adr r1, fname
|
adr r1, fname
|
||||||
@ -39,31 +42,33 @@ payload_maxsize equ 0x100000 ; Maximum size for the payload (maximum that CakeB
|
|||||||
orr r6, 1
|
orr r6, 1
|
||||||
blx r6
|
blx r6
|
||||||
cmp r0, #0
|
cmp r0, #0
|
||||||
beq read_payload
|
bne panic
|
||||||
subs r4, r4, #1
|
|
||||||
beq panic
|
|
||||||
adr r0, fname
|
|
||||||
adr r1, nand_mount
|
|
||||||
mov r2, #8
|
|
||||||
bl memcpy16
|
|
||||||
b open_payload
|
|
||||||
|
|
||||||
read_payload:
|
|
||||||
; Read file
|
; Read file
|
||||||
mov r0, r7
|
mov r0, r7
|
||||||
adr r1, bytes_read
|
adr r1, bytes_read
|
||||||
ldr r2, =payload_addr
|
ldr r2, =firm_addr
|
||||||
ldr r3, =payload_maxsize
|
ldr r3, =firm_maxsize
|
||||||
ldr r6, [r7]
|
ldr r6, [r7]
|
||||||
ldr r6, [r6, #0x28]
|
ldr r6, [r6, #0x28]
|
||||||
blx r6
|
blx r6
|
||||||
|
|
||||||
; Copy the low TID (in UTF-16) of the wanted firm to the 5th byte of the payload
|
; Copy the low TID (in UTF-16) of the wanted firm to the 5th byte of the payload
|
||||||
ldr r0, =payload_addr + 4
|
ldr r0, =low_tid_addr
|
||||||
add r1, r8, #0x1A
|
add r1, r8, #0x1A
|
||||||
mov r2, #0x10
|
mov r2, #0x10
|
||||||
bl memcpy16
|
bl memcpy16
|
||||||
|
|
||||||
|
ldr r0, =fname_addr
|
||||||
|
adr r1, fname
|
||||||
|
mov r2, #42
|
||||||
|
bl memcpy16
|
||||||
|
|
||||||
|
ldr r0, =argv_addr
|
||||||
|
ldr r1, =fname_addr
|
||||||
|
ldr r2, =low_tid_addr
|
||||||
|
stmia r0, {r1, r2}
|
||||||
|
|
||||||
; Set kernel state
|
; Set kernel state
|
||||||
mov r0, #0
|
mov r0, #0
|
||||||
mov r1, #0
|
mov r1, #0
|
||||||
@ -81,12 +86,14 @@ payload_maxsize equ 0x100000 ; Maximum size for the payload (maximum that CakeB
|
|||||||
b die
|
b die
|
||||||
|
|
||||||
memcpy16:
|
memcpy16:
|
||||||
|
cmp r2, #0
|
||||||
|
bxeq lr
|
||||||
add r2, r0, r2
|
add r2, r0, r2
|
||||||
copy_loop:
|
copy_loop16:
|
||||||
ldrh r3, [r1], #2
|
ldrh r3, [r1], #2
|
||||||
strh r3, [r0], #2
|
strh r3, [r0], #2
|
||||||
cmp r0, r2
|
cmp r0, r2
|
||||||
blo copy_loop
|
blo copy_loop16
|
||||||
bx lr
|
bx lr
|
||||||
|
|
||||||
panic:
|
panic:
|
||||||
@ -98,7 +105,7 @@ payload_maxsize equ 0x100000 ; Maximum size for the payload (maximum that CakeB
|
|||||||
bytes_read: .word 0
|
bytes_read: .word 0
|
||||||
fopen: .ascii "OPEN"
|
fopen: .ascii "OPEN"
|
||||||
.pool
|
.pool
|
||||||
fname: .dcw "sdmc:/arm9loaderhax.bin"
|
fname: .dcw "sdmc:/arm9loaderha.firm"
|
||||||
.word 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
.word 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||||
.pool
|
.pool
|
||||||
nand_mount: .dcw "nand"
|
nand_mount: .dcw "nand"
|
||||||
@ -106,12 +113,75 @@ nand_mount: .dcw "nand"
|
|||||||
.align 4
|
.align 4
|
||||||
kernelcode_start:
|
kernelcode_start:
|
||||||
|
|
||||||
ldr sp, =0x080FF000
|
mrs r0, cpsr ; disable interrupts
|
||||||
|
orr r0, #0xC0
|
||||||
|
msr cpsr, r0
|
||||||
|
|
||||||
|
ldr sp, =0x27FFDF00
|
||||||
|
|
||||||
|
ldr r0, =copy_launch_stub_addr
|
||||||
|
adr r1, copy_launch_stub
|
||||||
|
mov r2, #(copy_launch_stub_end - copy_launch_stub)
|
||||||
|
bl memcpy32
|
||||||
|
|
||||||
; Disable MPU
|
; Disable MPU
|
||||||
ldr r0, =0x42078 ; alt vector select, enable itcm
|
ldr r0, =0x42078 ; alt vector select, enable itcm
|
||||||
mcr p15, 0, r0, c1, c0, 0
|
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}
|
||||||
|
mov r0, r7
|
||||||
|
add r1, r4, r6
|
||||||
|
mov r2, r8
|
||||||
|
bl memcpy32
|
||||||
|
add r5, #1
|
||||||
|
cmp r5, #3
|
||||||
|
blo load_section_loop
|
||||||
|
|
||||||
|
ldr r0, =arm11_entrypoint_addr
|
||||||
|
ldr r1, [r4, #0x08]
|
||||||
|
str r1, [r0]
|
||||||
|
|
||||||
|
mov r0, #2 ; argc
|
||||||
|
ldr r1, =argv_addr ; argv
|
||||||
|
ldr r2, =0xBEEF ; magic word
|
||||||
|
|
||||||
|
ldr r5, =arm11_entrypoint_addr
|
||||||
|
ldr r6, [r4, #0x08]
|
||||||
|
str r6, [r5]
|
||||||
|
|
||||||
|
ldr lr, [r4, #0x0c]
|
||||||
|
bx lr
|
||||||
|
|
||||||
|
memcpy32:
|
||||||
|
cmp r2, #0
|
||||||
|
bxeq lr
|
||||||
|
add r2, r0, r2
|
||||||
|
copy_loop32:
|
||||||
|
ldr r3, [r1], #4
|
||||||
|
str r3, [r0], #4
|
||||||
|
cmp r0, r2
|
||||||
|
blo copy_loop32
|
||||||
|
bx lr
|
||||||
|
|
||||||
|
copy_launch_stub_end:
|
||||||
|
|
||||||
|
flushCaches:
|
||||||
|
|
||||||
; Clean and flush data cache
|
; Clean and flush data cache
|
||||||
mov r1, #0 ; segment counter
|
mov r1, #0 ; segment counter
|
||||||
outer_loop:
|
outer_loop:
|
||||||
@ -134,10 +204,7 @@ nand_mount: .dcw "nand"
|
|||||||
; Flush instruction cache
|
; Flush instruction cache
|
||||||
mcr p15, 0, r1, c7, c5, 0
|
mcr p15, 0, r1, c7, c5, 0
|
||||||
|
|
||||||
; Jump to payload
|
bx lr
|
||||||
ldr r0, =payload_addr
|
|
||||||
bx r0
|
|
||||||
|
|
||||||
.pool
|
.pool
|
||||||
.close
|
.close
|
||||||
|
|
||||||
|
@ -24,6 +24,8 @@
|
|||||||
* Adapted from 3DBrew and https://github.com/mid-kid/CakesForeveryWan/blob/master/source/headers.h
|
* Adapted from 3DBrew and https://github.com/mid-kid/CakesForeveryWan/blob/master/source/headers.h
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
typedef struct __attribute__((packed))
|
typedef struct __attribute__((packed))
|
||||||
{
|
{
|
||||||
u32 address;
|
u32 address;
|
||||||
@ -139,7 +141,7 @@ typedef struct __attribute__((packed))
|
|||||||
|
|
||||||
typedef struct __attribute__((packed))
|
typedef struct __attribute__((packed))
|
||||||
{
|
{
|
||||||
u32 magic;
|
char magic[4];
|
||||||
u32 reserved1;
|
u32 reserved1;
|
||||||
u8 *arm11Entry;
|
u8 *arm11Entry;
|
||||||
u8 *arm9Entry;
|
u8 *arm9Entry;
|
||||||
|
@ -84,7 +84,6 @@ void configMenu(bool isSdMode, bool oldPinStatus, u32 oldPinMode)
|
|||||||
const char *singleOptionsText[] = { "( ) Autoboot EmuNAND",
|
const char *singleOptionsText[] = { "( ) Autoboot EmuNAND",
|
||||||
"( ) Use EmuNAND FIRM if booting with R",
|
"( ) Use EmuNAND FIRM if booting with R",
|
||||||
"( ) Enable loading external FIRMs and modules",
|
"( ) Enable loading external FIRMs and modules",
|
||||||
"( ) Use custom path",
|
|
||||||
"( ) Enable game patching",
|
"( ) Enable game patching",
|
||||||
"( ) Show NAND or user string in System Settings",
|
"( ) Show NAND or user string in System Settings",
|
||||||
"( ) Show GBA boot screen in patched AGB_FIRM",
|
"( ) Show GBA boot screen in patched AGB_FIRM",
|
||||||
@ -147,10 +146,6 @@ void configMenu(bool isSdMode, bool oldPinStatus, u32 oldPinMode)
|
|||||||
"This isn't needed in most cases.\n\n"
|
"This isn't needed in most cases.\n\n"
|
||||||
"Refer to the wiki for instructions.",
|
"Refer to the wiki for instructions.",
|
||||||
|
|
||||||
"Use a custom path for the\n"
|
|
||||||
"Luma3DS payload.\n\n"
|
|
||||||
"Refer to the wiki for instructions.",
|
|
||||||
|
|
||||||
"Enable overriding the region and\n"
|
"Enable overriding the region and\n"
|
||||||
"language configuration and the usage\n"
|
"language configuration and the usage\n"
|
||||||
"of patched code binaries,\n"
|
"of patched code binaries,\n"
|
||||||
@ -195,8 +190,8 @@ void configMenu(bool isSdMode, bool oldPinStatus, u32 oldPinMode)
|
|||||||
|
|
||||||
"Enable Luma3DS's ARM9/ARM11 exception\n"
|
"Enable Luma3DS's ARM9/ARM11 exception\n"
|
||||||
"handlers.\n"
|
"handlers.\n"
|
||||||
"A9LH is required, and Luma3DS should\n"
|
"Luma3DS should be ran as:\n"
|
||||||
"be ran as arm9loaderhax.bin.\n"
|
"arm9loaderhax.bin\n\n"
|
||||||
"Useful for debugging."
|
"Useful for debugging."
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -226,7 +221,6 @@ void configMenu(bool isSdMode, bool oldPinStatus, u32 oldPinMode)
|
|||||||
{ .visible = true },
|
{ .visible = true },
|
||||||
{ .visible = true },
|
{ .visible = true },
|
||||||
{ .visible = true },
|
{ .visible = true },
|
||||||
{ .visible = true },
|
|
||||||
{ .visible = true }
|
{ .visible = true }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
|
|
||||||
#define CONFIG_FILE "config.bin"
|
#define CONFIG_FILE "config.bin"
|
||||||
#define CONFIG_VERSIONMAJOR 1
|
#define CONFIG_VERSIONMAJOR 1
|
||||||
#define CONFIG_VERSIONMINOR 10
|
#define CONFIG_VERSIONMINOR 11
|
||||||
|
|
||||||
#define BOOTCFG_NAND BOOTCONFIG(0, 7)
|
#define BOOTCFG_NAND BOOTCONFIG(0, 7)
|
||||||
#define BOOTCFG_FIRM BOOTCONFIG(3, 7)
|
#define BOOTCFG_FIRM BOOTCONFIG(3, 7)
|
||||||
@ -50,7 +50,6 @@ enum singleOptions
|
|||||||
AUTOBOOTEMU = 0,
|
AUTOBOOTEMU = 0,
|
||||||
USEEMUFIRM,
|
USEEMUFIRM,
|
||||||
LOADEXTFIRMSANDMODULES,
|
LOADEXTFIRMSANDMODULES,
|
||||||
USECUSTOMPATH,
|
|
||||||
PATCHGAMES,
|
PATCHGAMES,
|
||||||
PATCHVERSTRING,
|
PATCHVERSTRING,
|
||||||
SHOWGBABOOT,
|
SHOWGBABOOT,
|
||||||
|
@ -230,7 +230,7 @@ static void aes_batch(void *dst, const void *src, u32 blockCount)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void aes(void *dst, const void *src, u32 blockCount, void *iv, u32 mode, u32 ivMode)
|
void aes(void *dst, const void *src, u32 blockCount, void *iv, u32 mode, u32 ivMode)
|
||||||
{
|
{
|
||||||
*REG_AESCNT = mode |
|
*REG_AESCNT = mode |
|
||||||
AES_CNT_INPUT_ORDER | AES_CNT_OUTPUT_ORDER |
|
AES_CNT_INPUT_ORDER | AES_CNT_OUTPUT_ORDER |
|
||||||
@ -278,10 +278,8 @@ static void sha_wait_idle()
|
|||||||
while(*REG_SHA_CNT & 1);
|
while(*REG_SHA_CNT & 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sha(void *res, const void *src, u32 size, u32 mode)
|
void sha(void *res, const void *src, u32 size, u32 mode)
|
||||||
{
|
{
|
||||||
backupAndRestoreShaHash(false);
|
|
||||||
|
|
||||||
sha_wait_idle();
|
sha_wait_idle();
|
||||||
*REG_SHA_CNT = mode | SHA_CNT_OUTPUT_ENDIAN | SHA_NORMAL_ROUND;
|
*REG_SHA_CNT = mode | SHA_CNT_OUTPUT_ENDIAN | SHA_NORMAL_ROUND;
|
||||||
|
|
||||||
@ -571,21 +569,3 @@ void computePinHash(u8 *outbuf, const u8 *inbuf)
|
|||||||
aes(cipherText, inbuf, 1, cid, AES_CBC_ENCRYPT_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
|
aes(cipherText, inbuf, 1, cid, AES_CBC_ENCRYPT_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||||
sha(outbuf, cipherText, sizeof(cipherText), SHA_256_MODE);
|
sha(outbuf, cipherText, sizeof(cipherText), SHA_256_MODE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void backupAndRestoreShaHash(bool isRestore)
|
|
||||||
{
|
|
||||||
if(ISSIGHAX) return;
|
|
||||||
|
|
||||||
static bool didShaHashBackup = false;
|
|
||||||
__attribute__((aligned(4))) static u8 shaHashBackup[SHA_256_HASH_SIZE];
|
|
||||||
|
|
||||||
if(isRestore)
|
|
||||||
{
|
|
||||||
if(didShaHashBackup) memcpy((void *)REG_SHA_HASH, shaHashBackup, sizeof(shaHashBackup));
|
|
||||||
}
|
|
||||||
else if(!didShaHashBackup)
|
|
||||||
{
|
|
||||||
memcpy(shaHashBackup, (void *)REG_SHA_HASH, sizeof(shaHashBackup));
|
|
||||||
didShaHashBackup = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -107,6 +107,9 @@
|
|||||||
extern u32 emuOffset;
|
extern u32 emuOffset;
|
||||||
extern FirmwareSource firmSource;
|
extern FirmwareSource firmSource;
|
||||||
|
|
||||||
|
void aes(void *dst, const void *src, u32 blockCount, void *iv, u32 mode, u32 ivMode);
|
||||||
|
void sha(void *res, const void *src, u32 size, u32 mode);
|
||||||
|
|
||||||
void ctrNandInit(void);
|
void ctrNandInit(void);
|
||||||
int ctrNandRead(u32 sector, u32 sectorCount, u8 *outbuf);
|
int ctrNandRead(u32 sector, u32 sectorCount, u8 *outbuf);
|
||||||
int ctrNandWrite(u32 sector, u32 sectorCount, const u8 *inbuf);
|
int ctrNandWrite(u32 sector, u32 sectorCount, const u8 *inbuf);
|
||||||
@ -114,4 +117,3 @@ bool decryptExeFs(Cxi *cxi);
|
|||||||
bool decryptNusFirm(const Ticket *ticket, Cxi *cxi, u32 ncchSize);
|
bool decryptNusFirm(const Ticket *ticket, Cxi *cxi, u32 ncchSize);
|
||||||
void kernel9Loader(Arm9Bin *arm9Section);
|
void kernel9Loader(Arm9Bin *arm9Section);
|
||||||
void computePinHash(u8 *outbuf, const u8 *inbuf);
|
void computePinHash(u8 *outbuf, const u8 *inbuf);
|
||||||
void backupAndRestoreShaHash(bool isRestore);
|
|
||||||
|
@ -35,8 +35,6 @@
|
|||||||
#include "fmt.h"
|
#include "fmt.h"
|
||||||
#include "../build/bundled.h"
|
#include "../build/bundled.h"
|
||||||
|
|
||||||
static Firm *firm = (Firm *)0x24000000;
|
|
||||||
|
|
||||||
static inline bool loadFirmFromStorage(FirmwareType firmType)
|
static inline bool loadFirmFromStorage(FirmwareType firmType)
|
||||||
{
|
{
|
||||||
const char *firmwareFiles[] = {
|
const char *firmwareFiles[] = {
|
||||||
|
@ -23,6 +23,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
#include "3dsheaders.h"
|
||||||
|
|
||||||
|
static Firm *const firm = (Firm *const)0x24000000;
|
||||||
|
|
||||||
u32 loadFirm(FirmwareType *firmType, FirmwareSource nandType, bool loadFromStorage, bool isSafeMode);
|
u32 loadFirm(FirmwareType *firmType, FirmwareSource nandType, bool loadFromStorage, bool isSafeMode);
|
||||||
u32 patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32 emuHeader, bool isSafeMode, bool doUnitinfoPatch, bool enableExceptionHandlers);
|
u32 patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32 emuHeader, bool isSafeMode, bool doUnitinfoPatch, bool enableExceptionHandlers);
|
||||||
|
109
source/fs.c
109
source/fs.c
@ -32,6 +32,8 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "fatfs/ff.h"
|
#include "fatfs/ff.h"
|
||||||
#include "buttons.h"
|
#include "buttons.h"
|
||||||
|
#include "firm.h"
|
||||||
|
#include "crypto.h"
|
||||||
#include "../build/bundled.h"
|
#include "../build/bundled.h"
|
||||||
|
|
||||||
static FATFS sdFs,
|
static FATFS sdFs,
|
||||||
@ -116,12 +118,80 @@ void fileDelete(const char *path)
|
|||||||
f_unlink(path);
|
f_unlink(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static __attribute__((noinline)) bool overlaps(u32 as, u32 ae, u32 bs, u32 be)
|
||||||
|
{
|
||||||
|
if (as <= bs && bs <= ae)
|
||||||
|
return true;
|
||||||
|
else if (bs <= as && as <= be)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool checkFirmPayload(void)
|
||||||
|
{
|
||||||
|
if(memcmp(firm->magic, "FIRM", 4) != 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if(firm->arm9Entry == NULL) //allow for the arm11 entrypoint to be zero in which case nothing is done on the arm11 side
|
||||||
|
return false;
|
||||||
|
|
||||||
|
u32 size = 0x200;
|
||||||
|
for(u32 i = 0; i < 4; i++)
|
||||||
|
size += firm->section[i].size;
|
||||||
|
|
||||||
|
bool arm9EpFound = false, arm11EpFound = false;
|
||||||
|
for(u32 i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
__attribute__((aligned(4))) u8 hash[0x20];
|
||||||
|
|
||||||
|
FirmSection *section = &firm->section[i];
|
||||||
|
|
||||||
|
// allow empty sections
|
||||||
|
if (section->size == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if(section->offset < 0x200)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if(section->address + section->size < section->address) //overflow check
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if(((u32)section->address & 3) || (section->offset & 0x1FF) || (section->size & 0x1FF)) //alignment check
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if(overlaps((u32)section->address, (u32)section->address + section->size, 0x27FFE000, 0x28000000))
|
||||||
|
return false;
|
||||||
|
else if(overlaps((u32)section->address, (u32)section->address + section->size, 0x27FFE000 - 0x1000, 0x27FFE000))
|
||||||
|
return false;
|
||||||
|
else if(overlaps((u32)section->address, (u32)section->address + section->size, (u32)firm, (u32)firm + size))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
sha(hash, (u8 *)firm + section->offset, section->size, SHA_256_MODE);
|
||||||
|
if(memcmp(hash, section->hash, 0x20) != 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if(firm->arm9Entry >= section->address && firm->arm9Entry < (section->address + section->size))
|
||||||
|
arm9EpFound = true;
|
||||||
|
|
||||||
|
if(firm->arm11Entry >= section->address && firm->arm11Entry < (section->address + section->size))
|
||||||
|
arm11EpFound = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return arm9EpFound && (firm->arm11Entry == NULL || arm11EpFound);
|
||||||
|
}
|
||||||
|
|
||||||
void loadPayload(u32 pressed, const char *payloadPath)
|
void loadPayload(u32 pressed, const char *payloadPath)
|
||||||
{
|
{
|
||||||
u32 *loaderAddress = (u32 *)0x27FFE000;
|
u32 *loaderAddress = (u32 *)0x27FFE000;
|
||||||
u8 *payloadAddress = (u8 *)0x24000000;
|
|
||||||
u32 payloadSize = 0,
|
u32 payloadSize = 0,
|
||||||
maxPayloadSize = 0xFFE00;
|
maxPayloadSize = (u32)((u8 *)loaderAddress - (u8 *)firm);
|
||||||
|
|
||||||
|
char path[62] = {0},
|
||||||
|
absPath[92] = {0};
|
||||||
|
|
||||||
|
char mountPoint[5] = {0};
|
||||||
|
for(u32 i = 0; i < 4 && launchedPath[i] != ':'; i++)
|
||||||
|
mountPoint[i] = launchedPath[i];
|
||||||
|
|
||||||
if(payloadPath == NULL)
|
if(payloadPath == NULL)
|
||||||
{
|
{
|
||||||
@ -142,7 +212,6 @@ void loadPayload(u32 pressed, const char *payloadPath)
|
|||||||
DIR dir;
|
DIR dir;
|
||||||
FILINFO info;
|
FILINFO info;
|
||||||
FRESULT result;
|
FRESULT result;
|
||||||
char path[22];
|
|
||||||
|
|
||||||
result = f_findfirst(&dir, &info, "payloads", pattern);
|
result = f_findfirst(&dir, &info, "payloads", pattern);
|
||||||
|
|
||||||
@ -153,24 +222,36 @@ void loadPayload(u32 pressed, const char *payloadPath)
|
|||||||
if(!info.fname[0]) return;
|
if(!info.fname[0]) return;
|
||||||
|
|
||||||
sprintf(path, "payloads/%s", info.altname);
|
sprintf(path, "payloads/%s", info.altname);
|
||||||
payloadSize = fileRead(payloadAddress, path, maxPayloadSize);
|
if(memcmp(mountPoint, "nand", 4))
|
||||||
}
|
sprintf(absPath, "nand:/rw/luma/payloads/%s", info.altname);
|
||||||
else payloadSize = fileRead(payloadAddress, payloadPath, maxPayloadSize);
|
else
|
||||||
|
sprintf(absPath, "%s:/luma/payloads/%s", mountPoint, info.altname);
|
||||||
|
|
||||||
if(!payloadSize) return;
|
payloadSize = fileRead(firm, path, maxPayloadSize);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(memcmp(mountPoint, "nand", 4))
|
||||||
|
sprintf(absPath, "nand:/rw/luma/payloads/%s", payloadPath);
|
||||||
|
else
|
||||||
|
sprintf(absPath, "%s:/luma/payloads/%s", mountPoint, payloadPath);
|
||||||
|
|
||||||
|
payloadSize = fileRead(firm, payloadPath, maxPayloadSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!payloadSize || !checkFirmPayload()) return;
|
||||||
|
|
||||||
writeConfig(true);
|
writeConfig(true);
|
||||||
|
|
||||||
|
char *argv[1] = {absPath};
|
||||||
memcpy(loaderAddress, loader_bin, loader_bin_size);
|
memcpy(loaderAddress, loader_bin, loader_bin_size);
|
||||||
|
|
||||||
if(ISN3DS) kernel9Loader(NULL);
|
|
||||||
backupAndRestoreShaHash(true);
|
|
||||||
initScreens();
|
initScreens();
|
||||||
|
|
||||||
flushDCacheRange(loaderAddress, loader_bin_size);
|
flushDCacheRange(loaderAddress, loader_bin_size);
|
||||||
flushICacheRange(loaderAddress, loader_bin_size);
|
flushICacheRange(loaderAddress, loader_bin_size);
|
||||||
|
|
||||||
((void (*)(u32))loaderAddress)(payloadSize);
|
((void (*)(int, char **, u32))loaderAddress)(1, argv, 0x0000BEEF);
|
||||||
}
|
}
|
||||||
|
|
||||||
void payloadMenu(void)
|
void payloadMenu(void)
|
||||||
@ -190,11 +271,11 @@ void payloadMenu(void)
|
|||||||
|
|
||||||
u32 nameLength = strlen(info.fname);
|
u32 nameLength = strlen(info.fname);
|
||||||
|
|
||||||
if(nameLength < 5 || nameLength > 52) continue;
|
if(nameLength < 6 || nameLength > 52) continue;
|
||||||
|
|
||||||
nameLength -= 4;
|
nameLength -= 5;
|
||||||
|
|
||||||
if(memcmp(info.fname + nameLength, ".bin", 4) != 0) continue;
|
if(memcmp(info.fname + nameLength, ".firm", 5) != 0) continue;
|
||||||
|
|
||||||
memcpy(payloadList[payloadNum], info.fname, nameLength);
|
memcpy(payloadList[payloadNum], info.fname, nameLength);
|
||||||
payloadList[payloadNum][nameLength] = 0;
|
payloadList[payloadNum][nameLength] = 0;
|
||||||
@ -258,7 +339,7 @@ void payloadMenu(void)
|
|||||||
|
|
||||||
if(pressed != BUTTON_START)
|
if(pressed != BUTTON_START)
|
||||||
{
|
{
|
||||||
sprintf(path, "payloads/%s.bin", payloadList[selectedPayload]);
|
sprintf(path, "payloads/%s.firm", payloadList[selectedPayload]);
|
||||||
loadPayload(0, path);
|
loadPayload(0, path);
|
||||||
error("The payload is too large or corrupted.");
|
error("The payload is too large or corrupted.");
|
||||||
}
|
}
|
||||||
|
@ -32,12 +32,16 @@
|
|||||||
#include "pin.h"
|
#include "pin.h"
|
||||||
#include "crypto.h"
|
#include "crypto.h"
|
||||||
#include "fmt.h"
|
#include "fmt.h"
|
||||||
|
#include "memory.h"
|
||||||
|
|
||||||
extern CfgData configData;
|
extern CfgData configData;
|
||||||
extern ConfigurationStatus needConfig;
|
extern ConfigurationStatus needConfig;
|
||||||
extern FirmwareSource firmSource;
|
extern FirmwareSource firmSource;
|
||||||
|
|
||||||
void main(void)
|
u16 launchedFirmTidLow[8];
|
||||||
|
u16 launchedPath[42];
|
||||||
|
|
||||||
|
void main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
bool isSafeMode = false,
|
bool isSafeMode = false,
|
||||||
isNoForceFlagSet = false;
|
isNoForceFlagSet = false;
|
||||||
@ -45,15 +49,59 @@ void main(void)
|
|||||||
FirmwareType firmType;
|
FirmwareType firmType;
|
||||||
FirmwareSource nandType;
|
FirmwareSource nandType;
|
||||||
|
|
||||||
|
switch(argc)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
error("Unsupported launcher.");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1: //Normal boot
|
||||||
|
{
|
||||||
|
u32 i;
|
||||||
|
for(i = 0; i < 41 && launchedPath[i] != 0; i++) //Copy and convert the path to utf16
|
||||||
|
launchedPath[2 * i] = argv[0][i];
|
||||||
|
for(; i < 41; i++)
|
||||||
|
launchedPath[i] = 0;
|
||||||
|
|
||||||
|
for(u32 i = 0; i < 8; i++)
|
||||||
|
launchedFirmTidLow[i] = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 2: //Firmlaunch
|
||||||
|
{
|
||||||
|
u32 i;
|
||||||
|
u16 *p = (u16 *)argv[0];
|
||||||
|
for(i = 0; i < 41 && launchedPath[i] != 0; i++)
|
||||||
|
launchedPath[i] = p[i];
|
||||||
|
for(; i < 41; i++)
|
||||||
|
launchedPath[i] = 0;
|
||||||
|
|
||||||
|
memcpy(launchedFirmTidLow, (u16 *)argv[1], 16);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char mountPoint[5] = {0};
|
||||||
|
for(u32 i = 0; i < 4 && argv[0][i] != ':'; i++)
|
||||||
|
mountPoint[i] = argv[0][i];
|
||||||
|
|
||||||
//Mount SD or CTRNAND
|
//Mount SD or CTRNAND
|
||||||
bool isSdMode;
|
bool isSdMode;
|
||||||
if(mountFs(true, false)) isSdMode = true;
|
|
||||||
else
|
if(memcmp(mountPoint, "sdmc", 4) == 0)
|
||||||
|
{
|
||||||
|
if(!mountFs(true, false)) error("Failed to mount SD.");
|
||||||
|
isSdMode = true;
|
||||||
|
}
|
||||||
|
else if(memcmp(mountPoint, "nand", 4) == 0)
|
||||||
{
|
{
|
||||||
firmSource = FIRMWARE_SYSNAND;
|
firmSource = FIRMWARE_SYSNAND;
|
||||||
if(!mountFs(false, true)) error("Failed to mount SD and CTRNAND.");
|
if(!mountFs(false, true)) error("Failed to mount SD and CTRNAND.");
|
||||||
isSdMode = false;
|
isSdMode = false;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
error("Launched from an unsupported location");
|
||||||
|
|
||||||
//Attempt to read the configuration file
|
//Attempt to read the configuration file
|
||||||
needConfig = readConfig() ? MODIFY_CONFIGURATION : CREATE_CONFIGURATION;
|
needConfig = readConfig() ? MODIFY_CONFIGURATION : CREATE_CONFIGURATION;
|
||||||
|
@ -37,30 +37,6 @@
|
|||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "../build/bundled.h"
|
#include "../build/bundled.h"
|
||||||
|
|
||||||
static inline void pathChanger(u8 *pos)
|
|
||||||
{
|
|
||||||
const char *pathFile = "path.txt";
|
|
||||||
u8 path[57];
|
|
||||||
|
|
||||||
u32 pathSize = fileRead(path, pathFile, sizeof(path));
|
|
||||||
|
|
||||||
if(pathSize < 6) return;
|
|
||||||
|
|
||||||
if(path[pathSize - 1] == 0xA) pathSize--;
|
|
||||||
if(path[pathSize - 1] == 0xD) pathSize--;
|
|
||||||
|
|
||||||
if(pathSize < 6 || pathSize > 55 || path[0] != '/' || memcmp(path + pathSize - 4, ".bin", 4) != 0) return;
|
|
||||||
|
|
||||||
u16 finalPath[56];
|
|
||||||
for(u32 i = 0; i < pathSize; i++)
|
|
||||||
finalPath[i] = (u16)path[i];
|
|
||||||
|
|
||||||
finalPath[pathSize] = 0;
|
|
||||||
|
|
||||||
u8 *posPath = memsearch(pos, u"sd", reboot_bin_size, 4) + 0xA;
|
|
||||||
memcpy(posPath, finalPath, (pathSize + 1) * 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
u8 *getProcess9Info(u8 *pos, u32 size, u32 *process9Size, u32 *process9MemAddr)
|
u8 *getProcess9Info(u8 *pos, u32 size, u32 *process9Size, u32 *process9MemAddr)
|
||||||
{
|
{
|
||||||
u8 *temp = memsearch(pos, "NCCH", size, 4);
|
u8 *temp = memsearch(pos, "NCCH", size, 4);
|
||||||
@ -159,7 +135,8 @@ u32 patchFirmlaunches(u8 *pos, u32 size, u32 process9MemAddr)
|
|||||||
u32 *pos_fopen = (u32 *)memsearch(off, "OPEN", reboot_bin_size, 4);
|
u32 *pos_fopen = (u32 *)memsearch(off, "OPEN", reboot_bin_size, 4);
|
||||||
*pos_fopen = fOpenOffset;
|
*pos_fopen = fOpenOffset;
|
||||||
|
|
||||||
if(CONFIG(USECUSTOMPATH)) pathChanger(off);
|
//u16 *fname = (u16 *)memsearch(off, u"sd", reboot_bin_size, 4);
|
||||||
|
//memcpy(fname, u"sdmc:/test.firm", 32);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -24,32 +24,31 @@
|
|||||||
.align 4
|
.align 4
|
||||||
.global _start
|
.global _start
|
||||||
_start:
|
_start:
|
||||||
b start
|
|
||||||
|
|
||||||
.global launchedFirmTidLow
|
|
||||||
launchedFirmTidLow:
|
|
||||||
.hword 0, 0, 0, 0, 0, 0, 0, 0
|
|
||||||
|
|
||||||
start:
|
|
||||||
@ Disable interrupts
|
@ Disable interrupts
|
||||||
mrs r0, cpsr
|
mrs r4, cpsr
|
||||||
orr r0, #0x1C0
|
orr r4, #0x1C0
|
||||||
msr cpsr_cx, r0
|
msr cpsr_cx, r4
|
||||||
|
|
||||||
|
ldr r4, =0xBEEF
|
||||||
|
cmp r2, r4
|
||||||
|
movne r0, #0 @ check magic word
|
||||||
|
|
||||||
@ Change the stack pointer
|
@ Change the stack pointer
|
||||||
mov sp, #0x27000000
|
mov sp, #0x27000000
|
||||||
|
|
||||||
@ Disable caches / MPU
|
@ Disable caches / MPU
|
||||||
mrc p15, 0, r0, c1, c0, 0 @ read control register
|
mrc p15, 0, r4, c1, c0, 0 @ read control register
|
||||||
bic r0, #(1<<12) @ - instruction cache disable
|
bic r4, #(1<<12) @ - instruction cache disable
|
||||||
bic r0, #(1<<2) @ - data cache disable
|
bic r4, #(1<<2) @ - data cache disable
|
||||||
bic r0, #(1<<0) @ - mpu disable
|
bic r4, #(1<<0) @ - mpu disable
|
||||||
mcr p15, 0, r0, c1, c0, 0 @ write control register
|
mcr p15, 0, r4, c1, c0, 0 @ write control register
|
||||||
|
|
||||||
@ Flush caches
|
@ Flush caches
|
||||||
bl flushEntireDCache
|
bl flushEntireDCache
|
||||||
bl flushEntireICache
|
bl flushEntireICache
|
||||||
|
|
||||||
|
push {r0-r3}
|
||||||
|
|
||||||
@ Give read/write access to all the memory regions
|
@ Give read/write access to all the memory regions
|
||||||
ldr r0, =0x3333333
|
ldr r0, =0x3333333
|
||||||
mcr p15, 0, r0, c5, c0, 2 @ write data access
|
mcr p15, 0, r0, c5, c0, 2 @ write data access
|
||||||
@ -98,4 +97,5 @@ start:
|
|||||||
sub r2, r0
|
sub r2, r0
|
||||||
bl memset32
|
bl memset32
|
||||||
|
|
||||||
|
pop {r0-r3}
|
||||||
b main
|
b main
|
||||||
|
@ -115,4 +115,5 @@ typedef enum FirmwareType
|
|||||||
NATIVE_FIRM1X2X
|
NATIVE_FIRM1X2X
|
||||||
} FirmwareType;
|
} FirmwareType;
|
||||||
|
|
||||||
extern u16 launchedFirmTidLow[8]; //Defined in start.s
|
extern u16 launchedFirmTidLow[8];
|
||||||
|
extern u16 launchedPath[42];
|
||||||
|
Reference in New Issue
Block a user