diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 172c32be0..2dd220348 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -23,7 +23,7 @@ **Entrypoint (How/what you're using to boot Luma3DS):** -[e.g. Boot9Strap, Sighax, etc.] +[e.g. Boot9Strap/Sighax, etc.] **Luma3DS version:** @@ -62,13 +62,10 @@ Show NAND or user string in System Settings: ( ) Show GBA boot screen in patched AGB_FIRM: ( ) -Patch SVC/service/archive/ARM9 access: ( ) +Patch ARM9 access: ( ) Set developer UNITINFO: ( ) -Enable exception handlers: ( ) - - -- diff --git a/.gitignore b/.gitignore index 1bd840ecd..90f67624e 100644 --- a/.gitignore +++ b/.gitignore @@ -3,10 +3,16 @@ build arm11/build sysmodules/loader/build chainloader/build +rosalina/build exceptions/arm9/build exceptions/arm11/build +.vscode +.vscode/** *.bin *.firm *.o *.d -*.elf \ No newline at end of file +*.elf +*.cxi +*.bmp +*.dmp diff --git a/Makefile b/Makefile index 1dbf6b830..bd17bf4f3 100644 --- a/Makefile +++ b/Makefile @@ -4,21 +4,33 @@ ifeq ($(strip $(DEVKITARM)),) $(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") endif +ifneq ($(strip $(shell firmtool -v 2>&1 | grep usage)),) +$(error "Please install firmtool v1.1 or greater") +endif + include $(DEVKITARM)/base_tools name := Luma3DS revision := $(shell git describe --tags --match v[0-9]* --abbrev=8 | sed 's/-[0-9]*-g/-/i') commit := $(shell git rev-parse --short=8 HEAD) +ifeq ($(strip $(revision)),) + revision := v0.0.0-0 +endif + +ifeq ($(strip $(commit)),) + commit := 0 +endif + dir_source := source dir_patches := patches dir_arm11 := arm11 dir_chainloader := chainloader dir_exceptions := exceptions dir_arm9_exceptions := $(dir_exceptions)/arm9 -dir_arm11_exceptions := $(dir_exceptions)/arm11 dir_sysmodules := sysmodules dir_loader := $(dir_sysmodules)/loader +dir_rosalina := $(dir_sysmodules)/rosalina dir_build := build dir_out := out @@ -30,10 +42,10 @@ 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 $(dir_build)/svcGetCFWInfo.bin.o $(dir_build)/k11modules.bin.o \ - $(dir_build)/chainloader.bin.o $(dir_build)/arm9_exceptions.bin.o $(dir_build)/arm11_exceptions.bin.o +bundled = $(dir_build)/reboot.bin.o $(dir_build)/emunand.bin.o $(dir_build)/mmuHook.bin.o $(dir_build)/k11MainHook.bin.o $(dir_build)/svcConnectToPortInitHook.bin.o $(dir_build)/svcCustomBackdoor.bin.o\ + $(dir_build)/chainloader.bin.o $(dir_build)/arm9_exceptions.bin.o -modules = $(dir_build)/loader.cxi +modules = $(dir_build)/loader.cxi $(dir_build)/rosalina.cxi define bin2o bin2s $< | $(AS) -o $(@) @@ -53,8 +65,8 @@ clean: @$(MAKE) -C $(dir_arm11) clean @$(MAKE) -C $(dir_chainloader) clean @$(MAKE) -C $(dir_arm9_exceptions) clean - @$(MAKE) -C $(dir_arm11_exceptions) clean @$(MAKE) -C $(dir_loader) clean + @$(MAKE) -C $(dir_rosalina) clean @rm -rf $(dir_out) $(dir_build) .PRECIOUS: $(dir_build)/%.bin @@ -62,8 +74,8 @@ clean: .PHONY: $(dir_arm11) .PHONY: $(dir_chainloader) .PHONY: $(dir_arm9_exceptions) -.PHONY: $(dir_arm11_exceptions) .PHONY: $(dir_loader) +.PHONY: $(dir_rosalina) $(dir_out)/$(name)$(revision).7z: all @mkdir -p "$(@D)" @@ -71,7 +83,7 @@ $(dir_out)/$(name)$(revision).7z: all $(dir_out)/boot.firm: $(dir_build)/modules.bin $(dir_build)/arm11.elf $(dir_build)/main.elf @mkdir -p "$(@D)" - @firmtool build $@ -S nand-retail -D $^ -A 0x1FF60000 -C XDMA XDMA NDMA + @firmtool build $@ -D $^ -A 0x1FF60000 -C XDMA XDMA NDMA $(dir_build)/modules.bin: $(modules) @mkdir -p "$(@D)" @@ -88,6 +100,10 @@ $(dir_build)/loader.cxi: $(dir_loader) @mkdir -p "$(@D)" @$(MAKE) -C $< +$(dir_build)/rosalina.cxi: $(dir_rosalina) + @mkdir -p "$(@D)" + @$(MAKE) -C $< + $(dir_build)/%.bin.o: $(dir_build)/%.bin @$(bin2o) @@ -99,10 +115,6 @@ $(dir_build)/arm9_exceptions.bin: $(dir_arm9_exceptions) @mkdir -p "$(@D)" @$(MAKE) -C $< -$(dir_build)/arm11_exceptions.bin: $(dir_arm11_exceptions) - @mkdir -p "$(@D)" - @$(MAKE) -C $< - $(dir_build)/%.bin: $(dir_patches)/%.s @mkdir -p "$(@D)" @armips $< diff --git a/README.md b/README.md index 4daf8bef6..91df4baa7 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,8 @@ It also allows you to run unauthorized ("homebrew") content by removing signature checks. To use it, you will need a console capable of running homebrew software on the ARM9 processor. We recommend [Plailect's guide](https://3ds.guide/) for details on how to get your system ready. +Since Luma3DS v8.0, Luma3DS has its own in-game menu, triggerable by `L+Start+Select` (see the release notes). + --- ## Compiling diff --git a/arm11/source/main.c b/arm11/source/main.c index cc2a02039..1a9c2c403 100644 --- a/arm11/source/main.c +++ b/arm11/source/main.c @@ -1,5 +1,6 @@ -/** This file is part of Luma3DS -* Copyright (C) 2017 Aurora Wright, TuxSH +/* +* 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 @@ -14,9 +15,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * -* Additional Terms 7.b of GPLv3 applies 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. +* 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. */ /* diff --git a/arm11/source/memory.c b/arm11/source/memory.c index 2df03296a..1828b4459 100644 --- a/arm11/source/memory.c +++ b/arm11/source/memory.c @@ -1,6 +1,6 @@ /* * This file is part of Luma3DS -* Copyright (C) 2016 Aurora Wright, TuxSH +* 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 @@ -15,9 +15,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * -* Additional Terms 7.b of GPLv3 applies 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. +* 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. */ /* diff --git a/arm11/source/memory.h b/arm11/source/memory.h index d2409dc31..d9fa1591f 100644 --- a/arm11/source/memory.h +++ b/arm11/source/memory.h @@ -1,6 +1,6 @@ /* * This file is part of Luma3DS -* Copyright (C) 2016 Aurora Wright, TuxSH +* 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 @@ -15,9 +15,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * -* Additional Terms 7.b of GPLv3 applies 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. +* 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. */ /* diff --git a/arm11/source/start.s b/arm11/source/start.s index a3e4600a9..a6e30f01c 100644 --- a/arm11/source/start.s +++ b/arm11/source/start.s @@ -1,5 +1,5 @@ @ This file is part of Luma3DS -@ Copyright (C) 2017 Aurora Wright, TuxSH +@ 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 @@ -14,9 +14,13 @@ @ You should have received a copy of the GNU General Public License @ along with this program. If not, see . @ -@ Additional Terms 7.b of GPLv3 applies 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. +@ 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. .section .text.start .align 4 diff --git a/arm11/source/types.h b/arm11/source/types.h index a07e2ef7c..e8af14fdb 100644 --- a/arm11/source/types.h +++ b/arm11/source/types.h @@ -1,6 +1,6 @@ /* * This file is part of Luma3DS -* Copyright (C) 2017 Aurora Wright, TuxSH +* 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 @@ -15,9 +15,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * -* Additional Terms 7.b of GPLv3 applies 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. +* 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 diff --git a/chainloader/source/cache.h b/chainloader/source/cache.h index 8f80b43af..d5e03cc5a 100644 --- a/chainloader/source/cache.h +++ b/chainloader/source/cache.h @@ -1,6 +1,6 @@ /* * This file is part of Luma3DS -* Copyright (C) 2016 Aurora Wright, TuxSH +* 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 @@ -15,13 +15,17 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * -* Additional Terms 7.b of GPLv3 applies 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. +* 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" -void flushCaches(void); \ No newline at end of file +void flushCaches(void); diff --git a/chainloader/source/cache.s b/chainloader/source/cache.s index c4d6477d2..29e157f5a 100644 --- a/chainloader/source/cache.s +++ b/chainloader/source/cache.s @@ -1,5 +1,5 @@ @ This file is part of Luma3DS -@ Copyright (C) 2016 Aurora Wright, TuxSH +@ 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 @@ -14,9 +14,13 @@ @ You should have received a copy of the GNU General Public License @ along with this program. If not, see . @ -@ Additional Terms 7.b of GPLv3 applies 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. +@ 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. .text .arm diff --git a/chainloader/source/firm.c b/chainloader/source/firm.c index c1b91566f..54842b3ba 100644 --- a/chainloader/source/firm.c +++ b/chainloader/source/firm.c @@ -1,6 +1,6 @@ /* * This file is part of Luma3DS -* Copyright (C) 2017 Aurora Wright, TuxSH +* 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 @@ -15,9 +15,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * -* Additional Terms 7.b of GPLv3 applies 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. +* 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. */ #include "firm.h" diff --git a/chainloader/source/firm.h b/chainloader/source/firm.h index 47dc7ba75..0f9c84d0b 100644 --- a/chainloader/source/firm.h +++ b/chainloader/source/firm.h @@ -1,6 +1,6 @@ /* * This file is part of Luma3DS -* Copyright (C) 2017 Aurora Wright, TuxSH +* 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 @@ -15,9 +15,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * -* Additional Terms 7.b of GPLv3 applies 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. +* 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 diff --git a/chainloader/source/main.c b/chainloader/source/main.c index bb1e5e15d..302a1dfda 100644 --- a/chainloader/source/main.c +++ b/chainloader/source/main.c @@ -1,6 +1,6 @@ /* * This file is part of Luma3DS -* Copyright (C) 2016 Aurora Wright, TuxSH +* 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 @@ -15,9 +15,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * -* Additional Terms 7.b of GPLv3 applies 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. +* 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. */ #include "memory.h" diff --git a/chainloader/source/memory.c b/chainloader/source/memory.c index b6aefe1c6..5f207070f 100644 --- a/chainloader/source/memory.c +++ b/chainloader/source/memory.c @@ -1,6 +1,6 @@ /* * This file is part of Luma3DS -* Copyright (C) 2016 Aurora Wright, TuxSH +* 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 @@ -15,9 +15,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * -* Additional Terms 7.b of GPLv3 applies 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. +* 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. */ /* @@ -33,4 +37,4 @@ void memcpy(void *dest, const void *src, u32 size) for(u32 i = 0; i < size; i++) destc[i] = srcc[i]; -} \ No newline at end of file +} diff --git a/chainloader/source/memory.h b/chainloader/source/memory.h index da8751aef..2e120c48b 100644 --- a/chainloader/source/memory.h +++ b/chainloader/source/memory.h @@ -1,6 +1,6 @@ /* * This file is part of Luma3DS -* Copyright (C) 2016 Aurora Wright, TuxSH +* 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 @@ -15,9 +15,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * -* Additional Terms 7.b of GPLv3 applies 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. +* 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. */ /* @@ -28,4 +32,4 @@ #include "types.h" -void memcpy(void *dest, const void *src, u32 size); \ No newline at end of file +void memcpy(void *dest, const void *src, u32 size); diff --git a/chainloader/source/start.s b/chainloader/source/start.s index b598d71e1..60f149e8b 100644 --- a/chainloader/source/start.s +++ b/chainloader/source/start.s @@ -1,5 +1,5 @@ @ This file is part of Luma3DS -@ Copyright (C) 2017 Aurora Wright, TuxSH +@ 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 @@ -14,10 +14,13 @@ @ You should have received a copy of the GNU General Public License @ along with this program. If not, see . @ -@ Additional Terms 7.b of GPLv3 applies 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. - +@ 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. .arm .section .text.start diff --git a/chainloader/source/types.h b/chainloader/source/types.h index e6f12163c..c4565be6d 100644 --- a/chainloader/source/types.h +++ b/chainloader/source/types.h @@ -1,6 +1,6 @@ /* * This file is part of Luma3DS -* Copyright (C) 2016 Aurora Wright, TuxSH +* 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 @@ -15,9 +15,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * -* Additional Terms 7.b of GPLv3 applies 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. +* 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 diff --git a/exceptions/arm11/source/handlers.s b/exceptions/arm11/source/handlers.s deleted file mode 100644 index 696077c07..000000000 --- a/exceptions/arm11/source/handlers.s +++ /dev/null @@ -1,151 +0,0 @@ -@ This file is part of Luma3DS -@ Copyright (C) 2016 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 . -@ -@ Additional Terms 7.b of GPLv3 applies 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. - -.macro GEN_HANDLER name - .global \name - .type \name, %function - \name: - ldr sp, =#0xffff3000 - stmfd sp!, {r0-r7} - mov r1, #\@ @ macro expansion counter - b _commonHandler - - .size \name, . - \name -.endm - -.text -.arm -.align 4 - -.global _commonHandler -.type _commonHandler, %function -_commonHandler: - clrex - cpsid aif - mrs r2, spsr - mov r6, sp - mrs r3, cpsr - - tst r2, #0x20 - bne noFPUInitNorSvcBreak - sub r0, lr, #4 - stmfd sp!, {lr} - bl cannotAccessVA - ldmfd sp!, {lr} - cmp r0, #0 - bne noFPUInitNorSvcBreak - ldr r4, [lr, #-4] - cmp r1, #1 - bne noFPUInit - - lsl r4, #4 - sub r4, #0xc0000000 - cmp r4, #0x30000000 - bcs noFPUInitNorSvcBreak - fmrx r0, fpexc - tst r0, #0x40000000 - bne noFPUInitNorSvcBreak - - sub lr, #4 - srsfd sp!, #0x13 - ldmfd sp!, {r0-r7} @ restore context - cps #0x13 @ FPU init - stmfd sp, {r0-r3, r11-lr}^ - sub sp, #0x20 - bl . @ will be replaced - ldmfd sp, {r0-r3, r11-lr}^ - add sp, #0x20 - rfefd sp! - - noFPUInit: - cmp r1, #2 - bne noFPUInitNorSvcBreak - ldr r5, =#0xe12fff7f - cmp r4, r5 - bne noFPUInitNorSvcBreak - cps #0x13 @ switch to supervisor mode - cmp r10, #0 - addne sp, #0x28 - ldmfd sp, {r8-r11}^ @ implementation details of the official svc handler - ldr r2, [sp, #0x1c] - ldr r4, [sp, #0x18] - msr cpsr_c, r3 @ restore processor mode - tst r2, #0x20 - addne lr, r4, #2 @ adjust address for later - moveq lr, r4 - - noFPUInitNorSvcBreak: - ands r4, r2, #0xf @ get the mode that triggered the exception - moveq r4, #0xf @ usr => sys - bic r5, r3, #0xf - orr r5, r4 - msr cpsr_c, r5 @ change processor mode - stmfd r6!, {r8-lr} - msr cpsr_c, r3 @ restore processor mode - mov sp, r6 - - stmfd sp!, {r2,lr} - - mrc p15,0,r4,c5,c0,0 @ dfsr - mrc p15,0,r5,c5,c0,1 @ ifsr - mrc p15,0,r6,c6,c0,0 @ far - fmrx r7, fpexc - fmrx r8, fpinst - fmrx r9, fpinst2 - - stmfd sp!, {r4-r9} @ it's a bit of a mess, but we will fix that later - @ order of saved regs now: dfsr, ifsr, far, fpexc, fpinst, fpinst2, cpsr, pc + (2/4/8), r8-r14, r0-r7 - - bic r3, #(1<<31) - fmxr fpexc, r3 @ clear the VFP11 exception flag (if it's set) - - mov r0, sp - mrc p15,0,r2,c0,c0,5 @ CPU ID register - - b mainHandler - -GEN_HANDLER FIQHandler -GEN_HANDLER undefinedInstructionHandler -GEN_HANDLER prefetchAbortHandler -GEN_HANDLER dataAbortHandler - -.global mcuReboot -.type mcuReboot, %function -mcuReboot: - b . @ will be replaced - -.global cleanInvalidateDCacheAndDMB -.type cleanInvalidateDCacheAndDMB, %function -cleanInvalidateDCacheAndDMB: - mov r0, #0 - mcr p15,0,r0,c7,c14,0 @ Clean and Invalidate Entire Data Cache - mcr p15,0,r0,c7,c10,4 @ Drain Memory Barrier - bx lr - -.global cannotAccessVA -.type cannotAccessVA, %function -cannotAccessVA: - @ Thanks yellows8 for the hint - lsr r0, #12 - lsl r0, #12 - mcr p15,0,r0,c7,c8,0 @ VA to PA translation with privileged read permission check - mrc p15,0,r0,c7,c4,0 @ read PA register - and r0, #1 @ failure bit - bx lr diff --git a/exceptions/arm11/source/mainHandler.c b/exceptions/arm11/source/mainHandler.c deleted file mode 100644 index 22e53d8e5..000000000 --- a/exceptions/arm11/source/mainHandler.c +++ /dev/null @@ -1,109 +0,0 @@ -/* -* This file is part of Luma3DS -* Copyright (C) 2016 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 . -* -* Additional Terms 7.b of GPLv3 applies 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. -*/ - -#include "handlers.h" - -#define REG_DUMP_SIZE 4 * 23 -#define CODE_DUMP_SIZE 48 - -#define CODESET_OFFSET 0xBEEFBEEF - -static u32 __attribute__((noinline)) copyMemory(void *dst, const void *src, u32 size, u32 alignment) -{ - u8 *out = (u8 *)dst; - const u8 *in = (const u8 *)src; - - if(((u32)src & (alignment - 1)) != 0 || cannotAccessVA(src) || (size != 0 && cannotAccessVA((u8 *)src + size - 1))) - return 0; - - for(u32 i = 0; i < size; i++) - *out++ = *in++; - - return size; -} - -void __attribute__((noreturn)) mainHandler(u32 *regs, u32 type, u32 cpuId) -{ - ExceptionDumpHeader dumpHeader; - - u32 registerDump[REG_DUMP_SIZE / 4]; - u8 codeDump[CODE_DUMP_SIZE]; - u8 *finalBuffer = cannotAccessVA((void *)0xE5000000) ? (u8 *)0xF5000000 : (u8 *)0xE5000000; //VA for 0x25000000 - u8 *final = finalBuffer; - - while(*(vu32 *)final == 0xDEADC0DE && *((vu32 *)final + 1) == 0xDEADCAFE); - - dumpHeader.magic[0] = 0xDEADC0DE; - dumpHeader.magic[1] = 0xDEADCAFE; - dumpHeader.versionMajor = 1; - dumpHeader.versionMinor = 2; - - dumpHeader.processor = 11; - dumpHeader.core = cpuId & 0xF; - dumpHeader.type = type; - - dumpHeader.registerDumpSize = REG_DUMP_SIZE; - dumpHeader.codeDumpSize = CODE_DUMP_SIZE; - - //Dump registers - //Current order of saved regs: dfsr, ifsr, far, fpexc, fpinst, fpinst2, cpsr, pc, r8-r12, sp, lr, r0-r7 - u32 cpsr = regs[6]; - u32 pc = regs[7] - (type < 3 ? (((cpsr & 0x20) != 0 && type == 1) ? 2 : 4) : 0); - - registerDump[15] = pc; - registerDump[16] = cpsr; - for(u32 i = 0; i < 6; i++) registerDump[17 + i] = regs[i]; - for(u32 i = 0; i < 7; i++) registerDump[8 + i] = regs[8 + i]; - for(u32 i = 0; i < 8; i++) registerDump[i] = regs[15 + i]; - - //Dump code - u8 *instr = (u8 *)pc + ((cpsr & 0x20) ? 2 : 4) - dumpHeader.codeDumpSize; //Doesn't work well on 32-bit Thumb instructions, but it isn't much of a problem - dumpHeader.codeDumpSize = copyMemory(codeDump, instr, dumpHeader.codeDumpSize, ((cpsr & 0x20) != 0) ? 2 : 4); - - //Copy register dump and code dump - final = (u8 *)(finalBuffer + sizeof(ExceptionDumpHeader)); - final += copyMemory(final, registerDump, dumpHeader.registerDumpSize, 1); - final += copyMemory(final, codeDump, dumpHeader.codeDumpSize, 1); - - //Dump stack in place - dumpHeader.stackDumpSize = copyMemory(final, (const void *)registerDump[13], 0x1000 - (registerDump[13] & 0xFFF), 1); - final += dumpHeader.stackDumpSize; - - if(!cannotAccessVA((void *)0xFFFF9004)) - { - vu64 *additionalData = (vu64 *)final; - dumpHeader.additionalDataSize = 16; - vu8 *currentKCodeSet = *(vu8 **)(*(vu8 **)0xFFFF9004 + CODESET_OFFSET); //currentKProcess + CodeSet - - additionalData[0] = *(vu64 *)(currentKCodeSet + 0x50); //Process name - additionalData[1] = *(vu64 *)(currentKCodeSet + 0x5C); //Title ID - } - else dumpHeader.additionalDataSize = 0; - - dumpHeader.totalSize = sizeof(ExceptionDumpHeader) + dumpHeader.registerDumpSize + dumpHeader.codeDumpSize + dumpHeader.stackDumpSize + dumpHeader.additionalDataSize; - - //Copy header (actually optimized by the compiler) - *(ExceptionDumpHeader *)finalBuffer = dumpHeader; - - cleanInvalidateDCacheAndDMB(); - mcuReboot(); //Also contains DCache-cleaning code -} diff --git a/exceptions/arm9/source/handlers.h b/exceptions/arm9/source/handlers.h index 6a577ba3c..315723a3c 100644 --- a/exceptions/arm9/source/handlers.h +++ b/exceptions/arm9/source/handlers.h @@ -1,6 +1,6 @@ /* * This file is part of Luma3DS -* Copyright (C) 2016 Aurora Wright, TuxSH +* 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 @@ -15,9 +15,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * -* Additional Terms 7.b of GPLv3 applies 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. +* 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 @@ -43,4 +47,4 @@ u32 readMPUConfig(u32 *regionSettings); void FIQHandler(void); void undefinedInstructionHandler(void); void dataAbortHandler(void); -void prefetchAbortHandler(void); \ No newline at end of file +void prefetchAbortHandler(void); diff --git a/exceptions/arm9/source/handlers.s b/exceptions/arm9/source/handlers.s index 12b4491fd..f8a50fe65 100644 --- a/exceptions/arm9/source/handlers.s +++ b/exceptions/arm9/source/handlers.s @@ -1,5 +1,5 @@ @ This file is part of Luma3DS -@ Copyright (C) 2016 Aurora Wright, TuxSH +@ 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 @@ -14,9 +14,13 @@ @ You should have received a copy of the GNU General Public License @ along with this program. If not, see . @ -@ Additional Terms 7.b of GPLv3 applies 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. +@ 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. .macro GEN_HANDLER name .global \name diff --git a/exceptions/arm9/source/i2c.c b/exceptions/arm9/source/i2c.c index f2b479d75..2bf6c540a 100644 --- a/exceptions/arm9/source/i2c.c +++ b/exceptions/arm9/source/i2c.c @@ -1,6 +1,6 @@ /* * This file is part of Luma3DS -* Copyright (C) 2016 Aurora Wright, TuxSH +* 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 @@ -15,13 +15,17 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * -* Additional Terms 7.b of GPLv3 applies 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. +* 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. */ /* -* Thanks to the everyone who contributed in the development of this file +* Thanks to whoever contributed in the development of this file */ #include "i2c.h" @@ -136,4 +140,4 @@ bool i2cWriteRegister(u8 dev_id, u8 reg, u8 data) } return false; -} \ No newline at end of file +} diff --git a/exceptions/arm9/source/i2c.h b/exceptions/arm9/source/i2c.h index 0099d61a1..7aa8bf52a 100644 --- a/exceptions/arm9/source/i2c.h +++ b/exceptions/arm9/source/i2c.h @@ -1,6 +1,6 @@ /* * This file is part of Luma3DS -* Copyright (C) 2016 Aurora Wright, TuxSH +* 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 @@ -15,13 +15,17 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * -* Additional Terms 7.b of GPLv3 applies 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. +* 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. */ /* -* Thanks to the everyone who contributed in the development of this file +* Thanks to whoever contributed in the development of this file */ #pragma once @@ -41,4 +45,4 @@ #define I2C_DEV_GYRO 10 #define I2C_DEV_IR 13 -bool i2cWriteRegister(u8 dev_id, u8 reg, u8 data); \ No newline at end of file +bool i2cWriteRegister(u8 dev_id, u8 reg, u8 data); diff --git a/exceptions/arm9/source/mainHandler.c b/exceptions/arm9/source/mainHandler.c index 5023f6de5..8a3f98840 100644 --- a/exceptions/arm9/source/mainHandler.c +++ b/exceptions/arm9/source/mainHandler.c @@ -1,6 +1,6 @@ /* * This file is part of Luma3DS -* Copyright (C) 2016 Aurora Wright, TuxSH +* 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 @@ -15,9 +15,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * -* Additional Terms 7.b of GPLv3 applies 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. +* 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. */ #include "i2c.h" @@ -115,4 +119,4 @@ void __attribute__((noreturn)) mainHandler(u32 *regs, u32 type) ((void (*)())0xFFFF0830)(); //Ensure that all memory transfers have completed and that the data cache has been flushed i2cWriteRegister(I2C_DEV_MCU, 0x20, 1 << 2); //Reboot while(true); -} \ No newline at end of file +} diff --git a/exceptions/arm9/source/start.s b/exceptions/arm9/source/start.s index 3d320067e..80f70f730 100644 --- a/exceptions/arm9/source/start.s +++ b/exceptions/arm9/source/start.s @@ -1,5 +1,5 @@ @ This file is part of Luma3DS -@ Copyright (C) 2016 Aurora Wright, TuxSH +@ 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 @@ -14,9 +14,13 @@ @ You should have received a copy of the GNU General Public License @ along with this program. If not, see . @ -@ Additional Terms 7.b of GPLv3 applies 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. +@ 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. .section .text.start .align 4 diff --git a/exceptions/arm9/source/types.h b/exceptions/arm9/source/types.h index 2b89edbd4..fe5067cb9 100644 --- a/exceptions/arm9/source/types.h +++ b/exceptions/arm9/source/types.h @@ -1,6 +1,6 @@ /* * This file is part of Luma3DS -* Copyright (C) 2016 Aurora Wright, TuxSH +* 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 @@ -15,9 +15,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * -* Additional Terms 7.b of GPLv3 applies 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. +* 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 @@ -34,4 +38,4 @@ 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 +typedef volatile u64 vu64; diff --git a/patches/k11MainHook.s b/patches/k11MainHook.s new file mode 100644 index 000000000..1791c762e --- /dev/null +++ b/patches/k11MainHook.s @@ -0,0 +1,73 @@ +.arm.little + +.create "build/k11MainHook.bin", 0 +.arm + +bindSGI0: + ; hook __kernel_main to bind SGI0 for own purposes + push {r0-r4, lr} + sub sp, #16 ; 3 args passed through the stack + alignment + ldr r0, [interruptManager] + adr r1, interruptEvent + mov r2, #0 + mrc p15, 0, r3, c0, c0, 5 + and r3, #3 + mov r4, #0 + str r4, [sp] + str r4, [sp, #4] + str r4, [sp, #8] + + ldr r12, [InterruptManager_mapInterrupt] + blx r12 + cmp r0, #0 + blt . + + add sp, #16 + pop {r0-r4, pc} + +executeCustomHandler: + push {r4, lr} + mrs r4, cpsr + adr r0, customHandler + bl convertVAToPA + orr r0, #(1 << 31) + ldr r12, [r0] + + blx r12 + + mov r0, #0 + msr cpsr_cx, r4 + pop {r4, pc} + +convertVAToPA: + mov r1, #0x1000 + sub r1, #1 + and r2, r0, r1 + bic r0, r1 + mcr p15, 0, r0, c7, c8, 0 ; VA to PA translation with privileged read permission check + mrc p15, 0, r0, c7, c4, 0 ; read PA register + tst r0, #1 ; failure bit + bic r0, r1 + addeq r0, r2 + movne r0, #0 + bx lr + +.pool + +; Result InterruptManager::mapInterrupt(InterruptManager *this, InterruptEvent *iEvent, u32 interruptID, u32 coreID, s32 priority, bool willBeMasked, bool isLevelHighActive); +InterruptManager_mapInterrupt: .ascii "bind" + +_vtable: .word executeCustomHandler +interruptEvent: .word _vtable + +parameters: +customHandler: .ascii "hdlr" +interruptManager: .word 0 +L2MMUTable: .word 0 +funcs: .word 0,0,0 +TTBCR: .word 0 +L1MMUTableAddrs: .word 0,0,0,0 +kernelVersion: .word 0 +CFWInfo: .word 0,0,0,0 + +.close diff --git a/patches/k11modules.s b/patches/k11modules.s deleted file mode 100644 index 525d0d5a2..000000000 --- a/patches/k11modules.s +++ /dev/null @@ -1,105 +0,0 @@ -; -; This file is part of Luma3DS -; Copyright (C) 2016 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 . -; -; Additional Terms 7.b of GPLv3 applies 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. -; - -; Code originally from Subv - -.arm.little - -.create "build/k11modules.bin", 0 -.arm - ; This code searches the sm module for a specific byte pattern and patches some of the instructions - ; in the code to disable service access checks when calling srv:GetServiceHandle - - ; It also searches the fs module for archive access check code - - ; Save the registers we'll be using - ; Register contents: - ; r4: Pointer to a pointer to the exheader of the current NCCH - ; r6: Constant 0 - ; SP + 4: Pointer to the memory location where the NCCH text was loaded - - ; Execute the instruction we overwrote in our detour - ldr r0, [r4] - - ; Save the value of the register we use - push {r0-r4} - - ldr r1, [sp, #24] ; Load the .text address - ldr r2, [r0, #0x200] ; Load the low title id of the current NCCH - ldr r0, [r0, #0x18] ; Load the size of the .text - add r0, r1, r0 ; Max bounds of the memory region - - ldr r3, =0x1002 ; Low title id of the sm module - cmp r2, r3 ; Compare the low title id to the id of the sm module - bne fs_patch ; Skip if they're not the same - - ldr r2, =0xE1A01006 ; mov r1, r6 - - loop: - cmp r0, r1 - blo die ; Check if we didn't go past the bounds of the memory region - ldr r3, [r1] - cmp r3, r2 - ldreqh r3, [r1, #4] - cmpeq r3, #5 - addne r1, #4 - bne loop - - ; r1 now contains the start address of the pattern we found - ldr r0, =0xE3A00001 ; mov r0, #1 - str r0, [r1, #8] ; Patch the bl - b out - - fs_patch: ; patch adapted from BootNTR - ldr r3, =0x1102 ; Low title id of the fs module - cmp r2, r3 ; Compare the low title id to the id of the sm module - bne out ; Skip if they're not the same - - ldr r2, =0x7401 ; strb r1, [r0, #16] - ldr r3, =0x2000 ; movs r0, #0 - - loop_fs: - cmp r0, r1 - blo die - ldrh r4, [r1] - cmp r4, r2 - ldreqh r4, [r1, #2] - cmpeq r4, r3 - addeq r1, #8 - addne r1, #2 - bne loop_fs - - ; r1 now contains the start address of the pattern we found - ldr r0, =0x2001 ; mov r0, #1 - ldr r2, =0x4770 ; bx lr - strh r0, [r1] - strh r2, [r1, #2] - - out: - pop {r0-r4} ; Restore the registers we used - bx lr ; Jump back to whoever called us - - die: - b die - -.pool -.close diff --git a/patches/mmuHook.s b/patches/mmuHook.s new file mode 100644 index 000000000..5a6b9892c --- /dev/null +++ b/patches/mmuHook.s @@ -0,0 +1,36 @@ +.arm.little + +.create "build/mmuHook.bin", 0 +.arm + ; r2 = L1 table + ; Thanks @Dazzozo for giving me that idea + ; Maps physmem so that, if addr is in physmem(0, 0x30000000), it can be accessed uncached&rwx as addr|(1<<31) + ; Save the value of all registers + + push {r0-r1, r3-r7} + mov r0, #0 + mov r1, #0x30000000 ; end address + ldr r3, =#0x40C02 ; supersection (rwx for all) of strongly ordered memory, shared + loop: + orr r4, r0, #0x80000000 + orr r5, r0, r3 + + mov r6, #0 ; + loop2: + add r7, r6, r4,lsr #20 + str r5, [r2, r7,lsl #2] + add r6, #1 + cmp r6, #16 + blo loop2 + + add r0, #0x01000000 + cmp r0, r1 + blo loop + pop {r0-r1, r3-r7} + + mov r3, #0xe0000000 ; instruction that has been patched + bx lr + + +.pool +.close diff --git a/patches/reboot.s b/patches/reboot.s index b2430520a..5d029e4cd 100644 --- a/patches/reboot.s +++ b/patches/reboot.s @@ -120,7 +120,7 @@ fname: .ascii "FILE" orr r0, #0xC0 msr cpsr, r0 - ldr sp, =0x27FFDF00 + ldr sp, =copy_launch_stub_stack_top ldr r0, =copy_launch_stub_addr adr r1, copy_launch_stub diff --git a/patches/svcConnectToPortInitHook.s b/patches/svcConnectToPortInitHook.s new file mode 100644 index 000000000..b5daadd34 --- /dev/null +++ b/patches/svcConnectToPortInitHook.s @@ -0,0 +1,43 @@ +.arm.little + +.create "build/svcConnectToPortInitHook.bin", 0 +.arm + push {r0-r4, lr} + adr r0, jumpAddress + bl convertVAToPA + orr r4, r0, #(1 << 31) + + loop: + ldr r12, [r4] + cmp r12, #0 + bne loop_end + ldr r12, [SleepThread] + ldr r0, =(10 * 1000 * 1000) + mov r1, #0 + blx r12 + b loop + + loop_end: + pop {r0-r4, lr} + bx r12 + +convertVAToPA: + mov r1, #0x1000 + sub r1, #1 + and r2, r0, r1 + bic r0, r1 + mcr p15, 0, r0, c7, c8, 0 ; VA to PA translation with privileged read permission check + mrc p15, 0, r0, c7, c4, 0 ; read PA register + tst r0, #1 ; failure bit + bic r0, r1 + addeq r0, r2 + movne r0, #0 + bx lr + +.pool +_base: .ascii "base" +jumpAddressOrig: .ascii "orig" +SleepThread: .ascii "SlpT" +jumpAddress: .word 0 + +.close diff --git a/patches/svcCustomBackdoor.s b/patches/svcCustomBackdoor.s new file mode 100644 index 000000000..6ab4f5566 --- /dev/null +++ b/patches/svcCustomBackdoor.s @@ -0,0 +1,20 @@ +.arm.little + +.create "build/svcCustomBackdoor.bin", 0 +.arm + +; Result svcCustomBackdoor(void *func, ... ) +svcCustomBackdoor: + b skip_orig +orig: .word 0 +skip_orig: + push {r4, lr} + mov r4, r0 + mov r0, r1 + mov r1, r2 + mov r2, r3 + blx r4 + pop {r4, pc} + +.pool +.close diff --git a/patches/svcGetCFWInfo.s b/patches/svcGetCFWInfo.s deleted file mode 100644 index 66b54e874..000000000 --- a/patches/svcGetCFWInfo.s +++ /dev/null @@ -1,48 +0,0 @@ -; -; This file is part of Luma3DS -; Copyright (C) 2016 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 . -; -; Additional Terms 7.b of GPLv3 applies 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. -; - -.arm.little - -.create "build/svcGetCFWInfo.bin", 0 -.arm - - adr r1, infoStart - add r2, r0, #(infoEnd - infoStart) - - loop: - ldrb r3, [r1], #1 - strbt r3, [r0], #1 - cmp r0, r2 - blo loop - - mov r0, #0 - - bx lr - -.pool -infoStart: - .ascii "LUMA" ; magic - .word 0 ; version - .word 0 ; truncated commit hash - .word 0 ; config -infoEnd: -.close diff --git a/source/3dsheaders.h b/source/3dsheaders.h index bdbbefedd..e9746742b 100644 --- a/source/3dsheaders.h +++ b/source/3dsheaders.h @@ -1,6 +1,6 @@ /* * This file is part of Luma3DS -* Copyright (C) 2016 Aurora Wright, TuxSH +* 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 @@ -15,9 +15,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * -* Additional Terms 7.b of GPLv3 applies 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. +* 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. */ /* diff --git a/source/buttons.h b/source/buttons.h index cd5c87117..0bc78c9b0 100644 --- a/source/buttons.h +++ b/source/buttons.h @@ -1,6 +1,6 @@ /* * This file is part of Luma3DS -* Copyright (C) 2016 Aurora Wright, TuxSH +* 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 @@ -15,9 +15,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * -* Additional Terms 7.b of GPLv3 applies 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. +* 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 @@ -44,4 +48,4 @@ #define SINGLE_PAYLOAD_BUTTONS (DPAD_BUTTONS | BUTTON_B | BUTTON_X | BUTTON_Y) #define L_PAYLOAD_BUTTONS (BUTTON_R1 | BUTTON_A | BUTTON_START | BUTTON_SELECT) #define MENU_BUTTONS (DPAD_BUTTONS | BUTTON_A | BUTTON_START) -#define PIN_BUTTONS (BUTTON_A | BUTTON_B | BUTTON_X | BUTTON_Y | DPAD_BUTTONS | BUTTON_START | BUTTON_SELECT) \ No newline at end of file +#define PIN_BUTTONS (BUTTON_A | BUTTON_B | BUTTON_X | BUTTON_Y | DPAD_BUTTONS | BUTTON_START | BUTTON_SELECT) diff --git a/source/cache.h b/source/cache.h index 85804add7..3d8e31a04 100644 --- a/source/cache.h +++ b/source/cache.h @@ -1,6 +1,6 @@ /* * This file is part of Luma3DS -* Copyright (C) 2016 Aurora Wright, TuxSH +* 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 @@ -15,9 +15,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * -* Additional Terms 7.b of GPLv3 applies 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. +* 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 @@ -36,4 +40,4 @@ void flushEntireDCache(void); //actually: "clean and flush" void flushDCacheRange(void *startAddress, u32 size); void flushEntireICache(void); -void flushICacheRange(void *startAddress, u32 size); \ No newline at end of file +void flushICacheRange(void *startAddress, u32 size); diff --git a/source/cache.s b/source/cache.s index f22270d85..fcc55dcb4 100644 --- a/source/cache.s +++ b/source/cache.s @@ -1,5 +1,5 @@ @ This file is part of Luma3DS -@ Copyright (C) 2016 Aurora Wright, TuxSH +@ 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 @@ -14,9 +14,13 @@ @ You should have received a copy of the GNU General Public License @ along with this program. If not, see . @ -@ Additional Terms 7.b of GPLv3 applies 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. +@ 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. .text .arm diff --git a/source/config.c b/source/config.c index 176a542a8..3019ee03f 100644 --- a/source/config.c +++ b/source/config.c @@ -1,6 +1,6 @@ /* * This file is part of Luma3DS -* Copyright (C) 2016 Aurora Wright, TuxSH +* 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 @@ -15,9 +15,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * -* Additional Terms 7.b of GPLv3 applies 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. +* 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. */ #include "config.h" @@ -87,9 +91,8 @@ void configMenu(bool oldPinStatus, u32 oldPinMode) "( ) Enable game patching", "( ) Show NAND or user string in System Settings", "( ) Show GBA boot screen in patched AGB_FIRM", - "( ) Patch SVC/service/archive/ARM9 access", + "( ) Patch ARM9 access", "( ) Set developer UNITINFO", - "( ) Enable exception handlers" }; const char *optionsDescription[] = { "Select the default EmuNAND.\n\n" @@ -172,11 +175,7 @@ void configMenu(bool oldPinStatus, u32 oldPinMode) "Enable showing the GBA boot screen\n" "when booting GBA games.", - "Disable SVC, service, archive and ARM9\n" - "exheader access checks.\n\n" - "The service and archive patches\n" - "don't work on New 3DS FIRMs between\n" - "9.3 and 10.4.\n\n" + "Disable ARM9 exheader access checks.\n\n" "Only select this if you know what you\n" "are doing!", @@ -187,11 +186,6 @@ void configMenu(bool oldPinStatus, u32 oldPinMode) "and booting some developer software).\n\n" "Only select this if you know what you\n" "are doing!", - - "Enable Luma3DS's ARM9/ARM11 exception\n" - "handlers. Luma3DS should be ran as\n" - "boot.firm.\n\n" - "Useful for debugging." }; struct multiOption { @@ -219,7 +213,6 @@ void configMenu(bool oldPinStatus, u32 oldPinMode) { .visible = true }, { .visible = true }, { .visible = true }, - { .visible = true }, { .visible = true } }; diff --git a/source/config.h b/source/config.h index b5a832ece..24de63d00 100644 --- a/source/config.h +++ b/source/config.h @@ -1,6 +1,6 @@ /* * This file is part of Luma3DS -* Copyright (C) 2016 Aurora Wright, TuxSH +* 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 @@ -15,9 +15,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * -* Additional Terms 7.b of GPLv3 applies 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. +* 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 @@ -30,7 +34,7 @@ #define CONFIG_FILE "config.bin" #define CONFIG_VERSIONMAJOR 1 -#define CONFIG_VERSIONMINOR 11 +#define CONFIG_VERSIONMINOR 12 #define BOOTCFG_NAND BOOTCONFIG(0, 7) #define BOOTCFG_FIRM BOOTCONFIG(3, 7) @@ -42,7 +46,7 @@ enum multiOptions BRIGHTNESS, SPLASH, PIN, - NEWCPU, + NEWCPU }; enum singleOptions @@ -54,8 +58,7 @@ enum singleOptions PATCHVERSTRING, SHOWGBABOOT, PATCHACCESS, - PATCHUNITINFO, - ENABLEEXCEPTIONHANDLERS + PATCHUNITINFO }; typedef enum ConfigurationStatus diff --git a/source/crypto.c b/source/crypto.c index 9d915dff9..330896ca8 100755 --- a/source/crypto.c +++ b/source/crypto.c @@ -1,6 +1,6 @@ /* * This file is part of Luma3DS -* Copyright (C) 2016 Aurora Wright, TuxSH +* 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 @@ -15,9 +15,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * -* Additional Terms 7.b of GPLv3 applies 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. +* 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. */ /* diff --git a/source/crypto.h b/source/crypto.h index 2638a3f9a..63b52635a 100755 --- a/source/crypto.h +++ b/source/crypto.h @@ -1,6 +1,6 @@ /* * This file is part of Luma3DS -* Copyright (C) 2016 Aurora Wright, TuxSH +* 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 @@ -15,9 +15,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * -* Additional Terms 7.b of GPLv3 applies 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. +* 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. */ /* diff --git a/source/draw.c b/source/draw.c index 0cae22c16..f4ac1a471 100644 --- a/source/draw.c +++ b/source/draw.c @@ -1,6 +1,6 @@ /* * This file is part of Luma3DS -* Copyright (C) 2016 Aurora Wright, TuxSH +* 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 @@ -15,9 +15,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * -* Additional Terms 7.b of GPLv3 applies 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. +* 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. */ /* diff --git a/source/draw.h b/source/draw.h index cc0330931..807dd0d6a 100644 --- a/source/draw.h +++ b/source/draw.h @@ -1,6 +1,6 @@ /* * This file is part of Luma3DS -* Copyright (C) 2016 Aurora Wright, TuxSH +* 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 @@ -15,9 +15,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * -* Additional Terms 7.b of GPLv3 applies 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. +* 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. */ /* diff --git a/source/emunand.c b/source/emunand.c index 393ade62a..94be6c17b 100644 --- a/source/emunand.c +++ b/source/emunand.c @@ -1,6 +1,6 @@ /* * This file is part of Luma3DS -* Copyright (C) 2016 Aurora Wright, TuxSH +* 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 @@ -15,9 +15,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * -* Additional Terms 7.b of GPLv3 applies 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. +* 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. */ /* @@ -193,4 +197,4 @@ u32 patchEmuNand(u8 *arm9Section, u32 kernel9Size, u8 *process9Offset, u32 proce ret += patchMpu(arm9Section, kernel9Size); return ret; -} \ No newline at end of file +} diff --git a/source/emunand.h b/source/emunand.h index 06ecaa5af..9fc4cdc83 100644 --- a/source/emunand.h +++ b/source/emunand.h @@ -1,6 +1,6 @@ /* * This file is part of Luma3DS -* Copyright (C) 2016 Aurora Wright, TuxSH +* 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 @@ -15,9 +15,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * -* Additional Terms 7.b of GPLv3 applies 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. +* 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. */ /* @@ -31,4 +35,4 @@ #define ROUND_TO_4MB(a) (((a) + 0x2000 - 1) & (~(0x2000 - 1))) void locateEmuNand(FirmwareSource *nandType); -u32 patchEmuNand(u8 *arm9Section, u32 kernel9Size, u8 *process9Offset, u32 process9Size, u8 *kernel9Address); \ No newline at end of file +u32 patchEmuNand(u8 *arm9Section, u32 kernel9Size, u8 *process9Offset, u32 process9Size, u8 *kernel9Address); diff --git a/source/exceptions.c b/source/exceptions.c index f827ed236..3b879613d 100644 --- a/source/exceptions.c +++ b/source/exceptions.c @@ -1,6 +1,6 @@ /* * This file is part of Luma3DS -* Copyright (C) 2016 Aurora Wright, TuxSH +* 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 @@ -15,9 +15,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * -* Additional Terms 7.b of GPLv3 applies 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. +* 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. */ #include "exceptions.h" @@ -46,65 +50,6 @@ void installArm9Handlers(void) } } -u32 installArm11Handlers(u32 *exceptionsPage, u32 stackAddress, u32 codeSetOffset, u32 *dAbtHandler, u32 dAbtHandlerMemAddress) -{ - u32 *endPos = exceptionsPage + 0x400; - - u32 *initFPU; - for(initFPU = exceptionsPage; initFPU < endPos && *initFPU != 0xE1A0D002; initFPU++); - - u32 *freeSpace; - for(freeSpace = initFPU; freeSpace < endPos && *freeSpace != 0xFFFFFFFF; freeSpace++); - - u32 *mcuReboot; - for(mcuReboot = exceptionsPage; mcuReboot < endPos && *mcuReboot != 0xE3A0A0C2; mcuReboot++); - - if(initFPU == endPos || freeSpace == endPos || mcuReboot == endPos || *(u32 *)((u8 *)freeSpace + arm11_exceptions_bin_size - 36) != 0xFFFFFFFF) return 1; - - initFPU += 3; - mcuReboot -= 2; - - memcpy(freeSpace, arm11_exceptions_bin + 32, arm11_exceptions_bin_size - 32); - - exceptionsPage[1] = MAKE_BRANCH(exceptionsPage + 1, (u8 *)freeSpace + *(u32 *)(arm11_exceptions_bin + 8) - 32); //Undefined Instruction - exceptionsPage[3] = MAKE_BRANCH(exceptionsPage + 3, (u8 *)freeSpace + *(u32 *)(arm11_exceptions_bin + 12) - 32); //Prefetch Abort - exceptionsPage[7] = MAKE_BRANCH(exceptionsPage + 7, (u8 *)freeSpace + *(u32 *)(arm11_exceptions_bin + 4) - 32); //FIQ - - for(u32 *pos = dAbtHandler; *pos != stackAddress; pos++) - { - u32 va_dst = 0xFFFF0000 + (((u8 *)freeSpace + *(u32 *)(arm11_exceptions_bin + 4)) - (u8 *)exceptionsPage); - u32 va_src; - switch(*pos) - { - case 0xF96D0513: //srsdb sp!, 0x13 - va_src = dAbtHandlerMemAddress + ((u8 *)pos - (u8 *)dAbtHandler); - *pos = MAKE_BRANCH((u8 *)va_src, (u8 *)va_dst); - break; - case 0xE29EF004: //subs pc, lr, 4 - pos++; - *pos++ = 0xE8BD000F;// pop {r0-r3} - va_src = dAbtHandlerMemAddress + ((u8 *)pos - (u8 *)dAbtHandler); - *pos = MAKE_BRANCH((u8 *)va_src, (u8 *)va_dst); - break; - } - } - - - for(u32 *pos = freeSpace; pos < (u32 *)((u8 *)freeSpace + arm11_exceptions_bin_size - 32); pos++) - { - switch(*pos) //Perform relocations - { - case 0xFFFF3000: *pos = stackAddress - 0x10; break; - case 0xEBFFFFFE: *pos = MAKE_BRANCH_LINK(pos, initFPU); break; - case 0xEAFFFFFE: *pos = MAKE_BRANCH(pos, mcuReboot); break; - case 0xE12FFF1C: pos[1] = 0xFFFF0000 + 4 * (u32)(freeSpace - exceptionsPage) + pos[1] - 32; break; //bx r12 (mainHandler) - case 0xBEEFBEEF: *pos = codeSetOffset; break; - } - } - - return 0; -} - void detectAndProcessExceptionDumps(void) { volatile ExceptionDumpHeader *dumpHeader = (volatile ExceptionDumpHeader *)0x25000000; diff --git a/source/exceptions.h b/source/exceptions.h index a9aa5b15a..e7fee459f 100644 --- a/source/exceptions.h +++ b/source/exceptions.h @@ -1,6 +1,6 @@ /* * This file is part of Luma3DS -* Copyright (C) 2016 Aurora Wright, TuxSH +* 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 @@ -15,9 +15,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * -* Additional Terms 7.b of GPLv3 applies 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. +* 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 diff --git a/source/fatfs/sdmmc/sdmmc.c b/source/fatfs/sdmmc/sdmmc.c index 6369ac6be..e4c58f42b 100644 --- a/source/fatfs/sdmmc/sdmmc.c +++ b/source/fatfs/sdmmc/sdmmc.c @@ -291,8 +291,6 @@ static u32 calcSDSize(u8 *csd, int type) static void InitSD() { - *(vu32 *)0x10000020 = 0; //InitFS stuff - *(vu32 *)0x10000020 = 0x200; //InitFS stuff *(vu16 *)0x10006100 &= 0xF7FFu; //SDDATACTL32 *(vu16 *)0x10006100 &= 0xEFFFu; //SDDATACTL32 *(vu16 *)0x10006100 |= 0x402u; //SDDATACTL32 diff --git a/source/firm.c b/source/firm.c index 4e369d8a4..f9458dec1 100755 --- a/source/firm.c +++ b/source/firm.c @@ -1,6 +1,6 @@ /* * This file is part of Luma3DS -* Copyright (C) 2016 Aurora Wright, TuxSH +* 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 @@ -15,9 +15,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * -* Additional Terms 7.b of GPLv3 applies 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. +* 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. */ #include "firm.h" @@ -218,13 +222,17 @@ u32 patchNativeFirm(u32 firmVersion, FirmwareSource nandType, bool loadFromStora u32 baseK11VA; u8 *freeK11Space; u32 *arm11SvcHandler, - *arm11DAbtHandler, *arm11ExceptionsPage, - *arm11SvcTable = getKernel11Info(arm11Section1, firm->section[1].size, &baseK11VA, &freeK11Space, &arm11SvcHandler, &arm11DAbtHandler, &arm11ExceptionsPage); + *arm11SvcTable = getKernel11Info(arm11Section1, firm->section[1].size, &baseK11VA, &freeK11Space, &arm11SvcHandler, &arm11ExceptionsPage); u32 kernel9Size = (u32)(process9Offset - arm9Section) - sizeof(Cxi) - 0x200, ret = 0; + installMMUHook(arm11Section1, firm->section[1].size, &freeK11Space); + installK11MainHook(arm11Section1, firm->section[1].size, isSafeMode, baseK11VA, arm11SvcTable, arm11ExceptionsPage, &freeK11Space); + installSvcConnectToPortInitHook(arm11SvcTable, arm11ExceptionsPage, &freeK11Space); + installSvcCustomBackdoor(arm11SvcTable, &freeK11Space, arm11ExceptionsPage); + //Apply signature patches ret += patchSignatureChecks(process9Offset, process9Size); @@ -249,16 +257,8 @@ u32 patchNativeFirm(u32 firmVersion, FirmwareSource nandType, bool loadFromStora { //Apply anti-anti-DG patches ret += patchTitleInstallMinVersionChecks(process9Offset, process9Size, firmVersion); - - //Restore svcBackdoor - ret += reimplementSvcBackdoor(arm11Section1, arm11SvcTable, baseK11VA, &freeK11Space); } - //Stub svc 0x59 on 11.3+ FIRMs - if(firmVersion >= (ISN3DS ? 0x2D : 0x5C)) ret += stubSvcRestrictGpuDma(arm11Section1, arm11SvcTable, baseK11VA); - - ret += implementSvcGetCFWInfo(arm11Section1, arm11SvcTable, baseK11VA, &freeK11Space, isSafeMode); - //Apply UNITINFO patches if(doUnitinfoPatch) { @@ -268,32 +268,14 @@ u32 patchNativeFirm(u32 firmVersion, FirmwareSource nandType, bool loadFromStora if(enableExceptionHandlers) { - //ARM11 exception handlers - u32 codeSetOffset, - stackAddress = getInfoForArm11ExceptionHandlers(arm11Section1, firm->section[1].size, &codeSetOffset); - ret += installArm11Handlers(arm11ExceptionsPage, stackAddress, codeSetOffset, arm11DAbtHandler, baseK11VA + ((u8 *)arm11DAbtHandler - arm11Section1)); - patchSvcBreak11(arm11Section1, arm11SvcTable, baseK11VA); - ret += patchKernel11Panic(arm11Section1, firm->section[1].size); - //ARM9 exception handlers ret += patchArm9ExceptionHandlersInstall(arm9Section, kernel9Size); ret += patchSvcBreak9(arm9Section, kernel9Size, (u32)firm->section[2].address); ret += patchKernel9Panic(arm9Section, kernel9Size); } - bool patchAccess = CONFIG(PATCHACCESS), - patchGames = CONFIG(PATCHGAMES); - - if(patchAccess || patchGames) - { - ret += patchK11ModuleChecks(arm11Section1, firm->section[1].size, &freeK11Space, patchGames); - - if(patchAccess) - { - ret += patchArm11SvcAccessChecks(arm11SvcHandler, (u32 *)(arm11Section1 + firm->section[1].size)); - ret += patchP9AccessChecks(process9Offset, process9Size); - } - } + if(CONFIG(PATCHACCESS)) + ret += patchP9AccessChecks(process9Offset, process9Size); mergeSection0(NATIVE_FIRM, loadFromStorage); firm->section[0].size = 0; diff --git a/source/firm.h b/source/firm.h index 132003813..6bf15dd18 100644 --- a/source/firm.h +++ b/source/firm.h @@ -1,6 +1,6 @@ /* * This file is part of Luma3DS -* Copyright (C) 2016 Aurora Wright, TuxSH +* 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 @@ -15,9 +15,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * -* Additional Terms 7.b of GPLv3 applies 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. +* 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 diff --git a/source/fmt.c b/source/fmt.c index 6a54cc950..718d36f43 100644 --- a/source/fmt.c +++ b/source/fmt.c @@ -1,3 +1,29 @@ +/* +* 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 . +* +* 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. +*/ + /* File : barebones/ee_printf.c This file contains an implementation of ee_printf that only requires a method to output a char to a UART without pulling in library code. diff --git a/source/fmt.h b/source/fmt.h index 94ed5bfc5..56c4e59e5 100644 --- a/source/fmt.h +++ b/source/fmt.h @@ -1,3 +1,29 @@ +/* +* 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 . +* +* 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 "memory.h" #include diff --git a/source/fs.c b/source/fs.c index 63e4759df..f35736cfc 100644 --- a/source/fs.c +++ b/source/fs.c @@ -1,6 +1,6 @@ /* * This file is part of Luma3DS -* Copyright (C) 2016 Aurora Wright, TuxSH +* 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 @@ -15,9 +15,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * -* Additional Terms 7.b of GPLv3 applies 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. +* 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. */ #include "fs.h" diff --git a/source/fs.h b/source/fs.h index da4f27e7a..4e20a5dea 100644 --- a/source/fs.h +++ b/source/fs.h @@ -1,6 +1,6 @@ /* * This file is part of Luma3DS -* Copyright (C) 2016 Aurora Wright, TuxSH +* 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 @@ -15,9 +15,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * -* Additional Terms 7.b of GPLv3 applies 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. +* 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 diff --git a/source/i2c.c b/source/i2c.c index d3dfac789..4ce730052 100644 --- a/source/i2c.c +++ b/source/i2c.c @@ -1,6 +1,6 @@ /* * This file is part of Luma3DS -* Copyright (C) 2016 Aurora Wright, TuxSH +* 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 @@ -15,13 +15,17 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * -* Additional Terms 7.b of GPLv3 applies 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. +* 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. */ /* -* Thanks to the everyone who contributed in the development of this file +* Thanks to whoever contributed in the development of this file */ #include "utils.h" @@ -169,4 +173,4 @@ bool i2cWriteRegister(u8 dev_id, u8 reg, u8 data) wait(3ULL); return ret; -} \ No newline at end of file +} diff --git a/source/i2c.h b/source/i2c.h index f00a3019b..13537b65b 100644 --- a/source/i2c.h +++ b/source/i2c.h @@ -1,6 +1,6 @@ /* * This file is part of Luma3DS -* Copyright (C) 2016 Aurora Wright, TuxSH +* 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 @@ -15,13 +15,17 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * -* Additional Terms 7.b of GPLv3 applies 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. +* 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. */ /* -* Thanks to the everyone who contributed in the development of this file +* Thanks to whoever contributed in the development of this file */ #pragma once @@ -42,4 +46,4 @@ #define I2C_DEV_IR 13 u8 i2cReadRegister(u8 dev_id, u8 reg); -bool i2cWriteRegister(u8 dev_id, u8 reg, u8 data); \ No newline at end of file +bool i2cWriteRegister(u8 dev_id, u8 reg, u8 data); diff --git a/source/main.c b/source/main.c index 056944322..d5f3495c6 100644 --- a/source/main.c +++ b/source/main.c @@ -1,6 +1,6 @@ /* * This file is part of Luma3DS -* Copyright (C) 2016 Aurora Wright, TuxSH +* 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 @@ -15,9 +15,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * -* Additional Terms 7.b of GPLv3 applies 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. +* 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. */ #include "config.h" @@ -284,8 +288,7 @@ void main(int argc, char **argv, u32 magicWord) bool loadFromStorage = CONFIG(LOADEXTFIRMSANDMODULES); u32 firmVersion = loadFirm(&firmType, firmSource, loadFromStorage, isSafeMode); - bool doUnitinfoPatch = CONFIG(PATCHUNITINFO), - enableExceptionHandlers = CONFIG(ENABLEEXCEPTIONHANDLERS); + bool doUnitinfoPatch = CONFIG(PATCHUNITINFO), enableExceptionHandlers = CONFIG(PATCHUNITINFO); u32 res; switch(firmType) { diff --git a/source/memory.c b/source/memory.c index d63dad4d3..fc44871b4 100644 --- a/source/memory.c +++ b/source/memory.c @@ -1,6 +1,6 @@ /* * This file is part of Luma3DS -* Copyright (C) 2016 Aurora Wright, TuxSH +* 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 @@ -15,9 +15,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * -* Additional Terms 7.b of GPLv3 applies 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. +* 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. */ /* @@ -36,12 +40,13 @@ void memcpy(void *dest, const void *src, u32 size) destc[i] = srcc[i]; } -void memset(void *dest, u32 filler, u32 size) +void *memset(void *dest, u32 value, u32 size) { u8 *destc = (u8 *)dest; - for(u32 i = 0; i < size; i++) - destc[i] = (u8)filler; + for(u32 i = 0; i < size; i++) destc[i] = (u8)value; + + return dest; } void memset32(void *dest, u32 filler, u32 size) diff --git a/source/memory.h b/source/memory.h index 38460d692..d5515f236 100644 --- a/source/memory.h +++ b/source/memory.h @@ -1,6 +1,6 @@ /* * This file is part of Luma3DS -* Copyright (C) 2016 Aurora Wright, TuxSH +* 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 @@ -15,9 +15,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * -* Additional Terms 7.b of GPLv3 applies 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. +* 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. */ /* @@ -30,7 +34,7 @@ #include "types.h" void memcpy(void *dest, const void *src, u32 size); -void memset(void *dest, u32 value, u32 size) __attribute__((used)); +void *memset(void *dest, u32 value, u32 size) __attribute__((used)); void memset32(void *dest, u32 filler, u32 size); int memcmp(const void *buf1, const void *buf2, u32 size); u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSize); diff --git a/source/patches.c b/source/patches.c index bfe2e0feb..03364462e 100644 --- a/source/patches.c +++ b/source/patches.c @@ -1,6 +1,6 @@ /* * This file is part of Luma3DS -* Copyright (C) 2016 Aurora Wright, TuxSH +* 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 @@ -15,9 +15,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * -* Additional Terms 7.b of GPLv3 applies 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. +* 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. */ /* @@ -25,13 +29,13 @@ * Signature patches for old FIRMs by SciresM * firmlaunches patching code originally by delebile * FIRM partition writes patches by delebile -* ARM11 modules patching code originally by Subv * Idea for svcBreak patches from yellows8 and others on #3dsdev * TWL_FIRM patches by Steveice10 and others */ #include "patches.h" #include "fs.h" +#include "exceptions.h" #include "memory.h" #include "config.h" #include "utils.h" @@ -51,33 +55,138 @@ u8 *getProcess9Info(u8 *pos, u32 size, u32 *process9Size, u32 *process9MemAddr) return (u8 *)off + (off->ncch.exeFsOffset + 1) * 0x200; } -u32 *getKernel11Info(u8 *pos, u32 size, u32 *baseK11VA, u8 **freeK11Space, u32 **arm11SvcHandler, u32 **arm11DAbtHandler, u32 **arm11ExceptionsPage) +u32 *getKernel11Info(u8 *pos, u32 size, u32 *baseK11VA, u8 **freeK11Space, u32 **arm11SvcHandler, u32 **arm11ExceptionsPage) { - const u8 pattern[] = {0x00, 0xB0, 0x9C, 0xE5}, - pattern2[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; - + const u8 pattern[] = {0x00, 0xB0, 0x9C, 0xE5}; *arm11ExceptionsPage = (u32 *)memsearch(pos, pattern, size, sizeof(pattern)); - *freeK11Space = memsearch(pos, pattern2, size, sizeof(pattern2)); - if(*arm11ExceptionsPage == NULL || *freeK11Space == NULL) error("Failed to get Kernel11 data."); + if(*arm11ExceptionsPage == NULL) error("Failed to get Kernel11 data."); u32 *arm11SvcTable; *arm11ExceptionsPage -= 0xB; u32 svcOffset = (-(((*arm11ExceptionsPage)[2] & 0xFFFFFF) << 2) & (0xFFFFFF << 2)) - 8; //Branch offset + 8 for prefetch - u32 dabtOffset = (-(((*arm11ExceptionsPage)[4] & 0xFFFFFF) << 2) & (0xFFFFFF << 2)) - 8; //Branch offset + 8 for prefetch u32 pointedInstructionVA = 0xFFFF0008 - svcOffset; *baseK11VA = pointedInstructionVA & 0xFFFF0000; //This assumes that the pointed instruction has an offset < 0x10000, iirc that's always the case arm11SvcTable = *arm11SvcHandler = (u32 *)(pos + *(u32 *)(pos + pointedInstructionVA - *baseK11VA + 8) - *baseK11VA); //SVC handler address while(*arm11SvcTable) arm11SvcTable++; //Look for SVC0 (NULL) - pointedInstructionVA = 0xFFFF0010 - dabtOffset; - *arm11DAbtHandler = (u32 *)(pos + *(u32 *)(pos + pointedInstructionVA - *baseK11VA + 8) - *baseK11VA); - (*freeK11Space)++; + u32 *freeSpace; + for(freeSpace = *arm11ExceptionsPage; freeSpace < *arm11ExceptionsPage + 0x400 && *freeSpace != 0xFFFFFFFF; freeSpace++); + *freeK11Space = (u8 *) freeSpace; return arm11SvcTable; } +void installMMUHook(u8 *pos, u32 size, u8 **freeK11Space) +{ + const u8 pattern[] = {0x0E, 0x32, 0xA0, 0xE3, 0x02, 0xC2, 0xA0, 0xE3}; + + u32 *off = (u32 *)memsearch(pos, pattern, size, 8); + + memcpy(*freeK11Space, mmuHook_bin, mmuHook_bin_size); + *off = MAKE_BRANCH_LINK(off, *freeK11Space); + + (*freeK11Space) += mmuHook_bin_size; +} + +void installK11MainHook(u8 *pos, u32 size, bool isSafeMode, u32 baseK11VA, u32 *arm11SvcTable, u32 *arm11ExceptionsPage, u8 **freeK11Space) +{ + const u8 pattern[] = {0x00, 0x00, 0xA0, 0xE1, 0x03, 0xF0, 0x20, 0xE3, 0xFD, 0xFF, 0xFF, 0xEA}; + + u32 *off = (u32 *)memsearch(pos, pattern, size, 12); + // look for cpsie i and place our function call in the nop 2 instructions before + while(*off != 0xF1080080) off--; + off -= 2; + + memcpy(*freeK11Space, k11MainHook_bin, k11MainHook_bin_size); + + u32 relocBase = 0xFFFF0000 + (*freeK11Space - (u8 *)arm11ExceptionsPage); + *off = MAKE_BRANCH_LINK(baseK11VA + ((u8 *)off - pos), relocBase); + + off = (u32 *)(pos + (arm11SvcTable[0x50] - baseK11VA)); //svcBindInterrupt + while(off[0] != 0xE1A05000 || off[1] != 0xE2100102 || off[2] != 0x5A00000B) off++; + off--; + + signed int offset = (*off & 0xFFFFFF) << 2; + offset = offset << 6 >> 6; // sign extend + offset += 8; + + u32 InterruptManager_mapInterrupt = baseK11VA + ((u8 *)off - pos) + offset; + u32 interruptManager = *(u32 *)(off - 4 + (*(off - 6) & 0xFFF) / 4); + + off = (u32 *)memsearch(*freeK11Space, "bind", k11MainHook_bin_size, 4); + + *off++ = InterruptManager_mapInterrupt; + + // Relocate stuff + *off++ += relocBase; + *off++ += relocBase; + off++; + *off++ = interruptManager; + + off += 10; + + struct CfwInfo + { + char magic[4]; + + u8 versionMajor; + u8 versionMinor; + u8 versionBuild; + u8 flags; + + u32 commitHash; + + u32 config; + } __attribute__((packed)) *info = (struct CfwInfo *)off; + + const char *rev = REVISION; + memcpy(&info->magic, "LUMA", 4); + info->commitHash = COMMIT_HASH; + info->config = configData.config; + info->versionMajor = (u8)(rev[1] - '0'); + info->versionMinor = (u8)(rev[3] - '0'); + + if(rev[4] == '.') + info->versionBuild = (u8)(rev[5] - '0'); + + const char *revpos; + for(revpos = rev + 4; *revpos != 0 && *revpos != '-'; revpos++); + bool isRelease = *revpos != '-'; + + if(isRelease) info->flags = 1; + if(ISN3DS) info->flags |= 1 << 4; + if(isSafeMode) info->flags |= 1 << 5; + if(isSdMode) info->flags |= 1 << 6; + + (*freeK11Space) += k11MainHook_bin_size; +} + +void installSvcConnectToPortInitHook(u32 *arm11SvcTable, u32 *arm11ExceptionsPage, u8 **freeK11Space) +{ + u32 addr = 0xFFFF0000 + (u32)*freeK11Space - (u32)arm11ExceptionsPage; + u32 svcSleepThreadAddr = arm11SvcTable[0x0A], svcConnectToPortAddr = arm11SvcTable[0x2D]; + + arm11SvcTable[0x2D] = addr; + memcpy(*freeK11Space, svcConnectToPortInitHook_bin, svcConnectToPortInitHook_bin_size); + + u32 *off = (u32 *)memsearch(*freeK11Space, "orig", svcConnectToPortInitHook_bin_size, 4); + off[0] = svcConnectToPortAddr; + off[1] = svcSleepThreadAddr; + + (*freeK11Space) += svcConnectToPortInitHook_bin_size; +} + + +void installSvcCustomBackdoor(u32 *arm11SvcTable, u8 **freeK11Space, u32 *arm11ExceptionsPage) +{ + memcpy(*freeK11Space, svcCustomBackdoor_bin, svcCustomBackdoor_bin_size); + *((u32 *)*freeK11Space + 1) = arm11SvcTable[0x2F]; // temporary location + arm11SvcTable[0x2F] = 0xFFFF0000 + *freeK11Space - (u8 *)arm11ExceptionsPage; + (*freeK11Space) += svcCustomBackdoor_bin_size; +} + u32 patchSignatureChecks(u8 *pos, u32 size) { //Look for signature checks @@ -264,90 +373,6 @@ u32 patchK11ModuleLoading(u32 section0size, u32 modulesSize, u8 *pos, u32 size) return 0; } -u32 reimplementSvcBackdoor(u8 *pos, u32 *arm11SvcTable, u32 baseK11VA, u8 **freeK11Space) -{ - if(arm11SvcTable[0x7B] != 0) return 0; - - //Official implementation of svcBackdoor - const u8 svcBackdoor[] = {0xFF, 0x10, 0xCD, 0xE3, //bic r1, sp, #0xff - 0x0F, 0x1C, 0x81, 0xE3, //orr r1, r1, #0xf00 - 0x28, 0x10, 0x81, 0xE2, //add r1, r1, #0x28 - 0x00, 0x20, 0x91, 0xE5, //ldr r2, [r1] - 0x00, 0x60, 0x22, 0xE9, //stmdb r2!, {sp, lr} - 0x02, 0xD0, 0xA0, 0xE1, //mov sp, r2 - 0x30, 0xFF, 0x2F, 0xE1, //blx r0 - 0x03, 0x00, 0xBD, 0xE8, //pop {r0, r1} - 0x00, 0xD0, 0xA0, 0xE1, //mov sp, r0 - 0x11, 0xFF, 0x2F, 0xE1}; //bx r1 - - if(*(u32 *)(*freeK11Space + sizeof(svcBackdoor) - 4) != 0xFFFFFFFF) return 1; - - memcpy(*freeK11Space, svcBackdoor, sizeof(svcBackdoor)); - - arm11SvcTable[0x7B] = baseK11VA + *freeK11Space - pos; - *freeK11Space += sizeof(svcBackdoor); - - return 0; -} - -u32 stubSvcRestrictGpuDma(u8 *pos, u32 *arm11SvcTable, u32 baseK11VA) -{ - if(arm11SvcTable[0x59] != 0) - { - u32 *off = (u32 *)(pos + arm11SvcTable[0x59] - baseK11VA); - off[1] = 0xE1A00000; //replace call to inner function by a NOP - } - - return 0; -} - -u32 implementSvcGetCFWInfo(u8 *pos, u32 *arm11SvcTable, u32 baseK11VA, u8 **freeK11Space, bool isSafeMode) -{ - if(*(u32 *)(*freeK11Space + svcGetCFWInfo_bin_size - 4) != 0xFFFFFFFF) return 1; - - memcpy(*freeK11Space, svcGetCFWInfo_bin, svcGetCFWInfo_bin_size); - - struct CfwInfo - { - char magic[4]; - - u8 versionMajor; - u8 versionMinor; - u8 versionBuild; - u8 flags; - - u32 commitHash; - - u32 config; - } __attribute__((packed)) *info = (struct CfwInfo *)memsearch(*freeK11Space, "LUMA", svcGetCFWInfo_bin_size, 4); - - const char *rev = REVISION; - - info->commitHash = COMMIT_HASH; - info->config = configData.config; - info->versionMajor = (u8)(rev[1] - '0'); - info->versionMinor = (u8)(rev[3] - '0'); - - bool isRelease; - - if(rev[4] == '.') - { - info->versionBuild = (u8)(rev[5] - '0'); - isRelease = rev[6] == 0; - } - else isRelease = rev[4] == 0; - - if(isRelease) info->flags = 1; - if(ISN3DS) info->flags |= 1 << 4; - if(isSafeMode) info->flags |= 1 << 5; - if(isSdMode) info->flags |= 1 << 6; - - arm11SvcTable[0x2E] = baseK11VA + *freeK11Space - pos; //Stubbed svc - *freeK11Space += svcGetCFWInfo_bin_size; - - return 0; -} - u32 patchArm9ExceptionHandlersInstall(u8 *pos, u32 size) { const u8 pattern[] = {0x80, 0xE5, 0x40, 0x1C}; @@ -379,22 +404,6 @@ u32 patchArm9ExceptionHandlersInstall(u8 *pos, u32 size) return 0; } -u32 getInfoForArm11ExceptionHandlers(u8 *pos, u32 size, u32 *codeSetOffset) -{ - const u8 pattern[] = {0x1B, 0x50, 0xA0, 0xE3}, //Get TitleID from CodeSet - pattern2[] = {0xE8, 0x13, 0x00, 0x02}; //Call exception dispatcher - - u32 *loadCodeSet = (u32 *)memsearch(pos, pattern, size, sizeof(pattern)); - u8 *temp = memsearch(pos, pattern2, size, sizeof(pattern2)); - - if(loadCodeSet == NULL || temp == NULL) error("Failed to get ARM11 exception handlers data."); - - loadCodeSet -= 2; - *codeSetOffset = *loadCodeSet & 0xFFF; - - return *(u32 *)(temp + 9); -} - u32 patchSvcBreak9(u8 *pos, u32 size, u32 kernel9Address) { //Stub svcBreak with "bkpt 65535" so we can debug the panic @@ -414,13 +423,6 @@ u32 patchSvcBreak9(u8 *pos, u32 size, u32 kernel9Address) return 0; } -void patchSvcBreak11(u8 *pos, u32 *arm11SvcTable, u32 baseK11VA) -{ - //Same as above, for NATIVE_FIRM ARM11 - u32 *addr = (u32 *)(pos + arm11SvcTable[0x3C] - baseK11VA); - *addr = 0xE12FFF7F; -} - u32 patchKernel9Panic(u8 *pos, u32 size) { const u8 pattern[] = {0xFF, 0xEA, 0x04, 0xD0}; @@ -435,19 +437,6 @@ u32 patchKernel9Panic(u8 *pos, u32 size) return 0; } -u32 patchKernel11Panic(u8 *pos, u32 size) -{ - const u8 pattern[] = {0x02, 0x0B, 0x44, 0xE2}; - - u32 *off = (u32 *)memsearch(pos, pattern, size, sizeof(pattern)); - - if(off == NULL) return 1; - - *off = 0xE12FFF7E; - - return 0; -} - u32 patchP9AccessChecks(u8 *pos, u32 size) { const u8 pattern[] = {0x00, 0x08, 0x49, 0x68}; @@ -463,45 +452,6 @@ u32 patchP9AccessChecks(u8 *pos, u32 size) return 0; } -u32 patchArm11SvcAccessChecks(u32 *arm11SvcHandler, u32 *endPos) -{ - while(*arm11SvcHandler != 0xE11A0E1B && arm11SvcHandler < endPos) arm11SvcHandler++; //TST R10, R11,LSL LR - - if(arm11SvcHandler == endPos) return 1; - - *arm11SvcHandler = 0xE3B0A001; //MOVS R10, #1 - - return 0; -} - -u32 patchK11ModuleChecks(u8 *pos, u32 size, u8 **freeK11Space, bool patchGames) -{ - /* We have to detour a function in the ARM11 kernel because builtin modules - are compressed in memory and are only decompressed at runtime */ - - //Check that we have enough free space - if(*(u32 *)(*freeK11Space + k11modules_bin_size - 4) != 0xFFFFFFFF) return patchGames ? 1 : 0; - - //Look for the code that decompresses the .code section of the builtin modules - const u8 pattern[] = {0xE5, 0x48, 0x00, 0x9D}; - - u8 *temp = memsearch(pos, pattern, size, sizeof(pattern)); - - if(temp == NULL) return 1; - - //Inject our code into the free space - memcpy(*freeK11Space, k11modules_bin, k11modules_bin_size); - - u32 *off = (u32 *)(temp - 0xB); - - //Inject a jump (BL) instruction to our code at the offset we found - *off = 0xEB000000 | (((((u32)*freeK11Space) - ((u32)off + 8)) >> 2) & 0xFFFFFF); - - *freeK11Space += k11modules_bin_size; - - return 0; -} - u32 patchUnitInfoValueSet(u8 *pos, u32 size) { //Look for UNITINFO value being set during kernel sync diff --git a/source/patches.h b/source/patches.h index c93656fe9..4574447c2 100644 --- a/source/patches.h +++ b/source/patches.h @@ -1,6 +1,6 @@ /* * This file is part of Luma3DS -* Copyright (C) 2016 Aurora Wright, TuxSH +* 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 @@ -15,9 +15,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * -* Additional Terms 7.b of GPLv3 applies 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. +* 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. */ /* @@ -25,7 +29,6 @@ * Signature patches for old FIRMs by SciresM * firmlaunches patching code originally by delebile * FIRM partition writes patches by delebile -* ARM11 modules patching code originally by Subv * Idea for svcBreak patches from yellows8 and others on #3dsdev * TWL_FIRM patches by Steveice10 and others */ @@ -37,7 +40,11 @@ extern CfgData configData; u8 *getProcess9Info(u8 *pos, u32 size, u32 *process9Size, u32 *process9MemAddr); -u32 *getKernel11Info(u8 *pos, u32 size, u32 *baseK11VA, u8 **freeK11Space, u32 **arm11SvcHandler, u32 **arm11DAbtHandler, u32 **arm11ExceptionsPage); +u32 *getKernel11Info(u8 *pos, u32 size, u32 *baseK11VA, u8 **freeK11Space, u32 **arm11SvcHandler, u32 **arm11ExceptionsPage); +void installMMUHook(u8 *pos, u32 size, u8 **freeK11Space); +void installK11MainHook(u8 *pos, u32 size, bool isSafeMode, u32 baseK11VA, u32 *arm11SvcTable, u32 *arm11ExceptionsPage, u8 **freeK11Space); +void installSvcConnectToPortInitHook(u32 *arm11SvcTable, u32 *arm11ExceptionsPage, u8 **freeK11Space); +void installSvcCustomBackdoor(u32 *arm11SvcTable, u8 **freeK11Space, u32 *arm11ExceptionsPage); u32 patchSignatureChecks(u8 *pos, u32 size); u32 patchOldSignatureChecks(u8 *pos, u32 size); u32 patchFirmlaunches(u8 *pos, u32 size, u32 process9MemAddr); @@ -46,20 +53,12 @@ u32 patchOldFirmWrites(u8 *pos, u32 size); u32 patchTitleInstallMinVersionChecks(u8 *pos, u32 size, u32 firmVersion); u32 patchZeroKeyNcchEncryptionCheck(u8 *pos, u32 size); u32 patchNandNcchEncryptionCheck(u8 *pos, u32 size); -u32 patchK11ModuleLoading(u32 section0size, u32 modulesSize, u8 *startPos, u32 size); u32 patchCheckForDevCommonKey(u8 *pos, u32 size); -u32 reimplementSvcBackdoor(u8 *pos, u32 *arm11SvcTable, u32 baseK11VA, u8 **freeK11Space); -u32 stubSvcRestrictGpuDma(u8 *pos, u32 *arm11SvcTable, u32 baseK11VA); -u32 implementSvcGetCFWInfo(u8 *pos, u32 *arm11SvcTable, u32 baseK11VA, u8 **freeK11Space, bool isSafeMode); +u32 patchK11ModuleLoading(u32 section0size, u32 modulesSize, u8 *startPos, u32 size); u32 patchArm9ExceptionHandlersInstall(u8 *pos, u32 size); -u32 getInfoForArm11ExceptionHandlers(u8 *pos, u32 size, u32 *codeSetOffset); u32 patchSvcBreak9(u8 *pos, u32 size, u32 kernel9Address); -void patchSvcBreak11(u8 *pos, u32 *arm11SvcTable, u32 baseK11VA); u32 patchKernel9Panic(u8 *pos, u32 size); -u32 patchKernel11Panic(u8 *pos, u32 size); u32 patchP9AccessChecks(u8 *pos, u32 size); -u32 patchArm11SvcAccessChecks(u32 *arm11SvcHandler, u32 *endPos); -u32 patchK11ModuleChecks(u8 *pos, u32 size, u8 **freeK11Space, bool patchGames); u32 patchUnitInfoValueSet(u8 *pos, u32 size); u32 patchLgySignatureChecks(u8 *pos, u32 size); u32 patchTwlInvalidSignatureChecks(u8 *pos, u32 size); diff --git a/source/pin.c b/source/pin.c index b1b12c3c1..9d7e406dc 100644 --- a/source/pin.c +++ b/source/pin.c @@ -1,6 +1,6 @@ /* * This file is part of Luma3DS -* Copyright (C) 2016 Aurora Wright, TuxSH +* 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 @@ -15,9 +15,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * -* Additional Terms 7.b of GPLv3 applies 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. +* 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. */ /* diff --git a/source/pin.h b/source/pin.h index c781508ad..ed4933cb9 100644 --- a/source/pin.h +++ b/source/pin.h @@ -1,6 +1,6 @@ /* * This file is part of Luma3DS -* Copyright (C) 2016 Aurora Wright, TuxSH +* 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 @@ -15,9 +15,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * -* Additional Terms 7.b of GPLv3 applies 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. +* 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. */ /* @@ -33,4 +37,4 @@ #define PIN_VERSIONMINOR 3 void newPin(bool allowSkipping, u32 pinMode); -bool verifyPin(u32 pinMode); \ No newline at end of file +bool verifyPin(u32 pinMode); diff --git a/source/screen.c b/source/screen.c index 7afae0989..743269bca 100644 --- a/source/screen.c +++ b/source/screen.c @@ -1,6 +1,6 @@ /* * This file is part of Luma3DS -* Copyright (C) 2016 Aurora Wright, TuxSH +* 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 @@ -15,9 +15,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * -* Additional Terms 7.b of GPLv3 applies 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. +* 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. */ /* @@ -25,16 +29,6 @@ * Screen deinit code by tiniVi */ -/* -* About cache coherency: -* -* Flushing the data cache for all memory regions read from/written to by both processors is mandatory on the ARM9 processor. -* Thus, we make sure there'll be a cache miss on the ARM9 next time it's read. -* Otherwise the ARM9 won't see the changes made and things will break. -* -* On the ARM11, in the environment we're in, the MMU isn't enabled and nothing is cached. -*/ - #include "screen.h" #include "config.h" #include "memory.h" diff --git a/source/screen.h b/source/screen.h index e36911746..185e735cc 100644 --- a/source/screen.h +++ b/source/screen.h @@ -1,6 +1,6 @@ /* * This file is part of Luma3DS -* Copyright (C) 2016 Aurora Wright, TuxSH +* 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 @@ -15,9 +15,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * -* Additional Terms 7.b of GPLv3 applies 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. +* 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. */ /* diff --git a/source/start.s b/source/start.s index 528e97052..688a13faf 100644 --- a/source/start.s +++ b/source/start.s @@ -1,5 +1,5 @@ @ This file is part of Luma3DS -@ Copyright (C) 2016 Aurora Wright, TuxSH +@ 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 @@ -14,11 +14,13 @@ @ You should have received a copy of the GNU General Public License @ along with this program. If not, see . @ -@ Additional Terms 7.b of GPLv3 applies 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. - -@ Thanks to the numerous people who took part in writing this file +@ 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. .section .text.start .align 4 @@ -58,7 +60,7 @@ _start: @ Set MPU permissions and cache settings ldr r0, =0xFFFF001D @ ffff0000 32k | bootrom (unprotected part) - ldr r1, =0xFFF0801B @ fff00000 16k | dtcm + ldr r1, =0xFFF0001B @ fff00000 16k | dtcm ldr r2, =0x01FF801D @ 01ff8000 32k | itcm ldr r3, =0x08000027 @ 08000000 1M | arm9 mem ldr r4, =0x10000029 @ 10000000 2M | io mem (ARM9 / first 2MB) @@ -92,6 +94,11 @@ _start: orr r0, r0, #(1<<0) @ - MPU enable mcr p15, 0, r0, c1, c0, 0 @ write control register + @ Fix mounting of SDMC + ldr r0, =0x10000020 + mov r1, #0x340 + str r1, [r0] + @ Clear BSS ldr r0, =__bss_start mov r1, #0 diff --git a/source/strings.c b/source/strings.c index a639e39d0..782055423 100644 --- a/source/strings.c +++ b/source/strings.c @@ -1,6 +1,6 @@ /* * This file is part of Luma3DS -* Copyright (C) 2016 Aurora Wright, TuxSH +* 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 @@ -15,9 +15,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * -* Additional Terms 7.b of GPLv3 applies 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. +* 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. */ #include "strings.h" diff --git a/source/strings.h b/source/strings.h index 5aa917b3e..de573de4f 100644 --- a/source/strings.h +++ b/source/strings.h @@ -1,6 +1,6 @@ /* * This file is part of Luma3DS -* Copyright (C) 2016 Aurora Wright, TuxSH +* 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 @@ -15,9 +15,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * -* Additional Terms 7.b of GPLv3 applies 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. +* 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 diff --git a/source/types.h b/source/types.h index 703c34dd0..5374c6c2e 100644 --- a/source/types.h +++ b/source/types.h @@ -1,6 +1,6 @@ /* * This file is part of Luma3DS -* Copyright (C) 2016 Aurora Wright, TuxSH +* 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 @@ -15,9 +15,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * -* Additional Terms 7.b of GPLv3 applies 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. +* 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 diff --git a/source/utils.c b/source/utils.c index 05b041c73..0269c2834 100644 --- a/source/utils.c +++ b/source/utils.c @@ -1,6 +1,6 @@ /* * This file is part of Luma3DS -* Copyright (C) 2016 Aurora Wright, TuxSH +* 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 @@ -15,9 +15,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * -* Additional Terms 7.b of GPLv3 applies 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. +* 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. */ /* @@ -36,7 +40,7 @@ static void startChrono(void) { - bool isChronoStarted = false; + static bool isChronoStarted = false; if(isChronoStarted) return; @@ -81,7 +85,7 @@ u32 waitInput(bool isMenu) if(!key) { - if(i2cReadRegister(I2C_DEV_MCU, 0x10) == 1) mcuPowerOff(); + if((i2cReadRegister(I2C_DEV_MCU, 0x10) & 1)== 1) mcuPowerOff(); oldKey = 0; dPadDelay = 0; continue; diff --git a/source/utils.h b/source/utils.h index 9533dfc33..00ca57e4a 100644 --- a/source/utils.h +++ b/source/utils.h @@ -1,6 +1,6 @@ /* * This file is part of Luma3DS -* Copyright (C) 2016 Aurora Wright, TuxSH +* 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 @@ -15,9 +15,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * -* Additional Terms 7.b of GPLv3 applies 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. +* 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. */ /* diff --git a/sysmodules/loader/loader.rsf b/sysmodules/loader/loader.rsf index dfeeb0eb5..2d29c9360 100644 --- a/sysmodules/loader/loader.rsf +++ b/sysmodules/loader/loader.rsf @@ -102,6 +102,7 @@ AccessControlInfo: UnmapMemoryBlock: 32 WaitSynchronization1: 36 WaitSynchronizationN: 37 + KernelSetState: 124 InterruptNumbers: ServiceAccessControl: - fs:LDR @@ -112,4 +113,4 @@ AccessControlInfo: SystemControlInfo: SaveDataSize: 0KB # It doesn't use any save data. RemasterVersion: 0 - StackSize: 0x1000 \ No newline at end of file + StackSize: 0x1000 diff --git a/sysmodules/loader/source/CFWInfo.h b/sysmodules/loader/source/CFWInfo.h deleted file mode 100644 index 17f00c7fa..000000000 --- a/sysmodules/loader/source/CFWInfo.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -#include <3ds/types.h> - -typedef struct __attribute__((packed)) -{ - char magic[4]; - - u8 versionMajor; - u8 versionMinor; - u8 versionBuild; - u8 flags; - - u32 commitHash; - - u32 config; -} CFWInfo; - -u32 svcGetCFWInfo(CFWInfo *info); \ No newline at end of file diff --git a/sysmodules/loader/source/CFWInfo.s b/sysmodules/loader/source/CFWInfo.s deleted file mode 100644 index 8337620c0..000000000 --- a/sysmodules/loader/source/CFWInfo.s +++ /dev/null @@ -1,9 +0,0 @@ -.text -.arm -.align 4 - -.global svcGetCFWInfo -.type svcGetCFWInfo, %function -svcGetCFWInfo: - svc 0x2e - bx lr diff --git a/sysmodules/loader/source/exheader.h b/sysmodules/loader/source/exheader.h index be23527c6..811ff1f29 100755 --- a/sysmodules/loader/source/exheader.h +++ b/sysmodules/loader/source/exheader.h @@ -4,94 +4,96 @@ typedef struct { - u8 reserved[5]; - u8 flag; - u8 remasterversion[2]; + u8 reserved[5]; + u8 flag; + u8 remasterversion[2]; } PACKED exheader_systeminfoflags; typedef struct { - u32 address; - u32 nummaxpages; - u32 codesize; + u32 address; + u32 nummaxpages; + u32 codesize; } PACKED exheader_codesegmentinfo; typedef struct { - u8 name[8]; - exheader_systeminfoflags flags; - exheader_codesegmentinfo text; - u8 stacksize[4]; - exheader_codesegmentinfo ro; - u8 reserved[4]; - exheader_codesegmentinfo data; - u32 bsssize; + u8 name[8]; + exheader_systeminfoflags flags; + exheader_codesegmentinfo text; + u8 stacksize[4]; + exheader_codesegmentinfo ro; + u8 reserved[4]; + exheader_codesegmentinfo data; + u32 bsssize; } PACKED exheader_codesetinfo; typedef struct { - u64 programid[0x30]; + u64 programid[0x30]; } PACKED exheader_dependencylist; typedef struct { - u8 savedatasize[4]; - u8 reserved[4]; - u8 jumpid[8]; - u8 reserved2[0x30]; + u8 savedatasize[4]; + u8 reserved[4]; + u8 jumpid[8]; + u8 reserved2[0x30]; } PACKED exheader_systeminfo; typedef struct { - u8 extsavedataid[8]; - u8 systemsavedataid[8]; - u8 reserved[8]; - u8 accessinfo[7]; - u8 otherattributes; + u8 extsavedataid[8]; + u8 systemsavedataid[8]; + u8 reserved[8]; + u8 accessinfo[7]; + u8 otherattributes; } PACKED exheader_storageinfo; typedef struct { - u64 programid; - u8 flags[8]; - u16 resourcelimitdescriptor[0x10]; - exheader_storageinfo storageinfo; - u64 serviceaccesscontrol[0x20]; - u8 reserved[0x1f]; - u8 resourcelimitcategory; + u64 programid; + u32 coreversion; + u8 flags[3]; + u8 priority; + u16 resourcelimitdescriptor[0x10]; + exheader_storageinfo storageinfo; + u64 serviceaccesscontrol[0x22]; + u8 reserved[0xf]; + u8 resourcelimitcategory; } PACKED exheader_arm11systemlocalcaps; typedef struct { - u32 descriptors[28]; - u8 reserved[0x10]; + u32 descriptors[28]; + u8 reserved[0x10]; } PACKED exheader_arm11kernelcapabilities; typedef struct { - u8 descriptors[15]; - u8 descversion; + u8 descriptors[15]; + u8 descversion; } PACKED exheader_arm9accesscontrol; typedef struct { - // systemcontrol info { - // coreinfo { - exheader_codesetinfo codesetinfo; - exheader_dependencylist deplist; - // } - exheader_systeminfo systeminfo; - // } - // accesscontrolinfo { - exheader_arm11systemlocalcaps arm11systemlocalcaps; - exheader_arm11kernelcapabilities arm11kernelcaps; - exheader_arm9accesscontrol arm9accesscontrol; - // } - struct { - u8 signature[0x100]; - u8 ncchpubkeymodulus[0x100]; - exheader_arm11systemlocalcaps arm11systemlocalcaps; - exheader_arm11kernelcapabilities arm11kernelcaps; - exheader_arm9accesscontrol arm9accesscontrol; - } PACKED accessdesc; + // systemcontrol info { + // coreinfo { + exheader_codesetinfo codesetinfo; + exheader_dependencylist deplist; + // } + exheader_systeminfo systeminfo; + // } + // accesscontrolinfo { + exheader_arm11systemlocalcaps arm11systemlocalcaps; + exheader_arm11kernelcapabilities arm11kernelcaps; + exheader_arm9accesscontrol arm9accesscontrol; + // } + struct { + u8 signature[0x100]; + u8 ncchpubkeymodulus[0x100]; + exheader_arm11systemlocalcaps arm11systemlocalcaps; + exheader_arm11kernelcapabilities arm11kernelcaps; + exheader_arm9accesscontrol arm9accesscontrol; + } PACKED accessdesc; } PACKED exheader_header; diff --git a/sysmodules/loader/source/loader.c b/sysmodules/loader/source/loader.c index 5a49a3a25..7c5525943 100644 --- a/sysmodules/loader/source/loader.c +++ b/sysmodules/loader/source/loader.c @@ -8,7 +8,8 @@ #include "pxipm.h" #include "srvsys.h" -#define MAX_SESSIONS 1 +#define MAX_SESSIONS 1 +#define HBLDR_3DSX_TID (*(vu64 *)0x1FF81100) const char CODE_PATH[] = {0x01, 0x00, 0x00, 0x00, 0x2E, 0x63, 0x6F, 0x64, 0x65, 0x00, 0x00, 0x00}; @@ -163,13 +164,28 @@ static Result load_code(u64 progid, prog_addrs_t *shared, u64 prog_handle, int i return 0; } +static Result HBLDR_Init(Handle *session) +{ + Result res; + while (1) + { + res = svcConnectToPort(session, "hb:ldr"); + if (R_LEVEL(res) != RL_PERMANENT || + R_SUMMARY(res) != RS_NOTFOUND || + R_DESCRIPTION(res) != RD_NOT_FOUND + ) break; + svcSleepThread(500000); + } + return res; +} + static Result loader_GetProgramInfo(exheader_header *exheader, u64 prog_handle) { Result res; if (prog_handle >> 32 == 0xFFFF0000) { - return FSREG_GetProgramInfo(exheader, 1, prog_handle); + res = FSREG_GetProgramInfo(exheader, 1, prog_handle); } else { @@ -178,13 +194,41 @@ static Result loader_GetProgramInfo(exheader_header *exheader, u64 prog_handle) //so use PXIPM if FSREG fails OR returns "info", is the second condition a bug? if (R_FAILED(res) || (R_SUCCEEDED(res) && R_LEVEL(res) != RL_SUCCESS)) { - return PXIPM_GetProgramInfo(exheader, prog_handle); + res = PXIPM_GetProgramInfo(exheader, prog_handle); } else { - return FSREG_GetProgramInfo(exheader, 1, prog_handle); + res = FSREG_GetProgramInfo(exheader, 1, prog_handle); + } + } + + if (R_SUCCEEDED(res)) + { + // Force always having sdmc:/ and nand:/rw permission + exheader->arm11systemlocalcaps.storageinfo.accessinfo[0] |= 0x480; + exheader->accessdesc.arm11systemlocalcaps.storageinfo.accessinfo[0] |= 0x480; + + // Tweak 3dsx placeholder title exheader + if (exheader->arm11systemlocalcaps.programid == HBLDR_3DSX_TID) + { + Handle hbldr = 0; + res = HBLDR_Init(&hbldr); + if (R_SUCCEEDED(res)) + { + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = IPC_MakeHeader(4,0,2); + cmdbuf[1] = IPC_Desc_Buffer(sizeof(*exheader), IPC_BUFFER_RW); + cmdbuf[2] = (u32)exheader; + res = svcSendSyncRequest(hbldr); + svcCloseHandle(hbldr); + if (R_SUCCEEDED(res)) { + res = cmdbuf[1]; + } + } } } + + return res; } static Result loader_LoadProcess(Handle *process, u64 prog_handle) @@ -228,6 +272,39 @@ static Result loader_LoadProcess(Handle *process, u64 prog_handle) return MAKERESULT(RL_PERMANENT, RS_INVALIDARG, 1, 2); } + // check for 3dsx process + progid = g_exheader.arm11systemlocalcaps.programid; + if (progid == HBLDR_3DSX_TID) + { + Handle hbldr = 0; + res = HBLDR_Init(&hbldr); + if (R_FAILED(res)) + { + return res; + } + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = IPC_MakeHeader(1,6,0); + cmdbuf[1] = g_exheader.codesetinfo.text.address; + cmdbuf[2] = flags & 0xF00; + cmdbuf[3] = progid; + cmdbuf[4] = progid>>32; + memcpy(&cmdbuf[5], g_exheader.codesetinfo.name, 8); + res = svcSendSyncRequest(hbldr); + svcCloseHandle(hbldr); + if (R_SUCCEEDED(res)) + { + res = cmdbuf[1]; + } + if (R_FAILED(res)) + { + return res; + } + codeset = (Handle)cmdbuf[3]; + res = svcCreateProcess(process, codeset, g_exheader.arm11kernelcaps.descriptors, count); + svcCloseHandle(codeset); + return res; + } + // allocate process memory vaddr.text_addr = g_exheader.codesetinfo.text.address; vaddr.text_size = (g_exheader.codesetinfo.text.codesize + 4095) >> 12; @@ -243,7 +320,6 @@ static Result loader_LoadProcess(Handle *process, u64 prog_handle) } // load code - progid = g_exheader.arm11systemlocalcaps.programid; if ((res = load_code(progid, &shared_addr, prog_handle, g_exheader.codesetinfo.flags.flag & 1)) >= 0) { memcpy(&codesetinfo.name, g_exheader.codesetinfo.name, 8); diff --git a/sysmodules/loader/source/patcher.c b/sysmodules/loader/source/patcher.c index 66353a4aa..f7687963d 100644 --- a/sysmodules/loader/source/patcher.c +++ b/sysmodules/loader/source/patcher.c @@ -4,10 +4,10 @@ #include "strings.h" #include "fsldr.h" #include "ifile.h" -#include "CFWInfo.h" #include "../build/bundled.h" -static CFWInfo info; +static u32 config; +static bool isN3DS, isSafeMode, isSdMode; static u32 patchMemory(u8 *start, u32 size, const void *pattern, u32 patSize, s32 offset, const void *replace, u32 repSize, u32 count) { @@ -61,14 +61,14 @@ static bool dirCheck(FS_ArchiveID archiveId, const char *path) static bool openLumaFile(IFile *file, const char *path) { - FS_ArchiveID archiveId = LOADERFLAG(ISSDMODE) ? ARCHIVE_SDMC : ARCHIVE_NAND_RW; + FS_ArchiveID archiveId = isSdMode ? ARCHIVE_SDMC : ARCHIVE_NAND_RW; return R_SUCCEEDED(fileOpen(file, archiveId, path, FS_OPEN_READ)); } static u32 checkLumaDir(const char *path) { - FS_ArchiveID archiveId = LOADERFLAG(ISSDMODE) ? ARCHIVE_SDMC : ARCHIVE_NAND_RW; + FS_ArchiveID archiveId = isSdMode ? ARCHIVE_SDMC : ARCHIVE_NAND_RW; return dirCheck(archiveId, path) ? archiveId : 0; } @@ -76,14 +76,21 @@ static u32 checkLumaDir(const char *path) static inline void loadCFWInfo(void) { static bool infoLoaded = false; + s64 out; if(infoLoaded) return; - svcGetCFWInfo(&info); + if(R_FAILED(svcGetSystemInfo(&out, 0x10000, 2))) svcBreak(USERBREAK_ASSERT); + config = (u32)out; + if(R_FAILED(svcGetSystemInfo(&out, 0x10000, 4))) svcBreak(USERBREAK_ASSERT); + isN3DS = (bool)out; + if(R_FAILED(svcGetSystemInfo(&out, 0x10000, 5))) svcBreak(USERBREAK_ASSERT); + isSafeMode = (bool)out; + if(R_FAILED(svcGetSystemInfo(&out, 0x10000, 6))) svcBreak(USERBREAK_ASSERT); + isSdMode = (bool)out; IFile file; - if(LOADERFLAG(ISSAFEMODE)) fileOpen(&file, ARCHIVE_SDMC, "/", FS_OPEN_READ); //Init SD card if SAFE_MODE is being booted - + if(isSafeMode) fileOpen(&file, ARCHIVE_SDMC, "/", FS_OPEN_READ); //Init SD card if SAFE_MODE is being booted infoLoaded = true; } @@ -170,116 +177,6 @@ static u32 findFunctionStart(u8 *code, u32 pos) return 0xFFFFFFFF; } -static inline u8 *getCfgOffsets(u8 *code, u32 size, u32 *CFGUHandleOffset) -{ - /* HANS: - Look for error code which is known to be stored near cfg:u handle - this way we can find the right candidate - (handle should also be stored right after end of candidate function) */ - - u32 n = 0, - possible[24]; - - for(u8 *pos = code + 16; n < 24 && pos <= code + size - 16; pos += 4) - { - if(*(u32 *)pos != 0xD8A103F9) continue; - - for(u32 *l = (u32 *)pos - 4; n < 24 && l < (u32 *)pos + 4; l++) - if(*l <= 0x10000000) possible[n++] = *l; - } - - if(!n) return NULL; - - for(u8 *CFGU_GetConfigInfoBlk2_endPos = code; CFGU_GetConfigInfoBlk2_endPos <= code + size - 12; CFGU_GetConfigInfoBlk2_endPos += 4) - { - //There might be multiple implementations of GetConfigInfoBlk2 but let's search for the one we want - u32 *cmp = (u32 *)CFGU_GetConfigInfoBlk2_endPos; - - if(cmp[0] != 0xE8BD8010 || cmp[1] != 0x00010082) continue; - - for(u32 i = 0; i < n; i++) - if(possible[i] == cmp[2]) - { - *CFGUHandleOffset = cmp[2]; - - return CFGU_GetConfigInfoBlk2_endPos; - } - - CFGU_GetConfigInfoBlk2_endPos += 4; - } - - return NULL; -} - -static inline bool patchCfgGetLanguage(u8 *code, u32 size, u8 languageId, u8 *CFGU_GetConfigInfoBlk2_endPos) -{ - u32 additive = findFunctionStart(code, (u32)(CFGU_GetConfigInfoBlk2_endPos - code)); - - if(additive == 0xFFFFFFFF) return false; - - u8 *CFGU_GetConfigInfoBlk2_startPos = code + additive; - - for(u8 *languageBlkIdPos = code; languageBlkIdPos <= code + size - 4; languageBlkIdPos += 4) - { - if(*(u32 *)languageBlkIdPos != 0xA0002) continue; - - for(u8 *instr = languageBlkIdPos - 8; instr >= languageBlkIdPos - 0x1008 && instr >= code + 4; instr -= 4) //Should be enough - { - if(instr[3] != 0xEB) continue; //We're looking for BL - - u8 *calledFunction = instr; - u32 i = 0; - - do - { - u32 low24 = (*(u32 *)calledFunction & 0x00FFFFFF) << 2; - u32 signMask = (u32)(-(low24 >> 25)) & 0xFC000000; //Sign extension - s32 offset = (s32)(low24 | signMask) + 8; //Branch offset + 8 for prefetch - - calledFunction += offset; - - if(calledFunction >= CFGU_GetConfigInfoBlk2_startPos - 4 && calledFunction <= CFGU_GetConfigInfoBlk2_endPos) - { - *((u32 *)instr - 1) = 0xE3A00000 | languageId; //mov r0, sp => mov r0, =languageId - *(u32 *)instr = 0xE5CD0000; //bl CFGU_GetConfigInfoBlk2 => strb r0, [sp] - *((u32 *)instr + 1) = 0xE3B00000; //(1 or 2 instructions) => movs r0, 0 (result code) - - //We're done - return true; - } - - i++; - } - while(i < 2 && calledFunction[3] == 0xEA); - } - } - - return false; -} - -static inline void patchCfgGetRegion(u8 *code, u32 size, u8 regionId, u32 CFGUHandleOffset) -{ - for(u8 *cmdPos = code; cmdPos <= code + size - 28; cmdPos += 4) - { - u32 *cmp = (u32 *)cmdPos; - - if(*cmp != 0xE3A00802) continue; - - for(u32 i = 1; i < 3; i++) - if((*(cmp - i) & 0xFFFF0FFF) == 0xEE1D0F70 && *((u16 *)cmdPos + 5) == 0xE59F && - *(u32 *)(cmdPos + 16 + *((u16 *)cmdPos + 4)) == CFGUHandleOffset) - { - cmp[3] = 0xE3A00000 | regionId; //mov r0, =regionId - cmp[4] = 0xE5C40008; //strb r0, [r4, #8] - cmp[5] = 0xE3A00000; //mov r0, #0 (result code) - cmp[6] = 0xE5840004; //str r0, [r4, #4] - - //The remaining, not patched, function code will do the rest for us - return; - } - } -} - static inline bool findLayeredFsSymbols(u8 *code, u32 size, u32 *fsMountArchive, u32 *fsRegisterArchive, u32 *fsTryOpenFile, u32 *fsOpenFileDirectly) { u32 found = 0, @@ -480,55 +377,97 @@ static inline bool loadTitleCodeSection(u64 progId, u8 *code, u32 size) return ret; } -static inline bool loadTitleLocaleConfig(u64 progId, u8 *regionId, u8 *languageId) +static inline bool loadTitleLocaleConfig(u64 progId, u8 *mask, u8 *regionId, u8 *languageId, u8 *countryId, u8 *stateId) { /* Here we look for "/luma/titles/[u64 titleID in hex, uppercase]/locale.txt" If it exists it should contain, for example, "EUR IT" */ char path[] = "/luma/titles/0000000000000000/locale.txt"; progIdToStr(path + 28, progId); + *mask = *regionId = *languageId = *countryId = *stateId = 0; IFile file; - if(!openLumaFile(&file, path)) return true; + if(!openLumaFile(&file, path)) return false; bool ret = false; u64 fileSize; - if(R_FAILED(IFile_GetSize(&file, &fileSize)) || fileSize < 6 || fileSize > 8) goto exit; + if(R_FAILED(IFile_GetSize(&file, &fileSize)) || fileSize < 3) goto exit; + if(fileSize >= 12) fileSize = 12; - char buf[8]; + char buf[12] = "------------"; u64 total; if(R_FAILED(IFile_Read(&file, &total, buf, fileSize))) goto exit; - static const char *regions[] = {"JPN", "USA", "EUR", "AUS", "CHN", "KOR", "TWN"}, - *languages[] = {"JP", "EN", "FR", "DE", "IT", "ES", "ZH", "KO", "NL", "PT", "RU", "TW"}; + ret = true; + + static const char *regions[] = {"--", "JPN", "USA", "EUR", "AUS", "CHN", "KOR", "TWN"}, + *languages[] = {"--", "JP", "EN", "FR", "DE", "IT", "ES", "ZH", "KO", "NL", "PT", "RU", "TW"}, + *countries[] = {"--", "JP", "--", "--", "--", "--", "--", "--", "AI", "AG", "AR", "AW", + "BS", "BB", "BZ", "BO", "BR", "VG", "CA", "KY", "CL", "CO", "CR", "DM", + "DO", "EC", "SV", "GF", "GD", "GP", "GT", "GY", "HT", "HN", "JM", "MQ", + "MX", "MS", "AN", "NI", "PA", "PY", "PE", "KN", "LC", "VC", "SR", "TT", + "TC", "US", "UY", "VI", "VE", "--", "--", "--", "--", "--", "--", "--", + "--", "--", "--", "--", "AL", "AU", "AT", "BE", "BA", "BW", "BG", "HR", + "CY", "CZ", "DK", "EE", "FI", "FR", "DE", "GR", "HU", "IS", "IE", "IT", + "LV", "LS", "LI", "LT", "LU", "MK", "MT", "ME", "MZ", "NA", "NL", "NZ", + "NO", "PL", "PT", "RO", "RU", "RS", "SK", "SI", "ZA", "ES", "SZ", "SE", + "CH", "TR", "GB", "ZM", "ZW", "AZ", "MR", "ML", "NE", "TD", "SD", "ER", + "DJ", "SO", "AD", "GI", "GG", "IM", "JE", "MC", "TW", "--", "--", "--", + "--", "--", "--", "--", "KR", "--", "--", "--", "--", "--", "--", "--", + "HK", "MO", "--", "--", "--", "--", "--", "--", "ID", "SG", "TH", "PH", + "MY", "--", "--", "--", "CN", "--", "--", "--", "--", "--", "--", "--", + "AE", "IN", "EG", "OM", "QA", "KW", "SA", "SY", "BH", "JO", "--", "--", + "--", "--", "--", "--", "SM", "VA"}; u32 i; - for(i = 0; i < sizeof(regions) / sizeof(char *); i++) { - if(memcmp(buf, regions[i], 3) == 0) + if(memcmp(buf, regions[i], 3) == 0 && i != 0) { - *regionId = (u8)i; + *regionId = (u8)(i - 1); + *mask |= 1; break; } } - if(i != sizeof(regions) / sizeof(char *)) + for(i = 0; fileSize >= 6 && i < sizeof(languages) / sizeof(char *); i++) { - for(i = 0; i < sizeof(languages) / sizeof(char *); i++) + if(memcmp(buf + 4, languages[i], 2) == 0 && i != 0) { - if(memcmp(buf + 4, languages[i], 2) == 0) - { - *languageId = (u8)i; - ret = true; - break; - } + *languageId = (u8)(i - 1); + *mask |= 2; + break; } } + for(i = 0; fileSize >= 9 && i < sizeof(countries) / sizeof(char *); i++) + { + if(memcmp(buf + 7, countries[i], 2) == 0 && i != 0) + { + *countryId = (u8)i; + *mask |= 4; + break; + } + } + + if(fileSize >= 12 && + ((buf[10] >= '0' && buf[10] <= '9') || (buf[10] >= 'a' && buf[10] <= 'f') || (buf[10] >= 'A' && buf[10] <= 'F')) && + ((buf[11] >= '0' && buf[11] <= '9') || (buf[11] >= 'a' && buf[11] <= 'f') || (buf[11] >= 'A' && buf[11] <= 'F'))) + { + if (buf[10] >= '0' && buf[10] <= '9') *stateId = 16 * (buf[10] - '0'); + else if(buf[10] >= 'a' && buf[10] <= 'f') *stateId = 16 * (buf[10] - 'a'); + else if(buf[10] >= 'A' && buf[10] <= 'F') *stateId = 16 * (buf[10] - 'A'); + + if (buf[11] >= '0' && buf[11] <= '9') *stateId += buf[11] - '0'; + else if(buf[11] >= 'a' && buf[11] <= 'f') *stateId += buf[11] - 'a'; + else if(buf[11] >= 'A' && buf[11] <= 'F') *stateId += buf[11] - 'A'; + + *mask |= 8; + } + exit: IFile_Close(&file); @@ -775,7 +714,7 @@ void patchCode(u64 progId, u16 progVer, u8 *code, u32 size, u32 textSize, u32 ro if(ret == 0 || (ret == 1 && progVer > 0xB)) goto error; } - if(LOADERFLAG(ISN3DS)) + if(isN3DS) { u32 cpuSetting = MULTICONFIG(NEWCPU); @@ -796,6 +735,11 @@ void patchCode(u64 progId, u16 progVer, u8 *code, u32 size, u32 textSize, u32 ro *(off + 3) = 0xE3800000 | cpuSetting; } } + + // Makes ErrDisp to not start up + static const u64 errDispTid = 0x0004003000008A02ULL; + u32 *errDispTidLoc = (u32 *)memsearch(code, &errDispTid, size, sizeof(errDispTid)); + *(errDispTidLoc - 6) = 0xE3A00000; // mov r0, #0 } else if(progId == 0x0004013000001702LL) //CFG @@ -866,33 +810,6 @@ void patchCode(u64 progId, u16 progVer, u8 *code, u32 size, u32 textSize, u32 ro )) goto error; } - else if(progId == 0x0004003000008A02LL && CONFIG(ENABLEEXCEPTIONHANDLERS) && !CONFIG(PATCHUNITINFO)) //ErrDisp - { - static const u8 pattern[] = { - 0x00, 0xD0, 0xE5, 0xDB - }, - pattern2[] = { - 0x14, 0x00, 0xD0, 0xE5, 0x01 - }, - patch[] = { - 0x00, 0x00, 0xA0, 0xE3 - }; - - //Patch UNITINFO checks to make ErrDisp more verbose - if(!patchMemory(code, textSize, - pattern, - sizeof(pattern), -1, - patch, - sizeof(patch), 1 - ) || - patchMemory(code, textSize, - pattern2, - sizeof(pattern2), 0, - patch, - sizeof(patch), 3 - ) != 3) goto error; - } - else if(progId == 0x0004013000002802LL) //DLP { static const u8 pattern[] = { @@ -918,22 +835,15 @@ void patchCode(u64 progId, u16 progVer, u8 *code, u32 size, u32 textSize, u32 ro if((u32)((progId >> 0x20) & 0xFFFFFFEDULL) == 0x00040000) { - u8 regionId = 0xFF, - languageId; - - if(!loadTitleLocaleConfig(progId, ®ionId, &languageId) || - !patchLayeredFs(progId, code, size, textSize, roSize, dataSize, roAddress, dataAddress)) goto error; - - if(regionId != 0xFF) - { - u32 CFGUHandleOffset; - u8 *CFGU_GetConfigInfoBlk2_endPos = getCfgOffsets(code, textSize, &CFGUHandleOffset); - - if(CFGU_GetConfigInfoBlk2_endPos == NULL || - !patchCfgGetLanguage(code, textSize, languageId, CFGU_GetConfigInfoBlk2_endPos)) goto error; - - patchCfgGetRegion(code, textSize, regionId, CFGUHandleOffset); - } + u8 mask, + regionId, + languageId, + countryId, + stateId; + + if(loadTitleLocaleConfig(progId, &mask, ®ionId, &languageId, &countryId, &stateId)) + svcKernelSetState(0x10001, ((u32)stateId << 24) | ((u32)countryId << 16) | ((u32)languageId << 8) | ((u32)regionId << 4) | (u32)mask , progId); + if(!patchLayeredFs(progId, code, size, textSize, roSize, dataSize, roAddress, dataAddress)) goto error; } } diff --git a/sysmodules/loader/source/patcher.h b/sysmodules/loader/source/patcher.h index 995c5a433..fa9454cbe 100644 --- a/sysmodules/loader/source/patcher.h +++ b/sysmodules/loader/source/patcher.h @@ -5,10 +5,9 @@ #define MAKE_BRANCH(src,dst) (0xEA000000 | ((u32)((((u8 *)(dst) - (u8 *)(src)) >> 2) - 2) & 0xFFFFFF)) #define MAKE_BRANCH_LINK(src,dst) (0xEB000000 | ((u32)((((u8 *)(dst) - (u8 *)(src)) >> 2) - 2) & 0xFFFFFF)) -#define CONFIG(a) (((info.config >> (a + 17)) & 1) != 0) -#define MULTICONFIG(a) ((info.config >> (a * 2 + 7)) & 3) -#define BOOTCONFIG(a, b) ((info.config >> a) & b) -#define LOADERFLAG(a) ((info.flags >> (a + 4)) & 1) != 0 +#define CONFIG(a) (((config >> (a + 17)) & 1) != 0) +#define MULTICONFIG(a) ((config >> (a * 2 + 7)) & 3) +#define BOOTCONFIG(a, b) ((config >> a) & b) #define BOOTCFG_NAND BOOTCONFIG(0, 7) #define BOOTCFG_FIRM BOOTCONFIG(3, 7) @@ -32,15 +31,7 @@ enum singleOptions PATCHVERSTRING, SHOWGBABOOT, PATCHACCESS, - PATCHUNITINFO, - ENABLEEXCEPTIONHANDLERS -}; - -enum flags -{ - ISN3DS = 0, - ISSAFEMODE, - ISSDMODE + PATCHUNITINFO }; void patchCode(u64 progId, u16 progVer, u8 *code, u32 size, u32 textSize, u32 roSize, u32 dataSize, u32 roAddress, u32 dataAddress); diff --git a/sysmodules/loader/source/strings.c b/sysmodules/loader/source/strings.c index f4dc6c7e8..51998a3d9 100644 --- a/sysmodules/loader/source/strings.c +++ b/sysmodules/loader/source/strings.c @@ -17,4 +17,4 @@ void progIdToStr(char *strEnd, u64 progId) *strEnd-- = hexDigits[(u32)(progId & 0xF)]; progId >>= 4; } -} \ No newline at end of file +} diff --git a/sysmodules/loader/source/strings.h b/sysmodules/loader/source/strings.h index 659911825..19340cbff 100644 --- a/sysmodules/loader/source/strings.h +++ b/sysmodules/loader/source/strings.h @@ -3,4 +3,4 @@ #include <3ds/types.h> size_t strnlen(const char *string, size_t maxlen); -void progIdToStr(char *strEnd, u64 progId); \ No newline at end of file +void progIdToStr(char *strEnd, u64 progId); diff --git a/sysmodules/rosalina/Makefile b/sysmodules/rosalina/Makefile new file mode 100644 index 000000000..16b444fd3 --- /dev/null +++ b/sysmodules/rosalina/Makefile @@ -0,0 +1,78 @@ +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_include := include +dir_build := build +dir_out := ../../$(dir_build) +dir_kernel_extension := kernel_extension + +LIBS := -lctru +LIBDIRS := $(CTRULIB) +LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) + +INCLUDE := $(foreach dir,$(LIBDIRS),-I$(dir)/include) + +ARCH := -mcpu=mpcore -mfloat-abi=hard +ASFLAGS := -g $(ARCH) +CFLAGS := -Wall -Wextra -MMD -MP -marm $(ASFLAGS) -mtp=soft -fno-builtin -std=c11 -O2 -flto -ffast-math -mword-relocations \ + -fomit-frame-pointer -ffunction-sections -fdata-sections $(INCLUDE) -I$(dir_include) -DARM11 -D_3DS +LDFLAGS := -specs=3dsx.specs -g $(ARCH) -mtp=soft -Wl,--section-start,.text=0x14000000 -Wl,--gc-sections + +objects = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \ + $(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \ + $(call rwildcard, $(dir_source), *.s *.c))) + +xml_files = $(call rwildcard, $(dir_source), *.xml) + +.PHONY: all +all: $(dir_out)/$(name).cxi + +.PHONY: clean +clean: + @$(MAKE) -C $(dir_kernel_extension) clean + @rm -rf $(dir_build) + +.PHONY: $(dir_kernel_extension) + +$(dir_out)/$(name).cxi: $(dir_build)/$(name).elf + @makerom -f ncch -rsf rosalina.rsf -nocodepadding -o $@ -elf $< + +$(dir_build)/$(name).elf: $(objects) + $(LINK.o) $(OUTPUT_OPTION) $^ $(LIBPATHS) $(LIBS) + +$(dir_build)/kernel_extension.bin: $(dir_kernel_extension) + @mkdir -p "$(@D)" + @$(MAKE) -C $< + +$(dir_build)/xml_data.h: $(xml_files) + @ echo "" > $(@) + @$(foreach f, $(xml_files),\ + echo "static const char" `(echo $(notdir $(f)) | sed -e 's/^\([0-9]\)/_\1/g' | tr . _)`"[] = " >> $(@);\ + sed -e 's/\\/\\\\/g;s/"/\\"/g;s/^/"/g;s/[ \t\r\n]*$$/\\n"/g' $(f) >> $(@);\ + echo ';' >> $@;\ + ) +$(dir_build)/gdb/xfer.o: $(dir_build)/xml_data.h +$(dir_build)/memory.o : CFLAGS += -O3 +$(dir_build)/kernel_extension.o: $(dir_build)/kernel_extension.bin + +$(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/sysmodules/rosalina/include/3dsx.h b/sysmodules/rosalina/include/3dsx.h new file mode 100644 index 000000000..61ef1dae7 --- /dev/null +++ b/sysmodules/rosalina/include/3dsx.h @@ -0,0 +1,111 @@ +/* +* 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 . +* +* 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. +*/ + +/* File entirely written by fincs */ + +#pragma once +#include <3ds/types.h> +#include "ifile.h" + +// File layout: +// - File header +// - Code, rodata and data relocation table headers +// - Code segment +// - Rodata segment +// - Loadable (non-BSS) part of the data segment +// - Code relocation table +// - Rodata relocation table +// - Data relocation table + +// Memory layout before relocations are applied: +// [0..codeSegSize) -> code segment +// [codeSegSize..rodataSegSize) -> rodata segment +// [rodataSegSize..dataSegSize) -> data segment + +// Memory layout after relocations are applied: well, however the loader sets it up :) +// The entrypoint is always the start of the code segment. +// The BSS section must be cleared manually by the application. + +// File header +#define _3DSX_MAGIC 0x58534433 // '3DSX' +typedef struct +{ + u32 magic; + u16 headerSize, relocHdrSize; + u32 formatVer; + u32 flags; + + // Sizes of the code, rodata and data segments + + // size of the BSS section (uninitialized latter half of the data segment) + u32 codeSegSize, rodataSegSize, dataSegSize, bssSize; +} _3DSX_Header; + +// Relocation header: all fields (even extra unknown fields) are guaranteed to be relocation counts. +typedef struct +{ + u32 cAbsolute; // # of absolute relocations (that is, fix address to post-relocation memory layout) + u32 cRelative; // # of cross-segment relative relocations (that is, 32bit signed offsets that need to be patched) + // more? + + // Relocations are written in this order: + // - Absolute relocs + // - Relative relocs +} _3DSX_RelocHdr; + +// Relocation entry: from the current pointer, skip X words and patch Y words +typedef struct +{ + u16 skip, patch; +} _3DSX_Reloc; + +// _prm structure +#define _PRM_MAGIC 0x6D72705F // '_prm' +typedef struct +{ + u32 magic; + u32 pSrvOverride; + u32 aptAppId; + u32 heapSize, linearHeapSize; + u32 pArgList; + u32 runFlags; +} PrmStruct; + +// Service override structure +typedef struct +{ + u32 count; + struct + { + char name[8]; + Handle handle; + } services[]; +} SrvOverride; + +#define ARGVBUF_SIZE 0x400 +extern u32 ldrArgvBuf[ARGVBUF_SIZE/4]; + +bool Ldr_Get3dsxSize(u32* pSize, IFile *file); +Handle Ldr_CodesetFrom3dsx(const char* name, u32* codePages, u32 baseAddr, IFile *file, u64 tid); diff --git a/sysmodules/rosalina/include/MyThread.h b/sysmodules/rosalina/include/MyThread.h new file mode 100644 index 000000000..7872f5051 --- /dev/null +++ b/sysmodules/rosalina/include/MyThread.h @@ -0,0 +1,46 @@ +/* +* 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 . +* +* 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 <3ds/types.h> +#include <3ds/result.h> +#include <3ds/svc.h> +#include <3ds/synchronization.h> + +#define THREAD_STACK_SIZE 0x1000 + +typedef struct MyThread +{ + Handle handle; + void (*ep)(void); + bool finished; + void* stacktop; +} MyThread; + +Result MyThread_Create(MyThread *t, void (*entrypoint)(void), void *stack, u32 stackSize, int prio, int affinity); +Result MyThread_Join(MyThread *thread, s64 timeout_ns); +void MyThread_Exit(void); diff --git a/sysmodules/rosalina/include/csvc.h b/sysmodules/rosalina/include/csvc.h new file mode 100644 index 000000000..e4c7ff98a --- /dev/null +++ b/sysmodules/rosalina/include/csvc.h @@ -0,0 +1,137 @@ +/* This paricular file is licensed under the following terms: */ + +/* +* This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable +* for any damages arising from the use of this software. +* +* Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it +* and redistribute it freely, subject to the following restrictions: +* +* The origin of this software must not be misrepresented; you must not claim that you wrote the original software. +* If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +* +* Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +* This notice may not be removed or altered from any source distribution. +*/ + +#pragma once + +#include <3ds/types.h> + +/// Operations for svcControlService +typedef enum ServiceOp +{ + SERVICEOP_STEAL_CLIENT_SESSION = 0, ///< Steal a client session given a service or global port name + SERVICEOP_GET_NAME, ///< Get the name of a service or global port given a client or session handle +} ServiceOp; + +/** + * @brief Executes a function in supervisor mode, using the supervisor-mode stack. + * @param func Function to execute. + * @param ... Function parameters, up to 3 registers. +*/ +Result svcCustomBackdoor(void *func, ...); + +///@name I/O +///@{ +/** + * @brief Gives the physical address corresponding to a virtual address. + * @param VA Virtual address. + * @param writeCheck whether to check if the VA is writable in supervisor mode + * @return The corresponding physical address, or NULL. +*/ +u32 svcConvertVAToPA(const void *VA, bool writeCheck); + +/** + * @brief Flushes a range of the data cache (L2C included). + * @param addr Start address. + * @param len Length of the range. +*/ +void svcFlushDataCacheRange(void *addr, u32 len); + +/** + * @brief Flushes the data cache entirely (L2C included). +*/ +void svcFlushEntireDataCache(void); + +/** + * @brief Invalidates a range of the instruction cache. + * @param addr Start address. + * @param len Length of the range. +*/ +void svcInvalidateInstructionCacheRange(void *addr, u32 len); + +/** + * @brief Invalidates the data cache entirely. +*/ +void svcInvalidateEntireInstructionCache(void); +///@} + +///@name Memory management +///@{ +/** + * @brief Maps a block of process memory. + * @param process Handle of the process. + * @param destAddress Address of the mapped block in the current process. + * @param srcAddress Address of the mapped block in the source process. + * @param size Size of the block of the memory to map (truncated to a multiple of 0x1000 bytes). +*/ +Result svcMapProcessMemoryEx(Handle process, u32 destAddr, u32 srcAddr, u32 size); + +/** + * @brief Unmaps a block of process memory. + * @param process Handle of the process. + * @param destAddress Address of the block of memory to unmap, in the current (destination) process. + * @param size Size of the block of memory to unmap (truncated to a multiple of 0x1000 bytes). + */ +Result svcUnmapProcessMemoryEx(Handle process, u32 destAddress, u32 size); + +/** + * @brief Controls memory mapping, with the choice to use region attributes or not. + * @param[out] addr_out The virtual address resulting from the operation. Usually the same as addr0. + * @param addr0 The virtual address to be used for the operation. + * @param addr1 The virtual address to be (un)mirrored by @p addr0 when using @ref MEMOP_MAP or @ref MEMOP_UNMAP. + * It has to be pointing to a RW memory. + * Use NULL if the operation is @ref MEMOP_FREE or @ref MEMOP_ALLOC. + * @param size The requested size for @ref MEMOP_ALLOC and @ref MEMOP_ALLOC_LINEAR. + * @param op Operation flags. See @ref MemOp. + * @param perm A combination of @ref MEMPERM_READ and @ref MEMPERM_WRITE. Using MEMPERM_EXECUTE will return an error. + * Value 0 is used when unmapping memory. + * @param isLoader Whether to use the region attributes + * If a memory is mapped for two or more addresses, you have to use MEMOP_UNMAP before being able to MEMOP_FREE it. + * MEMOP_MAP will fail if @p addr1 was already mapped to another address. + * + * @sa svcControlMemory + */ +Result svcControlMemoryEx(u32* addr_out, u32 addr0, u32 addr1, u32 size, MemOp op, MemPerm perm, bool isLoader); +///@} + +///@name System +///@{ +/** + * @brief Performs actions related to services or global handles. + * @param op The operation to perform, see @ref ServiceOp. + * + * Examples: + * svcControlService(SERVICEOP_GET_NAME, (char [12])outName, (Handle)clientOrSessionHandle); + * svcControlService(SERVICEOP_STEAL_CLIENT_SESSION, (Handle *)&outHandle, (const char *)name); + */ +Result svcControlService(ServiceOp op, ...); + +/** + * @brief Copy a handle from a process to another one. + * @param[out] out The output handle. + * @param outProcess Handle of the process of the output handle. + * @param in The input handle. Pseudo-handles are not accepted. + * @param inProcess Handle of the process of the input handle. +*/ +Result svcCopyHandle(Handle *out, Handle outProcess, Handle in, Handle inProcess); + +/** + * @brief Get the address and class name of the underlying kernel object corresponding to a handle. + * @param[out] outKAddr The output kernel address. + * @param[out] outName Output class name. The buffer should be large enough to contain it. + * @param in The input handle. +*/ +Result svcTranslateHandle(u32 *outKAddr, char *outClassName, Handle in); +///@} diff --git a/sysmodules/rosalina/include/draw.h b/sysmodules/rosalina/include/draw.h new file mode 100644 index 000000000..34794bf51 --- /dev/null +++ b/sysmodules/rosalina/include/draw.h @@ -0,0 +1,85 @@ +/* +* 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 . +* +* 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 <3ds/types.h> +#include <3ds/gfx.h> +#include "utils.h" + +#define GPU_FB_TOP_LEFT_ADDR_1 REG32(0x10400468) +#define GPU_FB_TOP_LEFT_ADDR_2 REG32(0x1040046C) +#define GPU_FB_TOP_FMT REG32(0x10400470) +#define GPU_FB_TOP_SEL REG32(0x10400478) +#define GPU_FB_TOP_STRIDE REG32(0x10400490) +#define GPU_FB_TOP_RIGHT_ADDR_1 REG32(0x10400494) +#define GPU_FB_TOP_RIGHT_ADDR_2 REG32(0x10400498) + +#define GPU_FB_BOTTOM_ADDR_1 REG32(0x10400568) +#define GPU_FB_BOTTOM_ADDR_2 REG32(0x1040056C) +#define GPU_FB_BOTTOM_FMT REG32(0x10400570) +#define GPU_FB_BOTTOM_SEL REG32(0x10400578) +#define GPU_FB_BOTTOM_STRIDE REG32(0x10400590) + +#define GPU_PSC0_CNT REG32(0x1040001C) +#define GPU_PSC1_CNT REG32(0x1040001C) + +#define GPU_TRANSFER_CNT REG32(0x10400C18) +#define GPU_CMDLIST_CNT REG32(0x104018F0) + +#define FB_BOTTOM_VRAM_ADDR ((void *)0x1F48F000) // cached +#define FB_BOTTOM_VRAM_PA 0x1848F000 +#define FB_BOTTOM_SIZE (320 * 240 * 2) + +#define SCREEN_BOT_WIDTH 320 +#define SCREEN_BOT_HEIGHT 240 + +#define SPACING_Y 11 +#define SPACING_X 6 + +#define COLOR_TITLE RGB565(0x00, 0x26, 0x1F) +#define COLOR_WHITE RGB565(0x1F, 0x3F, 0x1F) +#define COLOR_RED RGB565(0x1F, 0x00, 0x00) +#define COLOR_BLACK RGB565(0x00, 0x00, 0x00) + +#define DRAW_MAX_FORMATTED_STRING_SIZE 512 + +void Draw_Lock(void); +void Draw_Unlock(void); + +void Draw_DrawCharacter(u32 posX, u32 posY, u32 color, char character); +u32 Draw_DrawString(u32 posX, u32 posY, u32 color, const char *string); +u32 Draw_DrawFormattedString(u32 posX, u32 posY, u32 color, const char *fmt, ...); + +void Draw_FillFramebuffer(u32 value); +void Draw_ClearFramebuffer(void); +void Draw_SetupFramebuffer(void); +void Draw_RestoreFramebuffer(void); +void Draw_FlushFramebuffer(void); +u32 Draw_GetCurrentFramebufferAddress(bool top, bool left); + +void Draw_CreateBitmapHeader(u8 *dst, u32 width, u32 heigth); +u8 *Draw_ConvertFrameBufferLine(bool top, bool left, u32 y); diff --git a/sysmodules/rosalina/include/errdisp.h b/sysmodules/rosalina/include/errdisp.h new file mode 100644 index 000000000..eab4b5114 --- /dev/null +++ b/sysmodules/rosalina/include/errdisp.h @@ -0,0 +1,34 @@ +/* +* 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 . +* +* 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 <3ds/types.h> +#include "MyThread.h" + +MyThread *errDispCreateThread(void); + +void errDispThreadMain(void); diff --git a/sysmodules/rosalina/include/exheader.h b/sysmodules/rosalina/include/exheader.h new file mode 100644 index 000000000..7fc2f2867 --- /dev/null +++ b/sysmodules/rosalina/include/exheader.h @@ -0,0 +1,127 @@ +/* +* 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 . +* +* 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. +*/ + +/* File written by fincs */ + +#pragma once + +#include <3ds/types.h> + +typedef struct +{ + u8 reserved[5]; + u8 flag; + u8 remasterversion[2]; +} PACKED exheader_systeminfoflags; + +typedef struct +{ + u32 address; + u32 nummaxpages; + u32 codesize; +} PACKED exheader_codesegmentinfo; + +typedef struct +{ + u8 name[8]; + exheader_systeminfoflags flags; + exheader_codesegmentinfo text; + u8 stacksize[4]; + exheader_codesegmentinfo ro; + u8 reserved[4]; + exheader_codesegmentinfo data; + u32 bsssize; +} PACKED exheader_codesetinfo; + +typedef struct +{ + u64 programid[0x30]; +} PACKED exheader_dependencylist; + +typedef struct +{ + u8 savedatasize[4]; + u8 reserved[4]; + u8 jumpid[8]; + u8 reserved2[0x30]; +} PACKED exheader_systeminfo; + +typedef struct +{ + u8 extsavedataid[8]; + u8 systemsavedataid[8]; + u8 reserved[8]; + u8 accessinfo[7]; + u8 otherattributes; +} PACKED exheader_storageinfo; + +typedef struct +{ + u64 programid; + u32 firm; + u8 flags[3]; + u8 priority; + u16 resourcelimitdescriptor[0x10]; + exheader_storageinfo storageinfo; + u64 serviceaccesscontrol[0x20]; + u8 reserved[0x1f]; + u8 resourcelimitcategory; +} PACKED exheader_arm11systemlocalcaps; + +typedef struct +{ + u32 descriptors[28]; + u8 reserved[0x10]; +} PACKED exheader_arm11kernelcapabilities; + +typedef struct +{ + u8 descriptors[15]; + u8 descversion; +} PACKED exheader_arm9accesscontrol; + +typedef struct +{ + // systemcontrol info { + // coreinfo { + exheader_codesetinfo codesetinfo; + exheader_dependencylist deplist; + // } + exheader_systeminfo systeminfo; + // } + // accesscontrolinfo { + exheader_arm11systemlocalcaps arm11systemlocalcaps; + exheader_arm11kernelcapabilities arm11kernelcaps; + exheader_arm9accesscontrol arm9accesscontrol; + // } + struct { + u8 signature[0x100]; + u8 ncchpubkeymodulus[0x100]; + exheader_arm11systemlocalcaps arm11systemlocalcaps; + exheader_arm11kernelcapabilities arm11kernelcaps; + exheader_arm9accesscontrol arm9accesscontrol; + } PACKED accessdesc; +} PACKED exheader_header; diff --git a/sysmodules/rosalina/include/fmt.h b/sysmodules/rosalina/include/fmt.h new file mode 100644 index 000000000..f4d6d6451 --- /dev/null +++ b/sysmodules/rosalina/include/fmt.h @@ -0,0 +1,32 @@ +/* +* 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 . +* +* 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 "memory.h" +#include + +int vsprintf(char *buf, const char *fmt, va_list args); +int sprintf(char *buf, const char *fmt, ...); diff --git a/sysmodules/rosalina/include/font.h b/sysmodules/rosalina/include/font.h new file mode 100644 index 000000000..97eaf0348 --- /dev/null +++ b/sysmodules/rosalina/include/font.h @@ -0,0 +1,3083 @@ +#pragma once +//--------------------------------------------------------------------------------- +// Linux 6x10 font +// https://github.com/torvalds/linux/tree/master/lib/fonts +//--------------------------------------------------------------------------------- +#define FONT_WIDTH 6 +#define FONT_HEIGHT 10 +//--------------------------------------------------------------------------------- +static const unsigned char font[] = { + + /* 0 0x00 '^@' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 1 0x01 '^A' */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0x84, /* 10000100 */ + 0xCC, /* 11001100 */ + 0x84, /* 10000100 */ + 0xCC, /* 11001100 */ + 0xB4, /* 10110100 */ + 0x78, /* 01111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 2 0x02 '^B' */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0xFC, /* 11111100 */ + 0xB4, /* 10110100 */ + 0xFC, /* 11111100 */ + 0xB4, /* 10110100 */ + 0xCC, /* 11001100 */ + 0x78, /* 01111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 3 0x03 '^C' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x28, /* 00101000 */ + 0x7C, /* 01111100 */ + 0x7C, /* 01111100 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 4 0x04 '^D' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x7C, /* 01111100 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 5 0x05 '^E' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x38, /* 00111000 */ + 0x6C, /* 01101100 */ + 0x6C, /* 01101100 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 6 0x06 '^F' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x7C, /* 01111100 */ + 0x7C, /* 01111100 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 7 0x07 '^G' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x78, /* 01111000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 8 0x08 '^H' */ + 0xFC, /* 11111100 */ + 0xFC, /* 11111100 */ + 0xFC, /* 11111100 */ + 0xCC, /* 11001100 */ + 0x84, /* 10000100 */ + 0xCC, /* 11001100 */ + 0xFC, /* 11111100 */ + 0xFC, /* 11111100 */ + 0xFC, /* 11111100 */ + 0xFC, /* 11111100 */ + + /* 9 0x09 '^I' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x48, /* 01001000 */ + 0x84, /* 10000100 */ + 0x48, /* 01001000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 10 0x0A '^J' */ + 0xFC, /* 11111100 */ + 0xFC, /* 11111100 */ + 0xCC, /* 11001100 */ + 0xB4, /* 10110100 */ + 0x78, /* 01111000 */ + 0xB4, /* 10110100 */ + 0xCC, /* 11001100 */ + 0xFC, /* 11111100 */ + 0xFC, /* 11111100 */ + 0xFC, /* 11111100 */ + + /* 11 0x0B '^K' */ + 0x00, /* 00000000 */ + 0x3C, /* 00111100 */ + 0x14, /* 00010100 */ + 0x20, /* 00100000 */ + 0x78, /* 01111000 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 12 0x0C '^L' */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 13 0x0D '^M' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x14, /* 00010100 */ + 0x14, /* 00010100 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x70, /* 01110000 */ + 0x60, /* 01100000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 14 0x0E '^N' */ + 0x00, /* 00000000 */ + 0x3C, /* 00111100 */ + 0x24, /* 00100100 */ + 0x3C, /* 00111100 */ + 0x24, /* 00100100 */ + 0x24, /* 00100100 */ + 0x6C, /* 01101100 */ + 0x6C, /* 01101100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 15 0x0F '^O' */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x54, /* 01010100 */ + 0x38, /* 00111000 */ + 0x6C, /* 01101100 */ + 0x38, /* 00111000 */ + 0x54, /* 01010100 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 16 0x10 '^P' */ + 0x00, /* 00000000 */ + 0x40, /* 01000000 */ + 0x60, /* 01100000 */ + 0x70, /* 01110000 */ + 0x78, /* 01111000 */ + 0x70, /* 01110000 */ + 0x60, /* 01100000 */ + 0x40, /* 01000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 17 0x11 '^Q' */ + 0x00, /* 00000000 */ + 0x04, /* 00000100 */ + 0x0C, /* 00001100 */ + 0x1C, /* 00011100 */ + 0x3C, /* 00111100 */ + 0x1C, /* 00011100 */ + 0x0C, /* 00001100 */ + 0x04, /* 00000100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 18 0x12 '^R' */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x54, /* 01010100 */ + 0x10, /* 00010000 */ + 0x54, /* 01010100 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 19 0x13 '^S' */ + 0x00, /* 00000000 */ + 0x48, /* 01001000 */ + 0x48, /* 01001000 */ + 0x48, /* 01001000 */ + 0x48, /* 01001000 */ + 0x48, /* 01001000 */ + 0x00, /* 00000000 */ + 0x48, /* 01001000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 20 0x14 '^T' */ + 0x3C, /* 00111100 */ + 0x54, /* 01010100 */ + 0x54, /* 01010100 */ + 0x54, /* 01010100 */ + 0x3C, /* 00111100 */ + 0x14, /* 00010100 */ + 0x14, /* 00010100 */ + 0x14, /* 00010100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 21 0x15 '^U' */ + 0x38, /* 00111000 */ + 0x44, /* 01000100 */ + 0x20, /* 00100000 */ + 0x50, /* 01010000 */ + 0x48, /* 01001000 */ + 0x24, /* 00100100 */ + 0x14, /* 00010100 */ + 0x08, /* 00001000 */ + 0x44, /* 01000100 */ + 0x38, /* 00111000 */ + + /* 22 0x16 '^V' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xF8, /* 11111000 */ + 0xF8, /* 11111000 */ + 0xF8, /* 11111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 23 0x17 '^W' */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x54, /* 01010100 */ + 0x10, /* 00010000 */ + 0x54, /* 01010100 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x7C, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 24 0x18 '^X' */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x54, /* 01010100 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 25 0x19 '^Y' */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x54, /* 01010100 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 26 0x1A '^Z' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x08, /* 00001000 */ + 0x7C, /* 01111100 */ + 0x08, /* 00001000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 27 0x1B '^[' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x20, /* 00100000 */ + 0x7C, /* 01111100 */ + 0x20, /* 00100000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 28 0x1C '^\' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x40, /* 01000000 */ + 0x40, /* 01000000 */ + 0x40, /* 01000000 */ + 0x78, /* 01111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 29 0x1D '^]' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x48, /* 01001000 */ + 0x84, /* 10000100 */ + 0xFC, /* 11111100 */ + 0x84, /* 10000100 */ + 0x48, /* 01001000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 30 0x1E '^^' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x38, /* 00111000 */ + 0x7C, /* 01111100 */ + 0x7C, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 31 0x1F '^_' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7C, /* 01111100 */ + 0x7C, /* 01111100 */ + 0x38, /* 00111000 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 32 0x20 ' ' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 33 0x21 '!' */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 34 0x22 '"' */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 35 0x23 '#' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x28, /* 00101000 */ + 0x7C, /* 01111100 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0x7C, /* 01111100 */ + 0x28, /* 00101000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 36 0x24 '$' */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x54, /* 01010100 */ + 0x50, /* 01010000 */ + 0x38, /* 00111000 */ + 0x14, /* 00010100 */ + 0x54, /* 01010100 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + + /* 37 0x25 '%' */ + 0x00, /* 00000000 */ + 0x64, /* 01100100 */ + 0x64, /* 01100100 */ + 0x08, /* 00001000 */ + 0x10, /* 00010000 */ + 0x20, /* 00100000 */ + 0x4C, /* 01001100 */ + 0x4C, /* 01001100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 38 0x26 '&' */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x48, /* 01001000 */ + 0x50, /* 01010000 */ + 0x20, /* 00100000 */ + 0x54, /* 01010100 */ + 0x48, /* 01001000 */ + 0x34, /* 00110100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 39 0x27 ''' */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 40 0x28 '(' */ + 0x08, /* 00001000 */ + 0x10, /* 00010000 */ + 0x20, /* 00100000 */ + 0x20, /* 00100000 */ + 0x20, /* 00100000 */ + 0x20, /* 00100000 */ + 0x20, /* 00100000 */ + 0x10, /* 00010000 */ + 0x08, /* 00001000 */ + 0x00, /* 00000000 */ + + /* 41 0x29 ')' */ + 0x20, /* 00100000 */ + 0x10, /* 00010000 */ + 0x08, /* 00001000 */ + 0x08, /* 00001000 */ + 0x08, /* 00001000 */ + 0x08, /* 00001000 */ + 0x08, /* 00001000 */ + 0x10, /* 00010000 */ + 0x20, /* 00100000 */ + 0x00, /* 00000000 */ + + /* 42 0x2A '*' */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x54, /* 01010100 */ + 0x38, /* 00111000 */ + 0x54, /* 01010100 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 43 0x2B '+' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x7C, /* 01111100 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 44 0x2C ',' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x10, /* 00010000 */ + 0x20, /* 00100000 */ + + /* 45 0x2D '-' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7C, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 46 0x2E '.' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 47 0x2F '/' */ + 0x04, /* 00000100 */ + 0x04, /* 00000100 */ + 0x08, /* 00001000 */ + 0x08, /* 00001000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x20, /* 00100000 */ + 0x20, /* 00100000 */ + 0x40, /* 01000000 */ + 0x40, /* 01000000 */ + + /* 48 0x30 '0' */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x44, /* 01000100 */ + 0x4C, /* 01001100 */ + 0x54, /* 01010100 */ + 0x64, /* 01100100 */ + 0x44, /* 01000100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 49 0x31 '1' */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x30, /* 00110000 */ + 0x50, /* 01010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x7C, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 50 0x32 '2' */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x44, /* 01000100 */ + 0x04, /* 00000100 */ + 0x08, /* 00001000 */ + 0x10, /* 00010000 */ + 0x20, /* 00100000 */ + 0x7C, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 51 0x33 '3' */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x44, /* 01000100 */ + 0x04, /* 00000100 */ + 0x18, /* 00011000 */ + 0x04, /* 00000100 */ + 0x44, /* 01000100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 52 0x34 '4' */ + 0x00, /* 00000000 */ + 0x08, /* 00001000 */ + 0x18, /* 00011000 */ + 0x28, /* 00101000 */ + 0x48, /* 01001000 */ + 0x7C, /* 01111100 */ + 0x08, /* 00001000 */ + 0x08, /* 00001000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 53 0x35 '5' */ + 0x00, /* 00000000 */ + 0x7C, /* 01111100 */ + 0x40, /* 01000000 */ + 0x78, /* 01111000 */ + 0x04, /* 00000100 */ + 0x04, /* 00000100 */ + 0x44, /* 01000100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 54 0x36 '6' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x20, /* 00100000 */ + 0x40, /* 01000000 */ + 0x78, /* 01111000 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 55 0x37 '7' */ + 0x00, /* 00000000 */ + 0x7C, /* 01111100 */ + 0x04, /* 00000100 */ + 0x04, /* 00000100 */ + 0x08, /* 00001000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 56 0x38 '8' */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x38, /* 00111000 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 57 0x39 '9' */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x3C, /* 00111100 */ + 0x04, /* 00000100 */ + 0x08, /* 00001000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 58 0x3A ':' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 59 0x3B ';' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x30, /* 00110000 */ + 0x10, /* 00010000 */ + 0x20, /* 00100000 */ + + /* 60 0x3C '<' */ + 0x00, /* 00000000 */ + 0x04, /* 00000100 */ + 0x08, /* 00001000 */ + 0x10, /* 00010000 */ + 0x20, /* 00100000 */ + 0x10, /* 00010000 */ + 0x08, /* 00001000 */ + 0x04, /* 00000100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 61 0x3D '=' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7C, /* 01111100 */ + 0x00, /* 00000000 */ + 0x7C, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 62 0x3E '>' */ + 0x00, /* 00000000 */ + 0x20, /* 00100000 */ + 0x10, /* 00010000 */ + 0x08, /* 00001000 */ + 0x04, /* 00000100 */ + 0x08, /* 00001000 */ + 0x10, /* 00010000 */ + 0x20, /* 00100000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 63 0x3F '?' */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x44, /* 01000100 */ + 0x04, /* 00000100 */ + 0x08, /* 00001000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 64 0x40 '@' */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x44, /* 01000100 */ + 0x5C, /* 01011100 */ + 0x54, /* 01010100 */ + 0x5C, /* 01011100 */ + 0x40, /* 01000000 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 65 0x41 'A' */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x28, /* 00101000 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x7C, /* 01111100 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 66 0x42 'B' */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0x24, /* 00100100 */ + 0x24, /* 00100100 */ + 0x38, /* 00111000 */ + 0x24, /* 00100100 */ + 0x24, /* 00100100 */ + 0x78, /* 01111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 67 0x43 'C' */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x44, /* 01000100 */ + 0x40, /* 01000000 */ + 0x40, /* 01000000 */ + 0x40, /* 01000000 */ + 0x44, /* 01000100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 68 0x44 'D' */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0x24, /* 00100100 */ + 0x24, /* 00100100 */ + 0x24, /* 00100100 */ + 0x24, /* 00100100 */ + 0x24, /* 00100100 */ + 0x78, /* 01111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 69 0x45 'E' */ + 0x00, /* 00000000 */ + 0x7C, /* 01111100 */ + 0x40, /* 01000000 */ + 0x40, /* 01000000 */ + 0x78, /* 01111000 */ + 0x40, /* 01000000 */ + 0x40, /* 01000000 */ + 0x7C, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 70 0x46 'F' */ + 0x00, /* 00000000 */ + 0x7C, /* 01111100 */ + 0x40, /* 01000000 */ + 0x40, /* 01000000 */ + 0x78, /* 01111000 */ + 0x40, /* 01000000 */ + 0x40, /* 01000000 */ + 0x40, /* 01000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 71 0x47 'G' */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x44, /* 01000100 */ + 0x40, /* 01000000 */ + 0x5C, /* 01011100 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 72 0x48 'H' */ + 0x00, /* 00000000 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x7C, /* 01111100 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 73 0x49 'I' */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 74 0x4A 'J' */ + 0x00, /* 00000000 */ + 0x1C, /* 00011100 */ + 0x08, /* 00001000 */ + 0x08, /* 00001000 */ + 0x08, /* 00001000 */ + 0x48, /* 01001000 */ + 0x48, /* 01001000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 75 0x4B 'K' */ + 0x00, /* 00000000 */ + 0x44, /* 01000100 */ + 0x48, /* 01001000 */ + 0x50, /* 01010000 */ + 0x60, /* 01100000 */ + 0x50, /* 01010000 */ + 0x48, /* 01001000 */ + 0x44, /* 01000100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 76 0x4C 'L' */ + 0x00, /* 00000000 */ + 0x40, /* 01000000 */ + 0x40, /* 01000000 */ + 0x40, /* 01000000 */ + 0x40, /* 01000000 */ + 0x40, /* 01000000 */ + 0x40, /* 01000000 */ + 0x7C, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 77 0x4D 'M' */ + 0x00, /* 00000000 */ + 0x44, /* 01000100 */ + 0x6C, /* 01101100 */ + 0x54, /* 01010100 */ + 0x54, /* 01010100 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 78 0x4E 'N' */ + 0x00, /* 00000000 */ + 0x44, /* 01000100 */ + 0x64, /* 01100100 */ + 0x54, /* 01010100 */ + 0x4C, /* 01001100 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 79 0x4F 'O' */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 80 0x50 'P' */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x78, /* 01111000 */ + 0x40, /* 01000000 */ + 0x40, /* 01000000 */ + 0x40, /* 01000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 81 0x51 'Q' */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x54, /* 01010100 */ + 0x48, /* 01001000 */ + 0x34, /* 00110100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 82 0x52 'R' */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x78, /* 01111000 */ + 0x50, /* 01010000 */ + 0x48, /* 01001000 */ + 0x44, /* 01000100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 83 0x53 'S' */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x44, /* 01000100 */ + 0x40, /* 01000000 */ + 0x38, /* 00111000 */ + 0x04, /* 00000100 */ + 0x44, /* 01000100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 84 0x54 'T' */ + 0x00, /* 00000000 */ + 0x7C, /* 01111100 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 85 0x55 'U' */ + 0x00, /* 00000000 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 86 0x56 'V' */ + 0x00, /* 00000000 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x28, /* 00101000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 87 0x57 'W' */ + 0x00, /* 00000000 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x54, /* 01010100 */ + 0x54, /* 01010100 */ + 0x6C, /* 01101100 */ + 0x44, /* 01000100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 88 0x58 'X' */ + 0x00, /* 00000000 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x28, /* 00101000 */ + 0x10, /* 00010000 */ + 0x28, /* 00101000 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 89 0x59 'Y' */ + 0x00, /* 00000000 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x28, /* 00101000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 90 0x5A 'Z' */ + 0x00, /* 00000000 */ + 0x7C, /* 01111100 */ + 0x04, /* 00000100 */ + 0x08, /* 00001000 */ + 0x10, /* 00010000 */ + 0x20, /* 00100000 */ + 0x40, /* 01000000 */ + 0x7C, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 91 0x5B '[' */ + 0x18, /* 00011000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + + /* 92 0x5C '\' */ + 0x40, /* 01000000 */ + 0x40, /* 01000000 */ + 0x20, /* 00100000 */ + 0x20, /* 00100000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x08, /* 00001000 */ + 0x08, /* 00001000 */ + 0x04, /* 00000100 */ + 0x04, /* 00000100 */ + + /* 93 0x5D ']' */ + 0x30, /* 00110000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + + /* 94 0x5E '^' */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x28, /* 00101000 */ + 0x44, /* 01000100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 95 0x5F '_' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7C, /* 01111100 */ + 0x00, /* 00000000 */ + + /* 96 0x60 '`' */ + 0x20, /* 00100000 */ + 0x10, /* 00010000 */ + 0x08, /* 00001000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 97 0x61 'a' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x04, /* 00000100 */ + 0x3C, /* 00111100 */ + 0x44, /* 01000100 */ + 0x3C, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 98 0x62 'b' */ + 0x00, /* 00000000 */ + 0x40, /* 01000000 */ + 0x40, /* 01000000 */ + 0x58, /* 01011000 */ + 0x64, /* 01100100 */ + 0x44, /* 01000100 */ + 0x64, /* 01100100 */ + 0x58, /* 01011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 99 0x63 'c' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x44, /* 01000100 */ + 0x40, /* 01000000 */ + 0x44, /* 01000100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 100 0x64 'd' */ + 0x00, /* 00000000 */ + 0x04, /* 00000100 */ + 0x04, /* 00000100 */ + 0x34, /* 00110100 */ + 0x4C, /* 01001100 */ + 0x44, /* 01000100 */ + 0x4C, /* 01001100 */ + 0x34, /* 00110100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 101 0x65 'e' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x44, /* 01000100 */ + 0x7C, /* 01111100 */ + 0x40, /* 01000000 */ + 0x3C, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 102 0x66 'f' */ + 0x00, /* 00000000 */ + 0x0C, /* 00001100 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 103 0x67 'g' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x34, /* 00110100 */ + 0x4C, /* 01001100 */ + 0x44, /* 01000100 */ + 0x4C, /* 01001100 */ + 0x34, /* 00110100 */ + 0x04, /* 00000100 */ + 0x38, /* 00111000 */ + + /* 104 0x68 'h' */ + 0x00, /* 00000000 */ + 0x40, /* 01000000 */ + 0x40, /* 01000000 */ + 0x78, /* 01111000 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 105 0x69 'i' */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 106 0x6A 'j' */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x60, /* 01100000 */ + + /* 107 0x6B 'k' */ + 0x00, /* 00000000 */ + 0x40, /* 01000000 */ + 0x40, /* 01000000 */ + 0x48, /* 01001000 */ + 0x50, /* 01010000 */ + 0x70, /* 01110000 */ + 0x48, /* 01001000 */ + 0x44, /* 01000100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 108 0x6C 'l' */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 109 0x6D 'm' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x68, /* 01101000 */ + 0x54, /* 01010100 */ + 0x54, /* 01010100 */ + 0x54, /* 01010100 */ + 0x54, /* 01010100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 110 0x6E 'n' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x58, /* 01011000 */ + 0x64, /* 01100100 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 111 0x6F 'o' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 112 0x70 'p' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x58, /* 01011000 */ + 0x64, /* 01100100 */ + 0x44, /* 01000100 */ + 0x64, /* 01100100 */ + 0x58, /* 01011000 */ + 0x40, /* 01000000 */ + 0x40, /* 01000000 */ + + /* 113 0x71 'q' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x34, /* 00110100 */ + 0x4C, /* 01001100 */ + 0x44, /* 01000100 */ + 0x4C, /* 01001100 */ + 0x34, /* 00110100 */ + 0x04, /* 00000100 */ + 0x04, /* 00000100 */ + + /* 114 0x72 'r' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x58, /* 01011000 */ + 0x64, /* 01100100 */ + 0x40, /* 01000000 */ + 0x40, /* 01000000 */ + 0x40, /* 01000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 115 0x73 's' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3C, /* 00111100 */ + 0x40, /* 01000000 */ + 0x38, /* 00111000 */ + 0x04, /* 00000100 */ + 0x78, /* 01111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 116 0x74 't' */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x0C, /* 00001100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 117 0x75 'u' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x4C, /* 01001100 */ + 0x34, /* 00110100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 118 0x76 'v' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x28, /* 00101000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 119 0x77 'w' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x54, /* 01010100 */ + 0x54, /* 01010100 */ + 0x54, /* 01010100 */ + 0x54, /* 01010100 */ + 0x28, /* 00101000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 120 0x78 'x' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x44, /* 01000100 */ + 0x28, /* 00101000 */ + 0x10, /* 00010000 */ + 0x28, /* 00101000 */ + 0x44, /* 01000100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 121 0x79 'y' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x3C, /* 00111100 */ + 0x04, /* 00000100 */ + 0x38, /* 00111000 */ + + /* 122 0x7A 'z' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7C, /* 01111100 */ + 0x08, /* 00001000 */ + 0x10, /* 00010000 */ + 0x20, /* 00100000 */ + 0x7C, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 123 0x7B '{' */ + 0x08, /* 00001000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x20, /* 00100000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x08, /* 00001000 */ + 0x00, /* 00000000 */ + + /* 124 0x7C '|' */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + + /* 125 0x7D '}' */ + 0x20, /* 00100000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x08, /* 00001000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x20, /* 00100000 */ + 0x00, /* 00000000 */ + + /* 126 0x7E '~' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x20, /* 00100000 */ + 0x54, /* 01010100 */ + 0x08, /* 00001000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 127 0x7F '' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x28, /* 00101000 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x7C, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 128 0x80 '\200' */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x44, /* 01000100 */ + 0x40, /* 01000000 */ + 0x40, /* 01000000 */ + 0x40, /* 01000000 */ + 0x44, /* 01000100 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x20, /* 00100000 */ + + /* 129 0x81 '\201' */ + 0x00, /* 00000000 */ + 0x28, /* 00101000 */ + 0x00, /* 00000000 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x4C, /* 01001100 */ + 0x34, /* 00110100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 130 0x82 '\202' */ + 0x08, /* 00001000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x44, /* 01000100 */ + 0x7C, /* 01111100 */ + 0x40, /* 01000000 */ + 0x3C, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 131 0x83 '\203' */ + 0x10, /* 00010000 */ + 0x28, /* 00101000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x04, /* 00000100 */ + 0x3C, /* 00111100 */ + 0x44, /* 01000100 */ + 0x3C, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 132 0x84 '\204' */ + 0x00, /* 00000000 */ + 0x28, /* 00101000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x04, /* 00000100 */ + 0x3C, /* 00111100 */ + 0x44, /* 01000100 */ + 0x3C, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 133 0x85 '\205' */ + 0x10, /* 00010000 */ + 0x08, /* 00001000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x04, /* 00000100 */ + 0x3C, /* 00111100 */ + 0x44, /* 01000100 */ + 0x3C, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 134 0x86 '\206' */ + 0x18, /* 00011000 */ + 0x24, /* 00100100 */ + 0x18, /* 00011000 */ + 0x38, /* 00111000 */ + 0x04, /* 00000100 */ + 0x3C, /* 00111100 */ + 0x44, /* 01000100 */ + 0x3C, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 135 0x87 '\207' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x44, /* 01000100 */ + 0x40, /* 01000000 */ + 0x44, /* 01000100 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x20, /* 00100000 */ + + /* 136 0x88 '\210' */ + 0x10, /* 00010000 */ + 0x28, /* 00101000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x44, /* 01000100 */ + 0x7C, /* 01111100 */ + 0x40, /* 01000000 */ + 0x3C, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 137 0x89 '\211' */ + 0x00, /* 00000000 */ + 0x28, /* 00101000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x44, /* 01000100 */ + 0x7C, /* 01111100 */ + 0x40, /* 01000000 */ + 0x3C, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 138 0x8A '\212' */ + 0x20, /* 00100000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x44, /* 01000100 */ + 0x7C, /* 01111100 */ + 0x40, /* 01000000 */ + 0x3C, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 139 0x8B '\213' */ + 0x00, /* 00000000 */ + 0x28, /* 00101000 */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 140 0x8C '\214' */ + 0x10, /* 00010000 */ + 0x28, /* 00101000 */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 141 0x8D '\215' */ + 0x20, /* 00100000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 142 0x8E '\216' */ + 0x44, /* 01000100 */ + 0x10, /* 00010000 */ + 0x28, /* 00101000 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x7C, /* 01111100 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 143 0x8F '\217' */ + 0x30, /* 00110000 */ + 0x48, /* 01001000 */ + 0x38, /* 00111000 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x7C, /* 01111100 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 144 0x90 '\220' */ + 0x10, /* 00010000 */ + 0x7C, /* 01111100 */ + 0x40, /* 01000000 */ + 0x40, /* 01000000 */ + 0x78, /* 01111000 */ + 0x40, /* 01000000 */ + 0x40, /* 01000000 */ + 0x7C, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 145 0x91 '\221' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x78, /* 01111000 */ + 0x14, /* 00010100 */ + 0x7C, /* 01111100 */ + 0x50, /* 01010000 */ + 0x3C, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 146 0x92 '\222' */ + 0x00, /* 00000000 */ + 0x3C, /* 00111100 */ + 0x50, /* 01010000 */ + 0x50, /* 01010000 */ + 0x78, /* 01111000 */ + 0x50, /* 01010000 */ + 0x50, /* 01010000 */ + 0x5C, /* 01011100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 147 0x93 '\223' */ + 0x10, /* 00010000 */ + 0x28, /* 00101000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 148 0x94 '\224' */ + 0x00, /* 00000000 */ + 0x28, /* 00101000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 149 0x95 '\225' */ + 0x20, /* 00100000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 150 0x96 '\226' */ + 0x10, /* 00010000 */ + 0x28, /* 00101000 */ + 0x00, /* 00000000 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x4C, /* 01001100 */ + 0x34, /* 00110100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 151 0x97 '\227' */ + 0x20, /* 00100000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x4C, /* 01001100 */ + 0x34, /* 00110100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 152 0x98 '\230' */ + 0x00, /* 00000000 */ + 0x28, /* 00101000 */ + 0x00, /* 00000000 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x3C, /* 00111100 */ + 0x04, /* 00000100 */ + 0x38, /* 00111000 */ + + /* 153 0x99 '\231' */ + 0x84, /* 10000100 */ + 0x38, /* 00111000 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 154 0x9A '\232' */ + 0x88, /* 10001000 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 155 0x9B '\233' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x54, /* 01010100 */ + 0x50, /* 01010000 */ + 0x54, /* 01010100 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + + /* 156 0x9C '\234' */ + 0x30, /* 00110000 */ + 0x48, /* 01001000 */ + 0x40, /* 01000000 */ + 0x70, /* 01110000 */ + 0x40, /* 01000000 */ + 0x40, /* 01000000 */ + 0x44, /* 01000100 */ + 0x78, /* 01111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 157 0x9D '\235' */ + 0x00, /* 00000000 */ + 0x44, /* 01000100 */ + 0x28, /* 00101000 */ + 0x7C, /* 01111100 */ + 0x10, /* 00010000 */ + 0x7C, /* 01111100 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 158 0x9E '\236' */ + 0x00, /* 00000000 */ + 0x70, /* 01110000 */ + 0x48, /* 01001000 */ + 0x70, /* 01110000 */ + 0x48, /* 01001000 */ + 0x5C, /* 01011100 */ + 0x48, /* 01001000 */ + 0x44, /* 01000100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 159 0x9F '\237' */ + 0x00, /* 00000000 */ + 0x0C, /* 00001100 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x60, /* 01100000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 160 0xA0 '\240' */ + 0x08, /* 00001000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x04, /* 00000100 */ + 0x3C, /* 00111100 */ + 0x44, /* 01000100 */ + 0x3C, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 161 0xA1 '\241' */ + 0x08, /* 00001000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x30, /* 00110000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 162 0xA2 '\242' */ + 0x08, /* 00001000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 163 0xA3 '\243' */ + 0x08, /* 00001000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x4C, /* 01001100 */ + 0x34, /* 00110100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 164 0xA4 '\244' */ + 0x34, /* 00110100 */ + 0x58, /* 01011000 */ + 0x00, /* 00000000 */ + 0x58, /* 01011000 */ + 0x64, /* 01100100 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 165 0xA5 '\245' */ + 0x58, /* 01011000 */ + 0x44, /* 01000100 */ + 0x64, /* 01100100 */ + 0x54, /* 01010100 */ + 0x4C, /* 01001100 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 166 0xA6 '\246' */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x04, /* 00000100 */ + 0x3C, /* 00111100 */ + 0x44, /* 01000100 */ + 0x3C, /* 00111100 */ + 0x00, /* 00000000 */ + 0x7C, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 167 0xA7 '\247' */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x7C, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 168 0xA8 '\250' */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x20, /* 00100000 */ + 0x40, /* 01000000 */ + 0x44, /* 01000100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 169 0xA9 '\251' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7C, /* 01111100 */ + 0x40, /* 01000000 */ + 0x40, /* 01000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 170 0xAA '\252' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7C, /* 01111100 */ + 0x04, /* 00000100 */ + 0x04, /* 00000100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 171 0xAB '\253' */ + 0x20, /* 00100000 */ + 0x60, /* 01100000 */ + 0x24, /* 00100100 */ + 0x28, /* 00101000 */ + 0x10, /* 00010000 */ + 0x28, /* 00101000 */ + 0x44, /* 01000100 */ + 0x08, /* 00001000 */ + 0x1C, /* 00011100 */ + 0x00, /* 00000000 */ + + /* 172 0xAC '\254' */ + 0x20, /* 00100000 */ + 0x60, /* 01100000 */ + 0x24, /* 00100100 */ + 0x28, /* 00101000 */ + 0x10, /* 00010000 */ + 0x28, /* 00101000 */ + 0x58, /* 01011000 */ + 0x3C, /* 00111100 */ + 0x08, /* 00001000 */ + 0x00, /* 00000000 */ + + /* 173 0xAD '\255' */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 174 0xAE '\256' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x24, /* 00100100 */ + 0x48, /* 01001000 */ + 0x90, /* 10010000 */ + 0x48, /* 01001000 */ + 0x24, /* 00100100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 175 0xAF '\257' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x90, /* 10010000 */ + 0x48, /* 01001000 */ + 0x24, /* 00100100 */ + 0x48, /* 01001000 */ + 0x90, /* 10010000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 176 0xB0 '\260' */ + 0x10, /* 00010000 */ + 0x44, /* 01000100 */ + 0x10, /* 00010000 */ + 0x44, /* 01000100 */ + 0x10, /* 00010000 */ + 0x44, /* 01000100 */ + 0x10, /* 00010000 */ + 0x44, /* 01000100 */ + 0x10, /* 00010000 */ + 0x44, /* 01000100 */ + + /* 177 0xB1 '\261' */ + 0xA8, /* 10101000 */ + 0x54, /* 01010100 */ + 0xA8, /* 10101000 */ + 0x54, /* 01010100 */ + 0xA8, /* 10101000 */ + 0x54, /* 01010100 */ + 0xA8, /* 10101000 */ + 0x54, /* 01010100 */ + 0xA8, /* 10101000 */ + 0x54, /* 01010100 */ + + /* 178 0xB2 '\262' */ + 0xDC, /* 11011100 */ + 0x74, /* 01110100 */ + 0xDC, /* 11011100 */ + 0x74, /* 01110100 */ + 0xDC, /* 11011100 */ + 0x74, /* 01110100 */ + 0xDC, /* 11011100 */ + 0x74, /* 01110100 */ + 0xDC, /* 11011100 */ + 0x74, /* 01110100 */ + + /* 179 0xB3 '\263' */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + + /* 180 0xB4 '\264' */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0xF0, /* 11110000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + + /* 181 0xB5 '\265' */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0xF0, /* 11110000 */ + 0x10, /* 00010000 */ + 0xF0, /* 11110000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + + /* 182 0xB6 '\266' */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0xE8, /* 11101000 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + + /* 183 0xB7 '\267' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xF8, /* 11111000 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + + /* 184 0xB8 '\270' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xF0, /* 11110000 */ + 0x10, /* 00010000 */ + 0xF0, /* 11110000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + + /* 185 0xB9 '\271' */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0xE8, /* 11101000 */ + 0x08, /* 00001000 */ + 0xE8, /* 11101000 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + + /* 186 0xBA '\272' */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + + /* 187 0xBB '\273' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xF8, /* 11111000 */ + 0x08, /* 00001000 */ + 0xE8, /* 11101000 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + + /* 188 0xBC '\274' */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0xE8, /* 11101000 */ + 0x08, /* 00001000 */ + 0xF8, /* 11111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 189 0xBD '\275' */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0xF8, /* 11111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 190 0xBE '\276' */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0xF0, /* 11110000 */ + 0x10, /* 00010000 */ + 0xF0, /* 11110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 191 0xBF '\277' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xF0, /* 11110000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + + /* 192 0xC0 '\300' */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x1C, /* 00011100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 193 0xC1 '\301' */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0xFC, /* 11111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 194 0xC2 '\302' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xFC, /* 11111100 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + + /* 195 0xC3 '\303' */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x1C, /* 00011100 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + + /* 196 0xC4 '\304' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xFC, /* 11111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 197 0xC5 '\305' */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0xFC, /* 11111100 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + + /* 198 0xC6 '\306' */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x1C, /* 00011100 */ + 0x10, /* 00010000 */ + 0x1C, /* 00011100 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + + /* 199 0xC7 '\307' */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0x2C, /* 00101100 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + + /* 200 0xC8 '\310' */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0x2C, /* 00101100 */ + 0x20, /* 00100000 */ + 0x3C, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 201 0xC9 '\311' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3C, /* 00111100 */ + 0x20, /* 00100000 */ + 0x2C, /* 00101100 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + + /* 202 0xCA '\312' */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0xEC, /* 11101100 */ + 0x00, /* 00000000 */ + 0xFC, /* 11111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 203 0xCB '\313' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xFC, /* 11111100 */ + 0x00, /* 00000000 */ + 0xEC, /* 11101100 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + + /* 204 0xCC '\314' */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0x2C, /* 00101100 */ + 0x20, /* 00100000 */ + 0x2C, /* 00101100 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + + /* 205 0xCD '\315' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xFC, /* 11111100 */ + 0x00, /* 00000000 */ + 0xFC, /* 11111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 206 0xCE '\316' */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0xEC, /* 11101100 */ + 0x00, /* 00000000 */ + 0xEC, /* 11101100 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + + /* 207 0xCF '\317' */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0xFC, /* 11111100 */ + 0x00, /* 00000000 */ + 0xFC, /* 11111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 208 0xD0 '\320' */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0xFC, /* 11111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 209 0xD1 '\321' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xFC, /* 11111100 */ + 0x00, /* 00000000 */ + 0xFC, /* 11111100 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + + /* 210 0xD2 '\322' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xFC, /* 11111100 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + + /* 211 0xD3 '\323' */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0x3C, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 212 0xD4 '\324' */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x1C, /* 00011100 */ + 0x10, /* 00010000 */ + 0x1C, /* 00011100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 213 0xD5 '\325' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1C, /* 00011100 */ + 0x10, /* 00010000 */ + 0x1C, /* 00011100 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + + /* 214 0xD6 '\326' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3C, /* 00111100 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + + /* 215 0xD7 '\327' */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0xFC, /* 11111100 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + + /* 216 0xD8 '\330' */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0xFC, /* 11111100 */ + 0x10, /* 00010000 */ + 0xFC, /* 11111100 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + + /* 217 0xD9 '\331' */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0xF0, /* 11110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 218 0xDA '\332' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x1C, /* 00011100 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + + /* 219 0xDB '\333' */ + 0xFC, /* 11111100 */ + 0xFC, /* 11111100 */ + 0xFC, /* 11111100 */ + 0xFC, /* 11111100 */ + 0xFC, /* 11111100 */ + 0xFC, /* 11111100 */ + 0xFC, /* 11111100 */ + 0xFC, /* 11111100 */ + 0xFC, /* 11111100 */ + 0xFC, /* 11111100 */ + + /* 220 0xDC '\334' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xFC, /* 11111100 */ + 0xFC, /* 11111100 */ + 0xFC, /* 11111100 */ + 0xFC, /* 11111100 */ + 0xFC, /* 11111100 */ + + /* 221 0xDD '\335' */ + 0xE0, /* 11100000 */ + 0xE0, /* 11100000 */ + 0xE0, /* 11100000 */ + 0xE0, /* 11100000 */ + 0xE0, /* 11100000 */ + 0xE0, /* 11100000 */ + 0xE0, /* 11100000 */ + 0xE0, /* 11100000 */ + 0xE0, /* 11100000 */ + 0xE0, /* 11100000 */ + + /* 222 0xDE '\336' */ + 0x1C, /* 00011100 */ + 0x1C, /* 00011100 */ + 0x1C, /* 00011100 */ + 0x1C, /* 00011100 */ + 0x1C, /* 00011100 */ + 0x1C, /* 00011100 */ + 0x1C, /* 00011100 */ + 0x1C, /* 00011100 */ + 0x1C, /* 00011100 */ + 0x1C, /* 00011100 */ + + /* 223 0xDF '\337' */ + 0xFC, /* 11111100 */ + 0xFC, /* 11111100 */ + 0xFC, /* 11111100 */ + 0xFC, /* 11111100 */ + 0xFC, /* 11111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 224 0xE0 '\340' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x34, /* 00110100 */ + 0x48, /* 01001000 */ + 0x48, /* 01001000 */ + 0x48, /* 01001000 */ + 0x34, /* 00110100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 225 0xE1 '\341' */ + 0x18, /* 00011000 */ + 0x24, /* 00100100 */ + 0x44, /* 01000100 */ + 0x48, /* 01001000 */ + 0x48, /* 01001000 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x58, /* 01011000 */ + 0x40, /* 01000000 */ + 0x00, /* 00000000 */ + + /* 226 0xE2 '\342' */ + 0x00, /* 00000000 */ + 0x7C, /* 01111100 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x40, /* 01000000 */ + 0x40, /* 01000000 */ + 0x40, /* 01000000 */ + 0x40, /* 01000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 227 0xE3 '\343' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7C, /* 01111100 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0x28, /* 00101000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 228 0xE4 '\344' */ + 0x00, /* 00000000 */ + 0x7C, /* 01111100 */ + 0x24, /* 00100100 */ + 0x10, /* 00010000 */ + 0x08, /* 00001000 */ + 0x10, /* 00010000 */ + 0x24, /* 00100100 */ + 0x7C, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 229 0xE5 '\345' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x3C, /* 00111100 */ + 0x48, /* 01001000 */ + 0x48, /* 01001000 */ + 0x48, /* 01001000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 230 0xE6 '\346' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x48, /* 01001000 */ + 0x48, /* 01001000 */ + 0x48, /* 01001000 */ + 0x48, /* 01001000 */ + 0x74, /* 01110100 */ + 0x40, /* 01000000 */ + 0x40, /* 01000000 */ + + /* 231 0xE7 '\347' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x7C, /* 01111100 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x0C, /* 00001100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 232 0xE8 '\350' */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 233 0xE9 '\351' */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x7C, /* 01111100 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 234 0xEA '\352' */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x28, /* 00101000 */ + 0x6C, /* 01101100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 235 0xEB '\353' */ + 0x00, /* 00000000 */ + 0x18, /* 00011000 */ + 0x20, /* 00100000 */ + 0x18, /* 00011000 */ + 0x24, /* 00100100 */ + 0x24, /* 00100100 */ + 0x24, /* 00100100 */ + 0x18, /* 00011000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 236 0xEC '\354' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x54, /* 01010100 */ + 0x54, /* 01010100 */ + 0x54, /* 01010100 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 237 0xED '\355' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x04, /* 00000100 */ + 0x38, /* 00111000 */ + 0x54, /* 01010100 */ + 0x54, /* 01010100 */ + 0x38, /* 00111000 */ + 0x40, /* 01000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 238 0xEE '\356' */ + 0x00, /* 00000000 */ + 0x3C, /* 00111100 */ + 0x40, /* 01000000 */ + 0x40, /* 01000000 */ + 0x38, /* 00111000 */ + 0x40, /* 01000000 */ + 0x40, /* 01000000 */ + 0x3C, /* 00111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 239 0xEF '\357' */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x44, /* 01000100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 240 0xF0 '\360' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0xFC, /* 11111100 */ + 0x00, /* 00000000 */ + 0xFC, /* 11111100 */ + 0x00, /* 00000000 */ + 0xFC, /* 11111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 241 0xF1 '\361' */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x7C, /* 01111100 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x7C, /* 01111100 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 242 0xF2 '\362' */ + 0x00, /* 00000000 */ + 0x20, /* 00100000 */ + 0x10, /* 00010000 */ + 0x08, /* 00001000 */ + 0x10, /* 00010000 */ + 0x20, /* 00100000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 243 0xF3 '\363' */ + 0x00, /* 00000000 */ + 0x08, /* 00001000 */ + 0x10, /* 00010000 */ + 0x20, /* 00100000 */ + 0x10, /* 00010000 */ + 0x08, /* 00001000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 244 0xF4 '\364' */ + 0x00, /* 00000000 */ + 0x0C, /* 00001100 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + + /* 245 0xF5 '\365' */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x10, /* 00010000 */ + 0x60, /* 01100000 */ + 0x00, /* 00000000 */ + + /* 246 0xF6 '\366' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x7C, /* 01111100 */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 247 0xF7 '\367' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x20, /* 00100000 */ + 0x54, /* 01010100 */ + 0x08, /* 00001000 */ + 0x20, /* 00100000 */ + 0x54, /* 01010100 */ + 0x08, /* 00001000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 248 0xF8 '\370' */ + 0x30, /* 00110000 */ + 0x48, /* 01001000 */ + 0x48, /* 01001000 */ + 0x30, /* 00110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 249 0xF9 '\371' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x38, /* 00111000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 250 0xFA '\372' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x10, /* 00010000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 251 0xFB '\373' */ + 0x00, /* 00000000 */ + 0x04, /* 00000100 */ + 0x08, /* 00001000 */ + 0x08, /* 00001000 */ + 0x50, /* 01010000 */ + 0x50, /* 01010000 */ + 0x20, /* 00100000 */ + 0x20, /* 00100000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 252 0xFC '\374' */ + 0x60, /* 01100000 */ + 0x50, /* 01010000 */ + 0x50, /* 01010000 */ + 0x50, /* 01010000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 253 0xFD '\375' */ + 0x60, /* 01100000 */ + 0x10, /* 00010000 */ + 0x20, /* 00100000 */ + 0x70, /* 01110000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 254 0xFE '\376' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x38, /* 00111000 */ + 0x38, /* 00111000 */ + 0x38, /* 00111000 */ + 0x38, /* 00111000 */ + 0x38, /* 00111000 */ + 0x38, /* 00111000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + + /* 255 0xFF '\377' */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ + 0x00, /* 00000000 */ +}; +const int font_size = sizeof(font); diff --git a/sysmodules/rosalina/include/fsreg.h b/sysmodules/rosalina/include/fsreg.h new file mode 100644 index 000000000..6b589e55f --- /dev/null +++ b/sysmodules/rosalina/include/fsreg.h @@ -0,0 +1,41 @@ +/* +* 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 . +* +* 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 <3ds/types.h> +#include "exheader.h" + +Result fsregInit(void); +void fsregExit(void); +Result FSREG_CheckHostLoadId(u64 prog_handle); +Result FSREG_LoadProgram(u64 *prog_handle, FS_ProgramInfo *title); +Result FSREG_GetProgramInfo(exheader_header *exheader, u32 entry_count, u64 prog_handle); +Result FSREG_UnloadProgram(u64 prog_handle); +Result FSREG_Unregister(u32 pid); +Result FSREG_Register(u32 pid, u64 prog_handle, FS_ProgramInfo *info, void *storageinfo); +Result fsregSetupPermissions(void); +Handle fsregGetHandle(void); diff --git a/sysmodules/rosalina/include/gdb.h b/sysmodules/rosalina/include/gdb.h new file mode 100644 index 000000000..6b378f009 --- /dev/null +++ b/sysmodules/rosalina/include/gdb.h @@ -0,0 +1,130 @@ +/* +* 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 . +* +* 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 <3ds/types.h> +#include <3ds/svc.h> +#include <3ds/synchronization.h> +#include <3ds/result.h> +#include "sock_util.h" +#include "memory.h" + +#define MAX_DEBUG 3 +#define MAX_DEBUG_THREAD 127 +#define MAX_BREAKPOINT 256 +// 512+24 is the ideal size as IDA will try to read exactly 0x100 bytes at a time. Add 4 to this, for $#, see below. +// IDA seems to want additional bytes as well. +// 1024 is fine enough to put all regs in the 'T' stop reply packets +#define GDB_BUF_LEN 1024 + +#define GDB_HANDLER(name) GDB_Handle##name +#define GDB_QUERY_HANDLER(name) GDB_HANDLER(Query##name) +#define GDB_VERBOSE_HANDLER(name) GDB_HANDLER(Verbose##name) + +#define GDB_DECLARE_HANDLER(name) int GDB_HANDLER(name)(GDBContext *ctx) +#define GDB_DECLARE_QUERY_HANDLER(name) GDB_DECLARE_HANDLER(Query##name) +#define GDB_DECLARE_VERBOSE_HANDLER(name) GDB_DECLARE_HANDLER(Verbose##name) + +typedef struct Breakpoint +{ + u32 address; + u32 savedInstruction; + u8 instructionSize; + bool persistent; +} Breakpoint; + +typedef enum GDBFlags +{ + GDB_FLAG_SELECTED = 1, + GDB_FLAG_USED = 2, + GDB_FLAG_PROCESS_CONTINUING = 4, + GDB_FLAG_TERMINATE_PROCESS = 8, +} GDBFlags; + +typedef enum GDBState +{ + GDB_STATE_DISCONNECTED, + GDB_STATE_CONNECTED, + GDB_STATE_NOACK_SENT, + GDB_STATE_NOACK, + GDB_STATE_CLOSING +} GDBState; + +typedef struct ThreadInfo +{ + u32 id; + u32 tls; +} ThreadInfo; + +typedef struct GDBContext +{ + sock_ctx super; + + RecursiveLock lock; + GDBFlags flags; + GDBState state; + + u32 pid; + Handle debug; + ThreadInfo threadInfos[MAX_DEBUG_THREAD]; + u32 nbThreads; + + u32 currentThreadId, selectedThreadId, selectedThreadIdForContinuing; + + Handle clientAcceptedEvent, continuedEvent; + Handle eventToWaitFor; + + bool catchThreadEvents; + bool processEnded, processExited; + + DebugEventInfo latestDebugEvent; + DebugFlags continueFlags; + u32 svcMask[8]; + + u32 nbBreakpoints; + Breakpoint breakpoints[MAX_BREAKPOINT]; + + u32 nbWatchpoints; + u32 watchpoints[2]; + + bool isGDB; + char *commandData, *commandEnd; + int latestSentPacketSize; + char buffer[GDB_BUF_LEN + 4]; + + char threadListData[0x800]; + u32 threadListDataPos; + + char memoryOsInfoXmlData[0x800]; + char processesOsInfoXmlData[0x2000]; +} GDBContext; + +typedef int (*GDBCommandHandler)(GDBContext *ctx); + +void GDB_InitializeContext(GDBContext *ctx); +void GDB_FinalizeContext(GDBContext *ctx); +GDB_DECLARE_HANDLER(Unsupported); diff --git a/sysmodules/rosalina/include/gdb/breakpoints.h b/sysmodules/rosalina/include/gdb/breakpoints.h new file mode 100644 index 000000000..65cf0bb1a --- /dev/null +++ b/sysmodules/rosalina/include/gdb/breakpoints.h @@ -0,0 +1,39 @@ +/* +* 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 . +* +* 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 "gdb.h" + +// We'll actually use SVC 0xFF for breakpoints :P +#define BREAKPOINT_INSTRUCTION_ARM 0xEF0000FF +#define BREAKPOINT_INSTRUCTION_THUMB 0xDFFF + +u32 GDB_FindClosestBreakpointSlot(GDBContext *ctx, u32 address); +int GDB_GetBreakpointInstruction(u32 *instr, GDBContext *ctx, u32 address); +int GDB_AddBreakpoint(GDBContext *ctx, u32 address, bool thumb, bool persist); +int GDB_DisableBreakpointById(GDBContext *ctx, u32 id); +int GDB_RemoveBreakpoint(GDBContext *ctx, u32 address); diff --git a/sysmodules/rosalina/include/gdb/debug.h b/sysmodules/rosalina/include/gdb/debug.h new file mode 100644 index 000000000..46c4c2fdd --- /dev/null +++ b/sysmodules/rosalina/include/gdb/debug.h @@ -0,0 +1,41 @@ +/* +* 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 . +* +* 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 "gdb.h" + +GDB_DECLARE_HANDLER(Detach); +GDB_DECLARE_HANDLER(Kill); +GDB_DECLARE_HANDLER(Break); +GDB_DECLARE_HANDLER(Continue); +GDB_DECLARE_VERBOSE_HANDLER(Continue); +GDB_DECLARE_HANDLER(GetStopReason); + +void GDB_PreprocessDebugEvent(GDBContext *ctx, DebugEventInfo *info); +int GDB_SendStopReply(GDBContext *ctx, const DebugEventInfo *info); +int GDB_HandleDebugEvents(GDBContext *ctx); +void GDB_BreakProcessAndSinkDebugEvents(GDBContext *ctx, DebugFlags flags); diff --git a/sysmodules/rosalina/include/gdb/mem.h b/sysmodules/rosalina/include/gdb/mem.h new file mode 100644 index 000000000..a826c80d3 --- /dev/null +++ b/sysmodules/rosalina/include/gdb/mem.h @@ -0,0 +1,40 @@ +/* +* 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 . +* +* 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 "gdb.h" + +Result GDB_ReadMemoryInPage(void *out, GDBContext *ctx, u32 addr, u32 len); +Result GDB_WriteMemoryInPage(GDBContext *ctx, const void *in, u32 addr, u32 len); +int GDB_SendMemory(GDBContext *ctx, const char *prefix, u32 prefixLen, u32 addr, u32 len); +int GDB_WriteMemory(GDBContext *ctx, const void *buf, u32 addr, u32 len); +u32 GDB_SearchMemory(bool *found, GDBContext *ctx, u32 addr, u32 len, const void *pattern, u32 patternLen); + +GDB_DECLARE_HANDLER(ReadMemory); +GDB_DECLARE_HANDLER(WriteMemory); +GDB_DECLARE_HANDLER(WriteMemoryRaw); +GDB_DECLARE_QUERY_HANDLER(SearchMemory); diff --git a/sysmodules/rosalina/include/gdb/monitor.h b/sysmodules/rosalina/include/gdb/monitor.h new file mode 100644 index 000000000..ef6c7e643 --- /dev/null +++ b/sysmodules/rosalina/include/gdb/monitor.h @@ -0,0 +1,32 @@ +/* +* 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 . +* +* 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 "gdb.h" +#include "gdb/server.h" + +void GDB_RunMonitor(GDBServer *server); diff --git a/sysmodules/rosalina/include/gdb/net.h b/sysmodules/rosalina/include/gdb/net.h new file mode 100644 index 000000000..dec766140 --- /dev/null +++ b/sysmodules/rosalina/include/gdb/net.h @@ -0,0 +1,47 @@ +/* +* 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 . +* +* 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 "gdb.h" +#define _REENT_ONLY +#include + +u8 GDB_ComputeChecksum(const char *packetData, u32 len); +void GDB_EncodeHex(char *dst, const void *src, u32 len); +u32 GDB_DecodeHex(void *dst, const char *src, u32 len); +u32 GDB_UnescapeBinaryData(void *dst, const void *src, u32 len); +const char *GDB_ParseIntegerList(u32 *dst, const char *src, u32 nb, char sep, char lastSep, u32 base, bool allowPrefix); +const char *GDB_ParseHexIntegerList(u32 *dst, const char *src, u32 nb, char lastSep); +int GDB_ReceivePacket(GDBContext *ctx); +int GDB_SendPacket(GDBContext *ctx, const char *packetData, u32 len); +int GDB_SendFormattedPacket(GDBContext *ctx, const char *packetDataFmt, ...); +int GDB_SendHexPacket(GDBContext *ctx, const void *packetData, u32 len); +int GDB_SendStreamData(GDBContext *ctx, const char *streamData, u32 offset, u32 length, u32 totalSize, bool forceEmptyLast); +int GDB_SendDebugString(GDBContext *ctx, const char *fmt, ...); // unsecure +int GDB_ReplyEmpty(GDBContext *ctx); +int GDB_ReplyOk(GDBContext *ctx); +int GDB_ReplyErrno(GDBContext *ctx, int no); diff --git a/sysmodules/rosalina/include/gdb/query.h b/sysmodules/rosalina/include/gdb/query.h new file mode 100644 index 000000000..0fe4221ba --- /dev/null +++ b/sysmodules/rosalina/include/gdb/query.h @@ -0,0 +1,37 @@ +/* +* 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 . +* +* 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 "gdb.h" + +int GDB_HandleReadQuery(GDBContext *ctx); +int GDB_HandleWriteQuery(GDBContext *ctx); + +GDB_DECLARE_QUERY_HANDLER(Supported); +GDB_DECLARE_QUERY_HANDLER(StartNoAckMode); +GDB_DECLARE_QUERY_HANDLER(Attached); +GDB_DECLARE_QUERY_HANDLER(CatchSyscalls); diff --git a/sysmodules/rosalina/include/gdb/regs.h b/sysmodules/rosalina/include/gdb/regs.h new file mode 100644 index 000000000..62ca0c8dc --- /dev/null +++ b/sysmodules/rosalina/include/gdb/regs.h @@ -0,0 +1,34 @@ +/* +* 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 . +* +* 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 "gdb.h" + +GDB_DECLARE_HANDLER(ReadRegisters); +GDB_DECLARE_HANDLER(WriteRegisters); +GDB_DECLARE_HANDLER(ReadRegister); +GDB_DECLARE_HANDLER(WriteRegister); diff --git a/sysmodules/rosalina/include/gdb/remote_command.h b/sysmodules/rosalina/include/gdb/remote_command.h new file mode 100644 index 000000000..9d0b2d527 --- /dev/null +++ b/sysmodules/rosalina/include/gdb/remote_command.h @@ -0,0 +1,39 @@ +/* +* 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 . +* +* 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 "gdb.h" + +#define GDB_REMOTE_COMMAND_HANDLER(name) GDB_HANDLER(RemoteCommand##name) +#define GDB_DECLARE_REMOTE_COMMAND_HANDLER(name) GDB_DECLARE_HANDLER(RemoteCommand##name) + +GDB_DECLARE_REMOTE_COMMAND_HANDLER(SyncRequestInfo); +GDB_DECLARE_REMOTE_COMMAND_HANDLER(TranslateHandle); +GDB_DECLARE_REMOTE_COMMAND_HANDLER(GetMmuConfig); +GDB_DECLARE_REMOTE_COMMAND_HANDLER(FlushCaches); + +GDB_DECLARE_QUERY_HANDLER(Rcmd); diff --git a/sysmodules/rosalina/include/gdb/server.h b/sysmodules/rosalina/include/gdb/server.h new file mode 100644 index 000000000..f4364e5db --- /dev/null +++ b/sysmodules/rosalina/include/gdb/server.h @@ -0,0 +1,55 @@ +/* +* 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 . +* +* 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 "gdb.h" + +#ifndef GDB_PORT_BASE +#define GDB_PORT_BASE 4000 +#endif + +typedef struct GDBServer +{ + sock_server super; + s32 referenceCount; + Handle statusUpdated; + GDBContext ctxs[MAX_DEBUG]; +} GDBServer; + +Result GDB_InitializeServer(GDBServer *server); +void GDB_FinalizeServer(GDBServer *server); + +void GDB_IncrementServerReferenceCount(GDBServer *server); +void GDB_DecrementServerReferenceCount(GDBServer *server); + +void GDB_RunServer(GDBServer *server); + +int GDB_AcceptClient(GDBContext *ctx); +int GDB_CloseClient(GDBContext *ctx); +GDBContext *GDB_GetClient(GDBServer *server, u16 port); +void GDB_ReleaseClient(GDBServer *server, GDBContext *ctx); +int GDB_DoPacket(GDBContext *ctx); diff --git a/sysmodules/rosalina/include/gdb/stop_point.h b/sysmodules/rosalina/include/gdb/stop_point.h new file mode 100644 index 000000000..e278ebbc7 --- /dev/null +++ b/sysmodules/rosalina/include/gdb/stop_point.h @@ -0,0 +1,31 @@ +/* +* 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 . +* +* 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 "gdb.h" + +GDB_DECLARE_HANDLER(ToggleStopPoint); diff --git a/sysmodules/rosalina/include/gdb/thread.h b/sysmodules/rosalina/include/gdb/thread.h new file mode 100644 index 000000000..dd792926e --- /dev/null +++ b/sysmodules/rosalina/include/gdb/thread.h @@ -0,0 +1,41 @@ +/* +* 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 . +* +* 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 "gdb.h" + +u32 GDB_GetCurrentThreadFromList(GDBContext *ctx, u32 *threadIds, u32 nbThreads); +u32 GDB_GetCurrentThread(GDBContext *ctx); + +GDB_DECLARE_HANDLER(SetThreadId); +GDB_DECLARE_HANDLER(IsThreadAlive); + +GDB_DECLARE_QUERY_HANDLER(CurrentThreadId); +GDB_DECLARE_QUERY_HANDLER(fThreadInfo); +GDB_DECLARE_QUERY_HANDLER(sThreadInfo); +GDB_DECLARE_QUERY_HANDLER(ThreadEvents); +GDB_DECLARE_QUERY_HANDLER(ThreadExtraInfo); diff --git a/sysmodules/rosalina/include/gdb/verbose.h b/sysmodules/rosalina/include/gdb/verbose.h new file mode 100644 index 000000000..ce0062926 --- /dev/null +++ b/sysmodules/rosalina/include/gdb/verbose.h @@ -0,0 +1,32 @@ +/* +* 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 . +* +* 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 "gdb.h" + +GDB_DECLARE_HANDLER(VerboseCommand); +GDB_DECLARE_VERBOSE_HANDLER(ContinueSupported); diff --git a/sysmodules/rosalina/include/gdb/watchpoints.h b/sysmodules/rosalina/include/gdb/watchpoints.h new file mode 100644 index 000000000..2b4190d20 --- /dev/null +++ b/sysmodules/rosalina/include/gdb/watchpoints.h @@ -0,0 +1,44 @@ +/* +* 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 . +* +* 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 "gdb.h" + +typedef enum WatchpointKind +{ + WATCHPOINT_DISABLED = 0, + WATCHPOINT_READ, + WATCHPOINT_WRITE, + WATCHPOINT_READWRITE +} WatchpointKind; + +void GDB_ResetWatchpoints(void); // needed for software breakpoints to be detected as debug events as well + +int GDB_AddWatchpoint(GDBContext *ctx, u32 address, u32 size, WatchpointKind kind); +int GDB_RemoveWatchpoint(GDBContext *ctx, u32 address, WatchpointKind kind); + +WatchpointKind GDB_GetWatchpointKind(GDBContext *ctx, u32 address); diff --git a/sysmodules/rosalina/include/gdb/xfer.h b/sysmodules/rosalina/include/gdb/xfer.h new file mode 100644 index 000000000..2c84ccb2d --- /dev/null +++ b/sysmodules/rosalina/include/gdb/xfer.h @@ -0,0 +1,45 @@ +/* +* 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 . +* +* 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 "gdb.h" + +#define GDB_XFER_HANDLER(name) GDB_HANDLER(Xfer##name) +#define GDB_DECLARE_XFER_HANDLER(name) int GDB_XFER_HANDLER(name)(GDBContext *ctx, bool write, const char *annex, u32 offset, u32 length) + +#define GDB_XFER_OSDATA_HANDLER(name) GDB_XFER_HANDLER(OsData##name) +#define GDB_DECLARE_XFER_OSDATA_HANDLER(name) int GDB_XFER_OSDATA_HANDLER(name)(GDBContext *ctx, bool write, u32 offset, u32 length) + +GDB_DECLARE_XFER_HANDLER(Features); + +GDB_DECLARE_XFER_OSDATA_HANDLER(CfwVersion); +GDB_DECLARE_XFER_OSDATA_HANDLER(Memory); +GDB_DECLARE_XFER_OSDATA_HANDLER(Processes); + +GDB_DECLARE_XFER_HANDLER(OsData); + +GDB_DECLARE_QUERY_HANDLER(Xfer); diff --git a/sysmodules/rosalina/include/hbloader.h b/sysmodules/rosalina/include/hbloader.h new file mode 100644 index 000000000..97d34ccc2 --- /dev/null +++ b/sysmodules/rosalina/include/hbloader.h @@ -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 . +* +* 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. +*/ + +/* File mainly written by fincs */ +#pragma once + +#include <3ds/types.h> +#include "MyThread.h" + +#define HBLDR_DEFAULT_3DSX_TID 0x000400000D921E00ULL +#define HBLDR_3DSX_TID (*(vu64 *)0x1FF81100) + +MyThread *hbldrCreateThread(void); + +void hbldrThreadMain(void); diff --git a/sysmodules/rosalina/include/ifile.h b/sysmodules/rosalina/include/ifile.h new file mode 100644 index 000000000..f3f070ace --- /dev/null +++ b/sysmodules/rosalina/include/ifile.h @@ -0,0 +1,44 @@ +/* +* 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 . +* +* 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 <3ds/types.h> + +#define PATH_MAX 255 + +typedef struct +{ + Handle handle; + u64 pos; + u64 size; +} IFile; + +Result IFile_Open(IFile *file, FS_ArchiveID archiveId, FS_Path archivePath, FS_Path filePath, u32 flags); +Result IFile_Close(IFile *file); +Result IFile_GetSize(IFile *file, u64 *size); +Result IFile_Read(IFile *file, u64 *total, void *buffer, u32 len); +Result IFile_Write(IFile *file, u64 *total, void *buffer, u32 len, u32 flags); diff --git a/sysmodules/rosalina/include/input_redirection.h b/sysmodules/rosalina/include/input_redirection.h new file mode 100644 index 000000000..2ff384c7e --- /dev/null +++ b/sysmodules/rosalina/include/input_redirection.h @@ -0,0 +1,39 @@ +/* +* 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 . +* +* 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 <3ds/types.h> +#include "MyThread.h" + +extern bool inputRedirectionEnabled; +extern Handle inputRedirectionThreadStartedEvent; + +extern int inputRedirectionStartResult; + +MyThread *inputRedirectionCreateThread(void); +void inputRedirectionThreadMain(void); +Result InputRedirection_DoOrUndoPatches(void); diff --git a/sysmodules/rosalina/include/kernel_extension.h b/sysmodules/rosalina/include/kernel_extension.h new file mode 100644 index 000000000..2e2afe5dd --- /dev/null +++ b/sysmodules/rosalina/include/kernel_extension.h @@ -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 . +* +* 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 + +#define PA_FROM_VA_PTR(addr) PA_PTR(convertVAToPA(addr)) + +#include "utils.h" + +Result svc0x2F(void *function, ...); // custom backdoor before kernel ext. is installed (and only before!) + +void *convertVAToPA(const void *VA); + +extern u8 kernel_extension[]; +extern u32 kernel_extension_size; diff --git a/sysmodules/rosalina/include/kernel_extension_setup.h b/sysmodules/rosalina/include/kernel_extension_setup.h new file mode 100644 index 000000000..5364df34b --- /dev/null +++ b/sysmodules/rosalina/include/kernel_extension_setup.h @@ -0,0 +1,30 @@ +/* +* 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 . +* +* 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 <3ds/types.h> + +void installKernelExtension(void); diff --git a/sysmodules/rosalina/include/memory.h b/sysmodules/rosalina/include/memory.h new file mode 100644 index 000000000..e2712b0f8 --- /dev/null +++ b/sysmodules/rosalina/include/memory.h @@ -0,0 +1,44 @@ +/* +* 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 . +* +* 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 <3ds/types.h> + +void *memcpy(void *dest, const void *src, u32 size); +int memcmp(const void *buf1, const void *buf2, u32 size); +void *memset(void *dest, u32 value, u32 size) __attribute__((used)); +void *memset32(void *dest, u32 value, u32 size); +u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSize); +char *strcpy(char *dest, const char *src); +char *strncpy(char *dest, const char *src, u32 size); +s32 strnlen(const char *string, s32 maxlen); +s32 strlen(const char *string); +s32 strcmp(const char *str1, const char *str2); +s32 strncmp(const char *str1, const char *str2, u32 size); +const char *strchr(const char *string, int c); +void hexItoa(u64 number, char *out, u32 digits, bool uppercase); +unsigned long int xstrtoul(const char *nptr, char **endptr, int base, bool allowPrefix, bool *ok); diff --git a/sysmodules/rosalina/include/menu.h b/sysmodules/rosalina/include/menu.h new file mode 100644 index 000000000..9cf5a2648 --- /dev/null +++ b/sysmodules/rosalina/include/menu.h @@ -0,0 +1,85 @@ +/* +* 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 . +* +* 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 <3ds/types.h> +#include "MyThread.h" +#include "utils.h" + +#define HID_PAD (REG32(0x10146000) ^ 0xFFF) + +#define BUTTON_A (1 << 0) +#define BUTTON_B (1 << 1) +#define BUTTON_SELECT (1 << 2) +#define BUTTON_START (1 << 3) +#define BUTTON_RIGHT (1 << 4) +#define BUTTON_LEFT (1 << 5) +#define BUTTON_UP (1 << 6) +#define BUTTON_DOWN (1 << 7) +#define BUTTON_R1 (1 << 8) +#define BUTTON_L1 (1 << 9) +#define BUTTON_X (1 << 10) +#define BUTTON_Y (1 << 11) + +#define DEFAULT_MENU_COMBO (BUTTON_L1 | BUTTON_DOWN | BUTTON_SELECT) + +#define CORE_APPLICATION 0 +#define CORE_SYSTEM 1 + +typedef enum MenuItemAction { + METHOD, + MENU +} MenuItemAction; +typedef struct MenuItem { + const char *title; + + MenuItemAction action_type; + union { + struct Menu *menu; + void (*method)(void); + }; +} MenuItem; +typedef struct Menu { + const char *title; + + u32 nbItems; + MenuItem items[0x40]; +} Menu; + +extern bool terminationRequest; +extern Handle terminationRequestEvent; + +extern u32 menuCombo; + +u32 waitInputWithTimeout(u32 msec); +u32 waitInput(void); + +MyThread *menuCreateThread(void); +void menuEnter(void); +void menuLeave(void); +void menuThreadMain(void); +void menuShow(Menu *root); diff --git a/sysmodules/rosalina/include/menus.h b/sysmodules/rosalina/include/menus.h new file mode 100644 index 000000000..bf0b0cf3f --- /dev/null +++ b/sysmodules/rosalina/include/menus.h @@ -0,0 +1,37 @@ + +/* +* 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 . +* +* 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 <3ds/types.h> +#include "menu.h" + +extern Menu rosalinaMenu; + +void RosalinaMenu_TakeScreenshot(void); +void RosalinaMenu_ShowCredits(void); +void RosalinaMenu_ProcessList(void); diff --git a/sysmodules/rosalina/include/menus/debugger.h b/sysmodules/rosalina/include/menus/debugger.h new file mode 100644 index 000000000..2487e0c81 --- /dev/null +++ b/sysmodules/rosalina/include/menus/debugger.h @@ -0,0 +1,35 @@ +/* +* 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 . +* +* 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 <3ds/types.h> +#include "menu.h" + +extern Menu debuggerMenu; + +void DebuggerMenu_EnableDebugger(void); +void DebuggerMenu_DisableDebugger(void); diff --git a/sysmodules/rosalina/include/menus/miscellaneous.h b/sysmodules/rosalina/include/menus/miscellaneous.h new file mode 100644 index 000000000..f46439ed0 --- /dev/null +++ b/sysmodules/rosalina/include/menus/miscellaneous.h @@ -0,0 +1,36 @@ +/* +* 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 . +* +* 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 <3ds/types.h> +#include "menu.h" + +extern Menu miscellaneousMenu; + +void MiscellaneousMenu_SwitchBoot3dsxTargetTitle(void); +void MiscellaneousMenu_ChangeMenuCombo(void); +void MiscellaneousMenu_InputRedirection(void); diff --git a/sysmodules/rosalina/include/menus/n3ds.h b/sysmodules/rosalina/include/menus/n3ds.h new file mode 100644 index 000000000..1ee202432 --- /dev/null +++ b/sysmodules/rosalina/include/menus/n3ds.h @@ -0,0 +1,36 @@ +/* +* 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 . +* +* 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 <3ds/types.h> +#include "menu.h" + +extern Menu N3DSMenu; + +void N3DSMenu_UpdateStatus(void); +void N3DSMenu_ChangeClockRate(void); +void N3DSMenu_EnableDisableL2Cache(void); diff --git a/sysmodules/rosalina/include/menus/process_list.h b/sysmodules/rosalina/include/menus/process_list.h new file mode 100644 index 000000000..a0564c3f5 --- /dev/null +++ b/sysmodules/rosalina/include/menus/process_list.h @@ -0,0 +1,33 @@ +/* +* 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 . +* +* 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 <3ds/types.h> + +#define PROCESSES_PER_MENU_PAGE 18 + +void RosalinaMenu_ProcessList(void); diff --git a/sysmodules/rosalina/include/menus/process_patches.h b/sysmodules/rosalina/include/menus/process_patches.h new file mode 100644 index 000000000..aa2e52d30 --- /dev/null +++ b/sysmodules/rosalina/include/menus/process_patches.h @@ -0,0 +1,35 @@ +/* +* 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 . +* +* 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 <3ds/types.h> +#include "menu.h" + +extern Menu processPatchesMenu; + +void ProcessPatchesMenu_PatchUnpatchSM(void); +void ProcessPatchesMenu_PatchUnpatchFS(void); diff --git a/sysmodules/rosalina/include/minisoc.h b/sysmodules/rosalina/include/minisoc.h new file mode 100644 index 000000000..8b82b4406 --- /dev/null +++ b/sysmodules/rosalina/include/minisoc.h @@ -0,0 +1,62 @@ +/* +* 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 . +* +* 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 +#include <3ds/types.h> +#include <3ds/svc.h> +#include <3ds/srv.h> +#include <3ds/services/soc.h> +#include + +#define _REENT_ONLY +#include + +#define SYNC_ERROR ENODEV + +extern Handle SOCU_handle; +extern Handle socMemhandle; + +Result miniSocInit(); +Result miniSocExit(void); + +s32 _net_convert_error(s32 sock_retval); + +int socSocket(int domain, int type, int protocol); +int socBind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); +int socListen(int sockfd, int max_connections); +int socAccept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); +int socPoll(struct pollfd *fds, nfds_t nfds, int timeout); +int socSetsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen); +int socClose(int sockfd); + +ssize_t soc_recv(int sockfd, void *buf, size_t len, int flags); +ssize_t soc_send(int sockfd, const void *buf, size_t len, int flags); + +// actually provided by ctrulib +ssize_t soc_recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen); +ssize_t soc_sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen); diff --git a/sysmodules/rosalina/include/services.h b/sysmodules/rosalina/include/services.h new file mode 100644 index 000000000..a27a33e94 --- /dev/null +++ b/sysmodules/rosalina/include/services.h @@ -0,0 +1,40 @@ +/* +* 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 . +* +* 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 <3ds/types.h> + +#define SDK_VERSION 0x70200C8 + +/// Initializes the service API. +Result srvSysInit(void); + +/// Exits the service API. +Result srvSysExit(void); + +/// Initializes FSUSER. Requires FSREG. +void fsSysInit(void); diff --git a/sysmodules/rosalina/include/sock_util.h b/sysmodules/rosalina/include/sock_util.h new file mode 100644 index 000000000..cef6d32d1 --- /dev/null +++ b/sysmodules/rosalina/include/sock_util.h @@ -0,0 +1,95 @@ +/* +* 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 . +* +* 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. +*/ + +/* File mainly written by Stary */ + +#pragma once +#include <3ds/types.h> +#include +#include + +#define MAX_PORTS 3 +#define MAX_CTXS (2 * MAX_PORTS) + +struct sock_server; +struct sock_ctx; + +typedef int (*sock_accept_cb)(struct sock_ctx *client_ctx); +typedef int (*sock_data_cb)(struct sock_ctx *client_ctx); +typedef int (*sock_close_cb)(struct sock_ctx *client_ctx); + +typedef struct sock_ctx* (*sock_alloc_func)(struct sock_server *serv, u16 port); +typedef void (*sock_free_func)(struct sock_server *serv, struct sock_ctx *ctx); + +typedef enum socket_type +{ + SOCK_NONE, + SOCK_SERVER, + SOCK_CLIENT +} socket_type; + +typedef struct sock_ctx +{ + enum socket_type type; + bool should_close; + int sockfd; + struct sockaddr_in addr_in; + struct sock_ctx *serv; + int n; + int i; +} sock_ctx; + +typedef struct sock_server +{ + // params + u32 host; + int clients_per_server; + + // poll stuff + struct pollfd poll_fds[MAX_CTXS]; + struct sock_ctx serv_ctxs[MAX_PORTS]; + struct sock_ctx *ctx_ptrs[MAX_CTXS]; + + nfds_t nfds; + bool running; + Handle started_event; + bool compact_needed; + + // callbacks + sock_accept_cb accept_cb; + sock_data_cb data_cb; + sock_close_cb close_cb; + + sock_alloc_func alloc; + sock_free_func free; + + Handle shall_terminate_event; +} sock_server; + +Result server_init(struct sock_server *serv); +void server_bind(struct sock_server *serv, u16 port); +void server_run(struct sock_server *serv); +void server_finalize(struct sock_server *serv); diff --git a/sysmodules/rosalina/include/utils.h b/sysmodules/rosalina/include/utils.h new file mode 100644 index 000000000..2896afcb9 --- /dev/null +++ b/sysmodules/rosalina/include/utils.h @@ -0,0 +1,59 @@ +/* +* 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 . +* +* 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 <3ds/svc.h> +#include <3ds/result.h> +#include "csvc.h" + +// For accessing physmem uncached (and directly) +#define PA_PTR(addr) (void *)((u32)(addr) | 1 << 31) + +#ifndef PA_FROM_VA_PTR +#define PA_FROM_VA_PTR(addr) PA_PTR(svcConvertVAToPA((const void *)(addr), false)) +#endif + +#define REG32(addr) (*(vu32 *)(PA_PTR(addr))) + +static inline u32 makeARMBranch(const void *src, const void *dst, bool link) // the macros for those are ugly and buggy +{ + u32 instrBase = link ? 0xEB000000 : 0xEA000000; + u32 off = (u32)((const u8 *)dst - ((const u8 *)src + 8)); // the PC is always two instructions ahead of the one being executed + + return instrBase | ((off >> 2) & 0xFFFFFF); +} + +static inline void *decodeARMBranch(const void *src) +{ + u32 instr = *(const u32 *)src; + s32 off = (instr & 0xFFFFFF) << 2; + off = (off << 6) >> 6; // sign extend + + return (void *)((const u8 *)src + 8 + off); +} + +Result OpenProcessByName(const char *name, Handle *h); diff --git a/exceptions/arm11/Makefile b/sysmodules/rosalina/kernel_extension/Makefile similarity index 54% rename from exceptions/arm11/Makefile rename to sysmodules/rosalina/kernel_extension/Makefile index c66608e66..45d916c24 100644 --- a/exceptions/arm11/Makefile +++ b/sysmodules/rosalina/kernel_extension/Makefile @@ -6,33 +6,37 @@ endif include $(DEVKITARM)/base_tools -name := arm11_exceptions +name := kernel_extension dir_source := source +dir_include := include dir_build := build -dir_out := ../../$(dir_build) -ASFLAGS := -mcpu=mpcore -mfpu=vfp -CFLAGS := -Wall -Wextra -MMD -MP -mthumb $(ASFLAGS) -fno-builtin -std=c11 -Wno-main -O2 -flto -ffast-math -LDFLAGS := -nostdlib +ARCH := -mcpu=mpcore -mfpu=vfp +ASFLAGS := $(ARCH) +CFLAGS := -Wall -Wextra -MMD -MP -marm $(ASFLAGS) -I$(dir_include) -fno-builtin -std=c11 -Wno-main -O2 -flto -ffast-math \ +-mword-relocations -ffunction-sections -fdata-sections +LDFLAGS := -nostdlib -Wl,--gc-sections $(ARCH) objects = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \ - $(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \ - $(call rwildcard, $(dir_source), *.s *.c))) + $(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \ + $(call rwildcard, $(dir_source), *.s *.c))) .PHONY: all -all: $(dir_out)/$(name).bin +all: ../$(dir_build)/$(name).bin .PHONY: clean clean: @rm -rf $(dir_build) -$(dir_out)/$(name).bin: $(dir_build)/$(name).elf +../$(dir_build)/$(name).bin: $(dir_build)/$(name).elf $(OBJCOPY) -S -O binary $< $@ $(dir_build)/$(name).elf: $(objects) $(CC) $(LDFLAGS) -T linker.ld $(OUTPUT_OPTION) $^ +$(dir_build)/memory.o : CFLAGS += -O3 -marm + $(dir_build)/%.o: $(dir_source)/%.c @mkdir -p "$(@D)" $(COMPILE.c) $(OUTPUT_OPTION) $< @@ -40,3 +44,4 @@ $(dir_build)/%.o: $(dir_source)/%.c $(dir_build)/%.o: $(dir_source)/%.s @mkdir -p "$(@D)" $(COMPILE.s) $(OUTPUT_OPTION) $< +include $(call rwildcard, $(dir_build), *.d) diff --git a/exceptions/arm11/source/handlers.h b/sysmodules/rosalina/kernel_extension/include/fatalExceptionHandlers.h similarity index 62% rename from exceptions/arm11/source/handlers.h rename to sysmodules/rosalina/kernel_extension/include/fatalExceptionHandlers.h index 95dcdb1a6..bf5e9ebd3 100644 --- a/exceptions/arm11/source/handlers.h +++ b/sysmodules/rosalina/kernel_extension/include/fatalExceptionHandlers.h @@ -1,6 +1,6 @@ /* * This file is part of Luma3DS -* Copyright (C) 2016 Aurora Wright, TuxSH +* 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 @@ -15,15 +15,28 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * -* Additional Terms 7.b of GPLv3 applies 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. +* 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" +bool isExceptionFatal(u32 spsr); +bool isDataAbortExceptionRangeControlled(u32 spsr, u32 addr); + + +void FIQHandler(void); +void undefinedInstructionHandler(void); +void prefetchAbortHandler(void); +void dataAbortHandler(void); + typedef struct __attribute__((packed)) { u32 magic[2]; @@ -38,11 +51,3 @@ typedef struct __attribute__((packed)) u32 stackDumpSize; u32 additionalDataSize; } ExceptionDumpHeader; - -void __attribute__((noreturn)) mcuReboot(void); -void cleanInvalidateDCacheAndDMB(void); -bool cannotAccessVA(const void *address); -void FIQHandler(void); -void undefinedInstructionHandler(void); -void dataAbortHandler(void); -void prefetchAbortHandler(void); \ No newline at end of file diff --git a/sysmodules/rosalina/kernel_extension/include/globals.h b/sysmodules/rosalina/kernel_extension/include/globals.h new file mode 100644 index 000000000..c6161647c --- /dev/null +++ b/sysmodules/rosalina/kernel_extension/include/globals.h @@ -0,0 +1,121 @@ +/* +* 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 . +* +* 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 "kernel.h" + +extern KRecursiveLock *criticalSectionLock; +extern KObjectList *threadList; +extern KObjectMutex *synchronizationMutex; + +extern void (*KRecursiveLock__Lock)(KRecursiveLock *this); +extern void (*KRecursiveLock__Unlock)(KRecursiveLock *this); + +extern void (*KAutoObject__AddReference)(KAutoObject *this); + +extern KProcess * (*KProcessHandleTable__ToKProcess)(KProcessHandleTable *this, Handle processHandle); +extern KThread * (*KProcessHandleTable__ToKThread)(KProcessHandleTable *this, Handle threadHandle); +extern KAutoObject * (*KProcessHandleTable__ToKAutoObject)(KProcessHandleTable *this, Handle handle); +extern void (*KSynchronizationObject__Signal)(KSynchronizationObject *this, bool isPulse); +extern Result (*WaitSynchronization1)(void *this_unused, KThread *thread, KSynchronizationObject *syncObject, s64 timeout); +extern Result (*KProcessHandleTable__CreateHandle)(KProcessHandleTable *this, Handle *out, KAutoObject *obj, u8 token); +extern Result (*KProcessHwInfo__MapProcessMemory)(KProcessHwInfo *this, KProcessHwInfo *other, void *dst, void *src, u32 nbPages); +extern Result (*KProcessHwInfo__UnmapProcessMemory)(KProcessHwInfo *this, void *addr, u32 nbPages); +extern Result (*KEvent__Clear)(KEvent *this); +extern void (*KObjectMutex__WaitAndAcquire)(KObjectMutex *this); +extern void (*KObjectMutex__ErrorOccured)(void); + +extern void (*KScheduler__AdjustThread)(KScheduler *this, KThread *thread, u32 oldSchedulingMask); +extern void (*KScheduler__AttemptSwitchingThreadContext)(KScheduler *this); + +extern Result (*ControlMemory)(u32 *addrOut, u32 addr0, u32 addr1, u32 size, MemOp op, MemPerm perm, bool isLoader); +extern void (*SleepThread)(s64 ns); +extern Result (*CloseHandle)(Handle handle); +extern Result (*GetSystemInfo)(s64 *out, s32 type, s32 param); +extern Result (*GetProcessInfo)(s64 *out, Handle processHandle, u32 type); +extern Result (*GetThreadInfo)(s64 *out, Handle threadHandle, u32 type); +extern Result (*ConnectToPort)(Handle *out, const char *name); +extern Result (*SendSyncRequest)(Handle handle); +extern Result (*OpenProcess)(Handle *out, u32 processId); +extern Result (*GetProcessId)(u32 *out, Handle process); +extern Result (*DebugActiveProcess)(Handle *out, u32 processId); +extern Result (*KernelSetState)(u32 type, u32 varg1, u32 varg2, u32 varg3); + +extern void (*flushDataCacheRange)(void *addr, u32 len); +extern void (*invalidateInstructionCacheRange)(void *addr, u32 len); + +extern bool (*usrToKernelMemcpy8)(void *dst, const void *src, u32 len); +extern bool (*usrToKernelMemcpy32)(u32 *dst, const u32 *src, u32 len); +extern s32 (*usrToKernelStrncpy)(char *dst, const char *src, u32 len); +extern bool (*kernelToUsrMemcpy8)(void *dst, const void *src, u32 len); +extern bool (*kernelToUsrMemcpy32)(u32 *dst, const u32 *src, u32 len); +extern s32 (*kernelToUsrStrncpy)(char *dst, const char *src, u32 len); + +extern Result (*CustomBackdoor)(void *function, ...); + +extern void (*svcFallbackHandler)(u8 svcId); +extern void (*kernelpanic)(void); +extern void (*PostprocessSvc)(void); + +extern Result (*SignalDebugEvent)(DebugEventType type, u32 info, ...); + +extern bool isN3DS; +extern u32 *exceptionStackTop; + +extern u32 TTBCR; +extern u32 L1MMUTableAddrs[4]; + +extern u32 kernelVersion; +extern void *kernelUsrCopyFuncsStart, *kernelUsrCopyFuncsEnd; + +extern bool *isDevUnit; + +extern InterruptManager *interruptManager; +extern KBaseInterruptEvent *customInterruptEvent; + +extern void (*initFPU)(void); +extern void (*mcuReboot)(void); +extern void (*coreBarrier)(void); + +typedef struct PACKED CfwInfo +{ + char magic[4]; + + u8 versionMajor; + u8 versionMinor; + u8 versionBuild; + u8 flags; + + u32 commitHash; + + u32 config; +} CfwInfo; + +extern CfwInfo cfwInfo; + +extern u32 rosalinaState; +extern bool hasStartedRosalinaNetworkFuncsOnce; diff --git a/sysmodules/rosalina/kernel_extension/include/ipc.h b/sysmodules/rosalina/kernel_extension/include/ipc.h new file mode 100644 index 000000000..c307d1989 --- /dev/null +++ b/sysmodules/rosalina/kernel_extension/include/ipc.h @@ -0,0 +1,61 @@ +/* +* 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 . +* +* 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" +#include "globals.h" +#include "kernel.h" +#include "utils.h" + +#define MAX_SESSION 345 + +// the structure of sessions is apparently not the same on older versions... + +typedef struct SessionInfo +{ + KSession *session; + char name[12]; +} SessionInfo; + +typedef struct LangemuAttributes +{ + u64 titleId; + u8 mask, region, language, country, state; +} LangemuAttributes; + +extern KRecursiveLock processLangemuLock; +extern LangemuAttributes processLangemuAttributes[0x40]; + +SessionInfo *SessionInfo_Lookup(KSession *session); +SessionInfo *SessionInfo_FindFirst(const char *name); +void SessionInfo_ChangeVtable(KSession *session); +void SessionInfo_Add(KSession *session, const char *name); +void SessionInfo_Remove(KSession *session); + +bool doLangEmu(Result *res, Handle handle, u32 *cmdbuf); +Result doPublishToProcessHook(Handle handle, u32 *cmdbuf); +bool doErrfThrowHook(u32 *cmdbuf); diff --git a/sysmodules/rosalina/kernel_extension/include/kernel.h b/sysmodules/rosalina/kernel_extension/include/kernel.h new file mode 100644 index 000000000..52d0ef14f --- /dev/null +++ b/sysmodules/rosalina/kernel_extension/include/kernel.h @@ -0,0 +1,1190 @@ +/* +* 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 . +* +* 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" + +struct KMutex; +struct KProcessO3DS; +struct KProcessN3DS; +union KProcess; +struct HandleDescriptor; +struct KDebugThread; +struct KCodeSet; +struct KDebug; +struct KResourceLimit; +struct KPort; +struct KSession; +struct KLinkedListNode; +struct KThread; +struct Vtable__KAutoObject; +struct KClassToken; +struct Vtable__KBaseInterruptEvent; +struct KObjectMutex; +struct KThreadLinkedList; +struct KMutexLinkedList; +struct KPreemptionTimer; + +/* 12 */ +typedef struct ALIGN(4) KAutoObject +{ + struct Vtable__KAutoObject *vtable; + u32 refCount; +} KAutoObject; + +/* 10 */ +typedef struct KLinkedListNode +{ + struct KLinkedListNode *next; + struct KLinkedListNode *prev; + void *key; +} KLinkedListNode; + +/* 83 */ +typedef struct KLinkedListNodePair +{ + KLinkedListNode *first; + KLinkedListNode *last; +} KLinkedListNodePair; + +/* 11 */ +typedef struct KLinkedList +{ + u32 size; + KLinkedListNodePair nodes; +} KLinkedList; + +/* 13 */ +typedef struct KSynchronizationObject +{ + KAutoObject autoObject; + KLinkedList syncedThreads; +} KSynchronizationObject; + +/* 91 */ +typedef struct KMutexLinkedListNode +{ + struct KMutex *prev; + struct KMutex *next; +} KMutexLinkedListNode; + +/* 1 */ +typedef struct ALIGN(4) KMutex +{ + KSynchronizationObject syncObject; + KMutexLinkedListNode mutexListNode; + u32 nbThreadsUsingThis; + struct KThread *lockingThread; + u32 priority; + union KProcess *owner; +} KMutex; + +/* 92 */ +typedef struct KMutexLinkedList +{ + KMutex *first; + KMutex *last; +} KMutexLinkedList; + +/* 45 */ +typedef struct KClassToken +{ + const char *name; + u8 flags; +} KClassToken; + +/* 44 */ +typedef struct ALIGN(4) Vtable__KAutoObject +{ + void *field_0; + void *field_4; + void (*dtor)(KAutoObject *this); + void *substractResource; + KAutoObject *(*DecrementReferenceCount)(KAutoObject *this); + union KProcess *(*GetParentProcess)(KAutoObject *this); + KClassToken *(*GetClassToken)(KClassToken *out, KAutoObject *this); // >= 9.0 only + const char *(*GetClassName)(KAutoObject *this); // < 9.0 only + void *field_20; + void *field_24; +} Vtable__KAutoObject; + +/* 52 */ +typedef struct KBaseInterruptEvent +{ + struct Vtable__KBaseInterruptEvent *vtable; +} KBaseInterruptEvent; + +/* 55 */ +typedef struct ALIGN(4) Vtable__KBaseInterruptEvent +{ + struct KSchedulableInterruptEvent *(*handleInterruptEvent)(KBaseInterruptEvent *, u32); +} Vtable__KBaseInterruptEvent; + + +/* 67 */ +typedef struct KSynchronizationInterruptEvent +{ + KBaseInterruptEvent baseInterruptEvent; + struct KSynchronizationInterruptEvent *next; +} KSynchronizationInterruptEvent; + +/* 77 */ +// This one got added a vtable func on 11.3 +typedef struct KTimeableInterruptEvent +{ + KSynchronizationInterruptEvent syncInterruptEvent; + s64 timer; +} KTimeableInterruptEvent; + +/* 90 */ +typedef KSynchronizationInterruptEvent KSendableInterruptEvent; + +/* 68 */ +typedef KSynchronizationInterruptEvent KSchedulableInterruptEvent; + +/* 85 */ +typedef struct KThreadLinkedListNode +{ + struct KThread *prev; + struct KThread *next; +} KThreadLinkedListNode; + + +/* 93 */ +typedef struct ALIGN(4) KPreemptionTimer +{ + u32 nLimitedTicks; + u32 timer; + u32 previousWDTValue; + u32 wantedDuration; +} KPreemptionTimer; + +/* 15 */ +typedef struct PACKED ALIGN(4) KThread +{ + KSynchronizationObject syncObject; + KTimeableInterruptEvent timeableInterruptEvent; + KSendableInterruptEvent sendableInterruptEvent; + KSchedulableInterruptEvent schedulableInterruptEvent; + u8 schedulingMask; + u8 syncing_1; + bool shallTerminate; + u8 syncing_3; + struct KDebugThread *debugThread; + u32 basePriority; + KSynchronizationObject *objectThreadIsWaitingOn; + Result resultObjectWaited_2; + struct KObjectMutex *mutex; + void *arbitrationAddr; + KLinkedList objectsToWaitFor; + KMutexLinkedList *mutexList; + KLinkedList mutexesUsed; + s32 dynamicPriority; + u32 processor; + KPreemptionTimer *preemptionTimer; + u32 unknown_1; + bool isAlive; + bool isEnded; + u8 affinityMask, padding; + union KProcess *ownerProcess; + u32 threadId; + void *svcRegisterStorage; + void *endOfThreadContext; + s32 idealProcessor; + void *threadLocalStorage; + void *threadLocalStorageKernel; + void *unknown_5; + KThreadLinkedListNode threadListNode; + struct KThreadLinkedList *stolenThreadList; + s32 highestPriority; +} KThread; + +/* 79 */ +typedef struct KObjectMutex +{ + KThread *owner; + s16 tryAcquireCounter; + s16 contextSwitchCounter; +} KObjectMutex; + + + +/* 120 */ +typedef enum ProcessStatus +{ + PROCESS_AVAILABLE = 0x1, + PROCESS_CLOSING = 0x2, + PROCESS_EXITED = 0x3, +} ProcessStatus; + +/* 3 */ +typedef struct ALIGN(4) HandleDescriptor +{ + u32 info; + KAutoObject *pointer; +} HandleDescriptor; + +/* 22 */ +typedef struct KProcessHandleTable +{ + HandleDescriptor *handleTable; + s16 maxHandleCount; + s16 highestHandleCount; + HandleDescriptor *nextOpenHandleDescriptor; + s16 totalHandlesUsed; + s16 handlesInUseCount; + KObjectMutex mutex; + HandleDescriptor internalTable[40]; +} KProcessHandleTable; + +/* 4 */ +typedef struct ALIGN(4) KDebugThread +{ + KThread *linkedThread; + bool usedSvcBreak; + bool debugLocked; + bool shallBeDebugLocked; + bool scheduledInOrOut; + bool threadAttached; + bool syscallInOurOut; + u8 paddingA[2]; + u32 threadExitReason; + u32 creatorThreadId; + u32 FAR; +} KDebugThread; + +/* 84 */ +typedef struct KThreadLinkedList +{ + KThread *first; + KThread *last; +} KThreadLinkedList; + +typedef enum { + DBGEVENT_ATTACH_PROCESS = 0, ///< Process attached event. + DBGEVENT_ATTACH_THREAD = 1, ///< Thread attached event. + DBGEVENT_EXIT_THREAD = 2, ///< Thread exit event. + DBGEVENT_EXIT_PROCESS = 3, ///< Process exit event. + DBGEVENT_EXCEPTION = 4, ///< Exception event. + DBGEVENT_DLL_LOAD = 5, ///< DLL load event. + DBGEVENT_DLL_UNLOAD = 6, ///< DLL unload event. + DBGEVENT_SCHEDULE_IN = 7, ///< Schedule in event. + DBGEVENT_SCHEDULE_OUT = 8, ///< Schedule out event. + DBGEVENT_SYSCALL_IN = 9, ///< Syscall in event. + DBGEVENT_SYSCALL_OUT = 10, ///< Syscall out event. + DBGEVENT_OUTPUT_STRING = 11, ///< Output string event. + DBGEVENT_MAP = 12, ///< Map event. +} DebugEventType; + +/* 80 */ +typedef struct KRecursiveLock +{ + KThread *owner; + u32 lockCount; +} KRecursiveLock; + +typedef enum { + EXCEVENT_UNDEFINED_INSTRUCTION = 0, ///< Undefined instruction. + EXCEVENT_PREFETCH_ABORT = 1, ///< Prefetch abort. + EXCEVENT_DATA_ABORT = 2, ///< Data abort (other than the below kind). + EXCEVENT_UNALIGNED_DATA_ACCESS = 3, ///< Unaligned data access. + EXCEVENT_ATTACH_BREAK = 4, ///< Attached break. + EXCEVENT_STOP_POINT = 5, ///< Stop point reached. + EXCEVENT_USER_BREAK = 6, ///< User break occurred. + EXCEVENT_DEBUGGER_BREAK = 7, ///< Debugger break occurred. + EXCEVENT_UNDEFINED_SYSCALL = 8, ///< Undefined syscall. +} ExceptionEventType; + +/* 6 */ +typedef struct ALIGN(4) KDebug +{ + KSynchronizationObject syncObject; + KSendableInterruptEvent sendableInterruptEvent; + bool processDebugEventSignaled; + bool debugStringFlag; + bool isSignalingDebugEvent; + bool isPaused; + DebugEventType debugEventType; + u32 field_24; + KThread *lockingThread; + u32 debugEventFlags; + u32 stopPointType; + KLinkedList eventInfos; + KLinkedList infoForEventsToContinue; + union KProcess *owner; + KThread *debuggedThread; + KThread *threadUsingContinueDebugEvent; + u32 coreIDOfThreadUsingContinueDebugEvent; + KLinkedList debuggedThreads; + KLinkedList threadsOfProcess; + KRecursiveLock recursiveLock; + KThread *threadUsingSvcBreak; + bool noExceptionDebugEventOccured; + bool exceptionDebugEventSignaled; + bool shouldUnlockAll; + bool exceptionDebugEventOccuredWhilePaused; + bool userBreakEventOccuredWhilePaused; + bool processHasEnded; + bool processHasBeenTerminated; + bool pendingSvcBreakEvent; + u32 *regdump; + ExceptionEventType exceptionInfo; + u16 nbExceptions; + u16 svcID; + u16 nbPendingEvents; + u16 nbPendingExitProcessEvents; + const char *debugString; + u32 debugStringLength; +} KDebug; + +/* 7 */ +typedef struct KResourceLimit +{ + KAutoObject autoObject; + s32 maxResources[10]; + s32 currentResources[10]; + KObjectMutex objMutex; + KPreemptionTimer preemptionTimer; + u32 padding; +} KResourceLimit; + +/* 64 */ +typedef struct SectionInfo +{ + void *loadAddress; + u32 nbPages; +} SectionInfo; + +/* 23 */ +typedef struct KCodeSetMemDescriptor +{ + SectionInfo section; + struct KLinkedList blocks; +} KCodeSetMemDescriptor; + +/* 5 */ +typedef struct PACKED ALIGN(4) KCodeSet +{ + KAutoObject autoObject; + KCodeSetMemDescriptor textSection; + KCodeSetMemDescriptor rodataSection; + KCodeSetMemDescriptor dataSection; + u32 nbTextPages; + u32 nbRodataPages; + u32 nbRwPages; + char processName[8]; + u16 unknown_1; + u16 unknown_2; + u64 titleId; +} KCodeSet; + +/* 30 */ +typedef struct KServerPort +{ + KSynchronizationObject syncObject; + KLinkedList serverSessions; + struct KPort *parentKPort; +} KServerPort; + +/* 31 */ +typedef struct KClientPort +{ + KSynchronizationObject syncObject; + s16 connectionCount; + s16 maxConnectionCount; + struct KPort *parentKPort; +} KClientPort; + +/* 8 */ +typedef struct KPort +{ + KAutoObject autoObject; + KServerPort serverPort; + KClientPort clientPort; +} KPort; + +/* 33 */ +typedef struct KServerSession +{ + KSynchronizationObject syncObject; + struct KSession *parentSession; + KThread *lastStolenThread; + KThread *firstStolenThread; + KThread *originatingThread; +} KServerSession; + +/* 32 */ +typedef struct KClientSession +{ + KSynchronizationObject syncObject; + struct KSession *parentSession; + u32 status; + KClientPort *clientPort; +} KClientSession; + +/* 9 */ +typedef struct KSession +{ + KAutoObject autoObject; + KServerSession serverSession; + KClientSession clientSession; +} KSession; + +/* 82 */ +typedef struct KUserBindableInterruptEvent +{ + KSchedulableInterruptEvent schedulableInterruptEvent; + s32 interruptID; +} KUserBindableInterruptEvent; + +/* 14 */ +typedef struct ALIGN(4) KEvent +{ + KSynchronizationObject syncObject; + KUserBindableInterruptEvent userBindableInterruptEvent; + bool isSignaled; + bool manualClear; + u8 resetType; + u8 unused; + union KProcess *owner; +} KEvent; + +/* 16 */ +typedef enum MemOp +{ + MEMOP_FREE = 0x1, + MEMOP_RESERVE = 0x2, + MEMOP_COMMIT = 0x3, + MEMOP_MAP = 0x4, + MEMOP_UNMAP = 0x5, + MEMOP_PROTECT = 0x6, + MEMOP_REGION_APP = 0x100, + MEMOP_REGION_SYSTEM = 0x200, + MEMOP_REGION_BASE = 0x300, + MEMOP_LINEAR = 0x10000, +} MemOp; + +/* 17 */ +typedef enum MemPerm +{ + MEMPERM_NONE = 0x0, + MEMPERM_R = 0x1, + MEMPERM_W = 0x2, + MEMPERM_RW = 0x3, + MEMPERM_X = 0x4, + MEMPERM_RX = 0x5, + MEMPERM_WX = 0x6, + MEMPERM_RWX = 0x7, + MEMPERM_DONTCARE = 0x10000000, +} MemPerm; + +/* 18 */ +typedef struct KObjectLink +{ + void *nextAvailable; + void *first; + u32 kheapAllocSize; + u32 size; +} KObjectLink; + +/* 19 */ +typedef struct KObjectList +{ + KLinkedList list; + KObjectMutex mutex; + s16 totalObjectsCreated; + s16 padding2; + KObjectLink objectInfo; +} KObjectList; + +/* 21 */ +typedef struct KSemaphore +{ + KSynchronizationObject syncObject; + KUserBindableInterruptEvent userBindableInterruptEvent; + u32 count; + u32 maxCount; + union KProcess *owner; +} KSemaphore; + +/* 24 */ +typedef struct KBlockInfo +{ + void *memSectionStartKVaddr; + u32 pageCount; +} KBlockInfo; + +/* 25 */ +typedef struct KMemoryBlock +{ + void *baseAddr; + u32 sizeInPages; + u32 permissions; + u32 state; + u32 zero; +} KMemoryBlock; + +/* 28 */ +typedef struct ALIGN(4) KScheduler +{ + KSchedulableInterruptEvent interruptEvent; + u32 threadSwitchAttempts; + bool contextSwitchNeeded; + bool contextSwitchStartedDuringInterrupt; + bool triggerCrossCoreInterrupt; + bool postInterruptReschedulingNeeded; + s16 coreNumber; + s16 managedThreadsCount; + u32 highPriorityThreadsBitfield; + u32 lowPriorityThreadsBitfield; + KThread *schedulerThread; + KThreadLinkedList listOfHandledThreads; + KThreadLinkedList threadsByPriority[64]; +} KScheduler; + +/* 46 */ +typedef struct PACKED CodeSetInfo +{ + char name[8]; + u16 unknown_1; + u16 unknown_2; + u32 unknown_3; + void *textAddr; + u32 textSize; + void *rodataAddr; + u32 rodataSize; + void *rwAddr; + u32 rwSize; + u32 totalTextPages; + u32 totalRodataPages; + u32 totalRwPages; + u32 unknown_4; + u64 programId; +} CodeSetInfo; + +/* 53 */ +typedef struct ALIGN(4) InterruptData +{ + KBaseInterruptEvent *interruptEvent; + bool disableUponReceipt; + bool isDisabled; + u8 priority; + u8 padding; +} InterruptData; + +/* 59 */ +typedef struct KFIQInterruptEvent +{ + KSchedulableInterruptEvent schedulableInterruptEvent; + KEvent *event; + bool isLevelHighActive; + bool otherFlag; +} KFIQInterruptEvent; + +/* 61 */ +typedef enum TLBOperation +{ + NO_TLB_OPERATION = 0x0, + FLUSH_TLB_ENTRIES_ON_ASID_MATCH = 0x1, + FLUSH_ENTIRE_TLB = 0x2, + FLUSH_TLB_ENTRIES_ON_MVA_MATCH = 0x3, + TLB_RESET_CONTEXT = 0x4, +} TLBOperation; + +/* 63 */ +typedef struct TLBOperationTarget +{ + union KProcessHwInfo *contextInfo; + void *VA; +} TLBOperationTarget; + +/* 62 */ +typedef struct KTLBOperationsInterruptEvent +{ + KBaseInterruptEvent interruptEvent; + TLBOperationTarget target; + TLBOperation operation; +} KTLBOperationsInterruptEvent; + +/* 65 */ +typedef struct KObjectName +{ + char name[12]; + KClientPort *parentClientPort; +} KObjectName; + +/* 74 */ +typedef enum MemState +{ + MEMSTATE_FREE = 0x0, + MEMSTATE_RESERVED = 0x1, + MEMSTATE_IO = 0x2, + MEMSTATE_STATIC = 0x3, + MEMSTATE_CODE = 0x4, + MEMSTATE_PRIVATE = 0x5, + MEMSTATE_SHARED = 0x6, + MEMSTATE_CONTINUOUS = 0x7, + MEMSTATE_ALIASED = 0x8, + MEMSTATE_ALIAS = 0x9, + MEMSTATE_ALIAS_CODE = 0xA, + MEMSTATE_LOCKED = 0xB, +} MemState; + +/* 75 */ +typedef struct MemoryInfo +{ + void *baseVA; + u32 size; + u32 permissions; + MemState state; + u32 padding; +} MemoryInfo; + +/* 76 */ +typedef struct PageInfo +{ + u32 flags; +} PageInfo; + +/* 78 */ +typedef struct KTimerAndWDTManager +{ + KSynchronizationInterruptEvent syncInterruptEvent; + u32 counter; + u32 previousCounter; + KTimeableInterruptEvent innerInterruptEvent; + KRecursiveLock recursiveLock; +} KTimerAndWDTManager; + +typedef enum ResetType +{ + RESET_ONESHOT = 0x0, + RESET_STICKY = 0x1, + RESET_PULSE = 0x2, +} ResetType; + +/* 81 */ +typedef struct PACKED ALIGN(4) KTimer +{ + KSynchronizationObject syncObject; + KTimeableInterruptEvent timeableInterruptEvent; + bool signaled; + ResetType resetType; + u16 padding; + s64 interval; + s64 currentValue; + union KProcess *owner; +} KTimer; + +/* 86 */ +typedef struct KSchedulableInterruptEventLinkedList +{ + KSchedulableInterruptEvent *first; + KSchedulableInterruptEvent *last; + u32 unused; + KThread *handlingKernelThread; +} KSchedulableInterruptEventLinkedList; + +/* 87 */ +typedef KSchedulableInterruptEvent KThreadTerminationInterruptEvent; + +/* 88 */ +typedef KSchedulableInterruptEvent KThreadExitInterruptEvent; + +/* 89 */ +typedef struct ALIGN(4) KInterruptEventMailbox +{ + u32 mailboxID; + KSendableInterruptEvent *first; + KSendableInterruptEvent *last; + bool isBusy; + KThread *handlingThread; +} KInterruptEventMailbox; + +/* 94 */ +typedef enum LimitableResource +{ + LIMITABLE_RESOURCE_MAX_PRIORITY = 0x0, + LIMITABLE_RESOURCE_MAX_COMMIT = 0x1, + LIMITABLE_RESOURCE_MAX_THREAD = 0x2, + LIMITABLE_RESOURCE_MAX_EVENT = 0x3, + LIMITABLE_RESOURCE_MAX_MUTEX = 0x4, + LIMITABLE_RESOURCE_MAX_SEMAPHORE = 0x5, + LIMITABLE_RESOURCE_MAX_TIMER = 0x6, + LIMITABLE_RESOURCE_MAX_SHAREDMEMORY = 0x7, + LIMITABLE_RESOURCE_MAX_ADDRESSARBITER = 0x8, + LIMITABLE_RESOURCE_MAX_CPUTIME = 0x9, + LIMITABLE_RESOURCE_END = 0xA, + LIMITABLE_RESOURCE_MAX_BIT = 0x80000000, +} LimitableResource; + +/* 99 */ +typedef struct ALIGN(4) CpuRegisters +{ + u32 r[13]; + u32 sp; + u32 lr; + u32 pc; + u32 cpsr; +} CpuRegisters; + +/* 100 */ +typedef struct FpuRegisters +{ + union + { + struct PACKED { double d[16]; }; + float s[32]; + }; + u32 fpscr; + u32 fpexc; +} FpuRegisters; + +/* 98 */ +typedef struct ThreadContext +{ + CpuRegisters cpuRegisters; + FpuRegisters fpuRegisters; +} ThreadContext; + +/* 101 */ +typedef struct KAttachProcessDebugEventInfo +{ + union KProcess *process; +} KAttachProcessDebugEventInfo; + +/* 102 */ +typedef struct KAttachThreadDebugEventInfo +{ + u32 creatorThreadId; + void *threadLocalStorage; + u32 *processEntrypoint; +} KAttachThreadDebugEventInfo; + + +/// Reasons for an exit thread event. +typedef enum { + EXITTHREAD_EVENT_EXIT = 0, ///< Thread exited. + EXITTHREAD_EVENT_TERMINATE = 1, ///< Thread terminated. + EXITTHREAD_EVENT_EXIT_PROCESS = 2, ///< Process exited either normally or due to an uncaught exception. + EXITTHREAD_EVENT_TERMINATE_PROCESS = 3, ///< Process has been terminated by @ref svcTerminateProcess. +} ExitThreadEventReason; + +/// Reasons for an exit process event. +typedef enum { + EXITPROCESS_EVENT_EXIT = 0, ///< Process exited either normally or due to an uncaught exception. + EXITPROCESS_EVENT_TERMINATE = 1, ///< Process has been terminated by @ref svcTerminateProcess. + EXITPROCESS_EVENT_DEBUG_TERMINATE = 2, ///< Process has been terminated by @ref svcTerminateDebugProcess. +} ExitProcessEventReason; + +/* 103 */ +typedef struct KExitThreadDebugEventInfo +{ + ExitThreadEventReason reason; +} KExitThreadDebugEventInfo; + +/* 104 */ +typedef struct KExitProcessDebugEventInfo +{ + ExitProcessEventReason reason; +} KExitProcessDebugEventInfo; + +/// Stop point types +typedef enum StopPointType +{ + STOPPOINT_SVC_FF = 0, ///< See @ref SVC_STOP_POINT. + STOPPOINT_BREAKPOINT = 1, ///< Breakpoint. + STOPPOINT_WATCHPOINT = 2, ///< Watchpoint. +} StopPointType; + +/* 105 */ +typedef struct KFaultExceptionDebugEventInfo +{ + u32 faultInfo; + StopPointType stopPointType; +} KFaultExceptionDebugEventInfo; + +/// Reasons for a user break. +typedef enum UserBreakType +{ + USERBREAK_PANIC = 0, ///< Panic. + USERBREAK_ASSERT = 1, ///< Assertion failed. + USERBREAK_USER = 2, ///< User related. + USERBREAK_LOAD_RO = 3, ///< Load RO. + USERBREAK_UNLOAD_RO = 4, ///< Unload RO. +} UserBreakType; + +/* 106 */ +typedef struct KUserBreakExceptionDebugEventInfo +{ + UserBreakType reason; + u32 croInfo, croInfoSize; +} KUserBreakExceptionDebugEventInfo; + +/* 107 */ +typedef struct KDebuggerBreakDebugEventInfo +{ + s32 threadIds[4]; +} KDebuggerBreakDebugEventInfo; + +/* 109 */ +typedef struct KExceptionDebugEventInfo +{ + ExceptionEventType type; + void *address; + u32 category; + union + { + KFaultExceptionDebugEventInfo fault; + KUserBreakExceptionDebugEventInfo userBreak; + KDebuggerBreakDebugEventInfo debuggerBreak; + }; +} KExceptionDebugEventInfo; + +/* 110 */ +typedef struct KScheduleDebugEventInfo +{ + u64 clockTick; + u32 cpuId; + u32 unk[5]; + u32 unkEventInfo; + u32 padding; +} KScheduleDebugEventInfo; + +/* 111 */ +typedef struct KSyscallDebugEventInfo +{ + u64 clockTick; + u32 svcId; +} KSyscallDebugEventInfo; + +/* 112 */ +typedef struct KOutputStringDebugEventInfo +{ + const char *str; + u32 size; +} KOutputStringDebugEventInfo; + +/* 113 */ +typedef struct KMapDebugEventInfo +{ + void *address; + u32 size; + MemPerm permissions; + MemState state; +} KMapDebugEventInfo; + +/* 115 */ +typedef struct KEventInfo +{ + DebugEventType type; + u32 threadId; + u32 flags; + bool processIsBeingAttached; + bool needsToBeContinued; + bool other; + bool isProcessed; + union + { + KAttachProcessDebugEventInfo attachProcess; + KAttachThreadDebugEventInfo attachThread; + KExitThreadDebugEventInfo exitThread; + KExitProcessDebugEventInfo exitProcess; + KExceptionDebugEventInfo exception; + KScheduleDebugEventInfo schedule; + KSyscallDebugEventInfo syscall; + KOutputStringDebugEventInfo outputString; + KMapDebugEventInfo map; + }; +} KEventInfo; + +typedef struct ALIGN(0x1000) KCoreObjectContext +{ + KThread *volatile currentThread; + union KProcess *volatile currentProcess; + KScheduler *volatile currentScheduler; + KSchedulableInterruptEventLinkedList *volatile currentSchedulableInterruptEventLinkedList; + KThread *volatile lastKThreadEncounteringExceptionPtr; + u8 padding[4]; + KThread schedulerThread; + KScheduler schedulerInstance; + KSchedulableInterruptEventLinkedList schedulableInterruptEventLinkedListInstance; + u8 padding2[2164]; + u32 unkStack[291]; +} KCoreObjectContext; + +typedef struct KCoreContext +{ + u32 gap0[1024]; + u32 L1Table_exceptionStack[4096]; + u32 gap1[1024]; + u32 schedulerThreadContext[1024]; + u32 gap2[1024]; + KCoreObjectContext objectContext; +} KCoreContext; + +static KCoreContext * const currentCoreContext = (KCoreContext *)0xFFFF1000; + +#define DEFINE_CONSOLE_SPECIFIC_STRUCTS(console, nbCores) +/* 60 */ +typedef struct ALIGN(4) KProcessHwInfoN3DS +{ + KObjectMutex mutex; + u32 processTLBEntriesNeedToBeFlushedOnCore[4]; + KLinkedList ownedKMemoryBlocks; + u32 unknown_3; + u32 field_28; + u32 translationTableBase; + u8 contextId; + bool globalTLBFlushRequired; + bool isCurrentlyLoadedApp; + u32 unknown_5; + void *endOfUserlandVmem; + void *linearVAUserlandBase; + u32 unknown_6; + u32 mmuTableSize; + u32 *mmuTableVA; +} KProcessHwInfoN3DS; + +typedef struct ALIGN(4) KProcessHwInfoO3DS8x +{ + KObjectMutex mutex; + u32 processTLBEntriesNeedToBeFlushedOnCore[2]; + KLinkedList ownedKMemoryBlocks; + u32 unknown_3; + u32 field_28; + u32 translationTableBase; + u8 contextId; + bool globalTLBFlushRequired; + bool isCurrentlyLoadedApp; + u32 unknown_5; + void *endOfUserlandVmem; + void *linearVAUserlandBase; + u32 unknown_6; + u32 mmuTableSize; + u32 *mmuTableVA; +} KProcessHwInfoO3DS8x; + +typedef struct ALIGN(4) KProcessHwInfoO3DSPre8x +{ + KObjectMutex mutex; + u32 processTLBEntriesNeedToBeFlushedOnCore[2]; + KLinkedList ownedKMemoryBlocks; + u32 unknown_3; + u32 field_28; + u32 translationTableBase; + u8 contextId; + bool globalTLBFlushRequired; + bool isCurrentlyLoadedApp; + u32 unknown_5; + void *endOfUserlandVmem; + u32 mmuTableSize; + u32 *mmuTableVA; +} KProcessHwInfoO3DSPre8x; + +#define INSTANCIATE_KPROCESS(sys) \ +typedef struct KProcess##sys\ +{\ + KSynchronizationObject syncObject;\ + KSendableInterruptEvent sendableInterruptEvent;\ + KProcessHwInfo##sys hwInfo;\ + u32 totalThreadContextSize;\ + KLinkedList threadLocalPages;\ + u32 unknown_7;\ + s32 idealProcessor;\ + KDebug *debug;\ + KResourceLimit *resourceLimits;\ + ProcessStatus status;\ + u8 affinityMask;\ + u16 padding;\ + s16 threadCount;\ + s16 maxThreadCount;\ + u32 svcAccessControlMask[4];\ + u32 interruptFlags[4];\ + u32 kernelFlags;\ + u16 handleTableSize;\ + u16 kernelReleaseVersion;\ + KCodeSet *codeSet;\ + u32 processId;\ + s64 creationTime;\ + KThread *mainThread;\ + u32 interruptEnabledFlags[4];\ + KProcessHandleTable handleTable;\ + u8 gap234[52];\ + u64 unused;\ +} KProcess##sys; + +INSTANCIATE_KPROCESS(N3DS); +INSTANCIATE_KPROCESS(O3DS8x); +INSTANCIATE_KPROCESS(O3DSPre8x); + +typedef union KProcessHwInfo +{ + KProcessHwInfoN3DS N3DS; + KProcessHwInfoO3DS8x O3DS8x; + KProcessHwInfoO3DSPre8x O3DSPre8x; +} KProcessHwInfo; + +typedef union KProcess +{ + KProcessN3DS N3DS; + KProcessO3DS8x O3DS8x; + KProcessO3DSPre8x O3DSPre8x; +} KProcess; + +/* 54 */ +typedef struct InterruptManagerN3DS +{ + InterruptData privateInterrupts[4][32]; + InterruptData publicEvents[96]; + KObjectMutex mutex; +} InterruptManagerN3DS; + +typedef struct InterruptManagerO3DS +{ + InterruptData privateInterrupts[2][32]; + InterruptData publicEvents[96]; + KObjectMutex mutex; +} InterruptManagerO3DS; + +typedef union InterruptManager +{ + InterruptManagerN3DS N3DS; + InterruptManagerO3DS O3DS; +} InterruptManager; + +typedef struct AddressRange +{ + void *begin; + void *end; +} AddressRange; + +typedef struct KAsyncCacheMaintenanceInterruptEvent +{ + KSchedulableInterruptEvent schedulableInterruptEvent; + const KThread *handlingThread; +} KAsyncCacheMaintenanceInterruptEvent; + +typedef struct KCacheMaintenanceInterruptEventN3DS +{ + KBaseInterruptEvent baseInterruptEvent; + u8 cacheMaintenanceOperation; + bool async; + s8 remaining; + KThread *operatingThread; + AddressRange addrRange; + KThreadLinkedListNode *threadListNode; + KThreadLinkedList *threadList; + KAsyncCacheMaintenanceInterruptEvent asyncInterruptEventsPerCore[4]; +} KCacheMaintenanceInterruptEventN3DS; + +typedef struct KCacheMaintenanceInterruptEventO3DS +{ + KBaseInterruptEvent baseInterruptEvent; + u8 cacheMaintenanceOperation; + bool async; + s8 remaining; + KThread *operatingThread; + AddressRange addrRange; + KThreadLinkedListNode *threadListNode; + KThreadLinkedList *threadList; + KAsyncCacheMaintenanceInterruptEvent asyncInterruptEventsPerCore[2]; +} KCacheMaintenanceInterruptEventO3DS; + +typedef union KCacheMaintenanceInterruptEvent +{ + KCacheMaintenanceInterruptEventN3DS N3DS; + KCacheMaintenanceInterruptEventO3DS O3DS; +} KCacheMaintenanceInterruptEvent; + +extern bool isN3DS; +extern void *officialSVCs[0x7E]; + +extern u32 kernelVersion; +#define KPROCESS_OFFSETOF(field) (isN3DS ? offsetof(KProcessN3DS, field) :\ +((kernelVersion >= SYSTEM_VERSION(2, 44, 6)) ? offsetof(KProcessO3DS8x, field) :\ +offsetof(KProcessO3DSPre8x, field))) + +#define KPROCESS_GET_PTR(obj, field) (isN3DS ? &(obj)->N3DS.field :\ +((kernelVersion >= SYSTEM_VERSION(2, 44, 6)) ? &(obj)->O3DS8x.field :\ +&(obj)->O3DSPre8x.field )) + +#define KPROCESS_GET_PTR_TYPE(type, obj, field) (isN3DS ? (type *)(&(obj)->N3DS.field) :\ +((kernelVersion >= SYSTEM_VERSION(2, 44, 6)) ? (type *)(&(obj)->O3DS8x.field) :\ +(type *)(&(obj)->O3DSPre8x.field) )) + +#define KPROCESS_GET_RVALUE(obj, field) *(KPROCESS_GET_PTR(obj, field)) + +#define KPROCESS_GET_RVALUE_TYPE(type, obj, field) *(KPROCESS_GET_PTR(type, obj, field)) + +static inline u32 idOfProcess(KProcess *process) +{ + return KPROCESS_GET_RVALUE(process, processId); +} + +static inline KProcessHwInfo *hwInfoOfProcess(KProcess *process) +{ + return KPROCESS_GET_PTR_TYPE(KProcessHwInfo, process, hwInfo); +} + +static inline KCodeSet *codeSetOfProcess(KProcess *process) +{ + return KPROCESS_GET_RVALUE(process, codeSet); +} + +static inline KProcessHandleTable *handleTableOfProcess(KProcess *process) +{ + return KPROCESS_GET_PTR(process, handleTable); +} + +static inline KDebug *debugOfProcess(KProcess *process) +{ + return KPROCESS_GET_RVALUE(process, debug); +} + +extern Result (*KProcessHandleTable__CreateHandle)(KProcessHandleTable *this, Handle *out, KAutoObject *obj, u8 token); + +static inline Result createHandleForProcess(Handle *out, KProcess *process, KAutoObject *obj) +{ + u8 token; + if(kernelVersion >= SYSTEM_VERSION(2, 46, 0)) + { + KClassToken tok; + obj->vtable->GetClassToken(&tok, obj); + token = tok.flags; + } + else + token = (u8)(u32)(obj->vtable->GetClassName(obj)); + + KProcessHandleTable *handleTable = handleTableOfProcess(process); + return KProcessHandleTable__CreateHandle(handleTable, out, obj, token); +} + +static inline Result createHandleForThisProcess(Handle *out, KAutoObject *obj) +{ + return createHandleForProcess(out, currentCoreContext->objectContext.currentProcess, obj); +} diff --git a/sysmodules/rosalina/kernel_extension/include/memory.h b/sysmodules/rosalina/kernel_extension/include/memory.h new file mode 100644 index 000000000..40b3cce1a --- /dev/null +++ b/sysmodules/rosalina/kernel_extension/include/memory.h @@ -0,0 +1,42 @@ +/* +* 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 . +* +* 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" + +void *memcpy(void *dest, const void *src, u32 size) USED; +int memcmp(const void *buf1, const void *buf2, u32 size) USED; +void *memset(void *dest, u32 value, u32 size) USED; // thanks binutils for the nice bug involving memset. +void *memset32(void *dest, u32 value, u32 size); +u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSize); +char *strcpy(char *dest, const char *src); +char *strncpy(char *dest, const char *src, u32 size); +s32 strnlen(const char *string, s32 maxlen); +s32 strlen(const char *string); +s32 strcmp(const char *str1, const char *str2); +s32 strncmp(const char *str1, const char *str2, u32 size); +void hexItoa(u64 number, char *out, u32 digits, bool uppercase); diff --git a/sysmodules/rosalina/kernel_extension/include/svc.h b/sysmodules/rosalina/kernel_extension/include/svc.h new file mode 100644 index 000000000..b6c9c73a9 --- /dev/null +++ b/sysmodules/rosalina/kernel_extension/include/svc.h @@ -0,0 +1,37 @@ +/* +* 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 . +* +* 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" +#include "globals.h" +#include "kernel.h" +#include "utils.h" + +extern void *officialSVCs[0x7E]; + +void svcDefaultHandler(u8 svcId); +void *svcHook(u8 *pageEnd); diff --git a/sysmodules/rosalina/kernel_extension/include/svc/Backdoor.h b/sysmodules/rosalina/kernel_extension/include/svc/Backdoor.h new file mode 100644 index 000000000..f0507f486 --- /dev/null +++ b/sysmodules/rosalina/kernel_extension/include/svc/Backdoor.h @@ -0,0 +1,33 @@ +/* +* 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 . +* +* 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 "utils.h" +#include "kernel.h" +#include "svc.h" + +void Backdoor(void *function); diff --git a/sysmodules/rosalina/kernel_extension/include/svc/Break.h b/sysmodules/rosalina/kernel_extension/include/svc/Break.h new file mode 100644 index 000000000..4528e2fa3 --- /dev/null +++ b/sysmodules/rosalina/kernel_extension/include/svc/Break.h @@ -0,0 +1,32 @@ +/* +* 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 . +* +* 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 "utils.h" +#include "kernel.h" + +void __attribute__((noreturn)) Break(UserBreakType type, ...); diff --git a/sysmodules/rosalina/kernel_extension/include/svc/ConnectToPort.h b/sysmodules/rosalina/kernel_extension/include/svc/ConnectToPort.h new file mode 100644 index 000000000..2e66076bb --- /dev/null +++ b/sysmodules/rosalina/kernel_extension/include/svc/ConnectToPort.h @@ -0,0 +1,34 @@ +/* +* 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 . +* +* 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 "utils.h" +#include "kernel.h" +#include "svc.h" + +Result ConnectToPortHookWrapper(u32 dummy, const char *name); +Result ConnectToPortHook(Handle *out, const char *name); diff --git a/sysmodules/rosalina/kernel_extension/include/svc/ControlMemory.h b/sysmodules/rosalina/kernel_extension/include/svc/ControlMemory.h new file mode 100644 index 000000000..d98d6fbb7 --- /dev/null +++ b/sysmodules/rosalina/kernel_extension/include/svc/ControlMemory.h @@ -0,0 +1,35 @@ +/* +* 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 . +* +* 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 "utils.h" +#include "kernel.h" +#include "svc.h" + +Result ControlMemoryHookWrapper(u32 *addrOut, u32 addr0, u32 addr1, u32 size, MemOp op, MemPerm perm); +Result ControlMemoryHook(u32 *addrOut, u32 addr0, u32 addr1, u32 size, MemOp op, MemPerm perm); +Result ControlMemoryEx(u32 *addrOut, u32 addr0, u32 addr1, u32 size, MemOp op, MemPerm perm, bool isLoader); diff --git a/sysmodules/rosalina/kernel_extension/include/svc/ControlService.h b/sysmodules/rosalina/kernel_extension/include/svc/ControlService.h new file mode 100644 index 000000000..088c831cb --- /dev/null +++ b/sysmodules/rosalina/kernel_extension/include/svc/ControlService.h @@ -0,0 +1,40 @@ +/* +* 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 . +* +* 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 "utils.h" +#include "kernel.h" +#include "svc.h" + +/// Operations for svcControlService +typedef enum ServiceOp +{ + SERVICEOP_STEAL_CLIENT_SESSION = 0, ///< Steal a client session given a service or global port name + SERVICEOP_GET_NAME, ///< Get the name of a service or global port given a client or session handle +} ServiceOp; + +Result ControlService(ServiceOp op, u32 varg1, u32 varg2); diff --git a/sysmodules/rosalina/kernel_extension/include/svc/CopyHandle.h b/sysmodules/rosalina/kernel_extension/include/svc/CopyHandle.h new file mode 100644 index 000000000..24265e648 --- /dev/null +++ b/sysmodules/rosalina/kernel_extension/include/svc/CopyHandle.h @@ -0,0 +1,34 @@ +/* +* 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 . +* +* 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 "utils.h" +#include "kernel.h" +#include "svc.h" + +Result CopyHandleWrapper(Handle *outHandle, Handle outProcessHandle, Handle inHandle, Handle inProcessHandle); +Result CopyHandle(Handle *outHandle, Handle outProcessHandle, Handle inHandle, Handle inProcessHandle); diff --git a/sysmodules/rosalina/kernel_extension/include/svc/GetCFWInfo.h b/sysmodules/rosalina/kernel_extension/include/svc/GetCFWInfo.h new file mode 100644 index 000000000..44f08ec1a --- /dev/null +++ b/sysmodules/rosalina/kernel_extension/include/svc/GetCFWInfo.h @@ -0,0 +1,35 @@ +/* +* 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 . +* +* 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 "utils.h" +#include "kernel.h" +#include "svc.h" +#include "globals.h" + +// DEPRECATED +Result GetCFWInfo(CfwInfo *out); diff --git a/sysmodules/rosalina/kernel_extension/include/svc/GetProcessInfo.h b/sysmodules/rosalina/kernel_extension/include/svc/GetProcessInfo.h new file mode 100644 index 000000000..db71723d2 --- /dev/null +++ b/sysmodules/rosalina/kernel_extension/include/svc/GetProcessInfo.h @@ -0,0 +1,34 @@ +/* +* 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 . +* +* 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 "utils.h" +#include "kernel.h" +#include "svc.h" + +Result GetProcessInfoHookWrapper(u32 dummy, Handle processHandle, u32 type); +Result GetProcessInfoHook(s64 *out, Handle processHandle, u32 type); diff --git a/sysmodules/rosalina/kernel_extension/include/svc/GetSystemInfo.h b/sysmodules/rosalina/kernel_extension/include/svc/GetSystemInfo.h new file mode 100644 index 000000000..ad3ea18c3 --- /dev/null +++ b/sysmodules/rosalina/kernel_extension/include/svc/GetSystemInfo.h @@ -0,0 +1,34 @@ +/* +* 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 . +* +* 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 "utils.h" +#include "kernel.h" +#include "svc.h" + +Result GetSystemInfoHookWrapper(u32 dummy, s32 type, s32 param); +Result GetSystemInfoHook(s64 *out, s32 type, s32 param); diff --git a/sysmodules/rosalina/kernel_extension/include/svc/GetThreadInfo.h b/sysmodules/rosalina/kernel_extension/include/svc/GetThreadInfo.h new file mode 100644 index 000000000..2c8b8f978 --- /dev/null +++ b/sysmodules/rosalina/kernel_extension/include/svc/GetThreadInfo.h @@ -0,0 +1,34 @@ +/* +* 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 . +* +* 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 "utils.h" +#include "kernel.h" +#include "svc.h" + +Result GetThreadInfoHookWrapper(u32 dummy, Handle threadHandle, u32 type); +Result GetThreadInfoHook(s64 *out, Handle threadHandle, u32 type); diff --git a/sysmodules/rosalina/kernel_extension/include/svc/KernelSetState.h b/sysmodules/rosalina/kernel_extension/include/svc/KernelSetState.h new file mode 100644 index 000000000..6b6e22733 --- /dev/null +++ b/sysmodules/rosalina/kernel_extension/include/svc/KernelSetState.h @@ -0,0 +1,35 @@ +/* +* 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 . +* +* 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 "utils.h" +#include "kernel.h" +#include "svc.h" + +extern u32 rosalinaState; +bool shouldSignalSyscallDebugEvent(KProcess *process, u8 svcId); +Result KernelSetStateHook(u32 type, u32 varg1, u32 varg2, u32 varg3); diff --git a/sysmodules/rosalina/kernel_extension/include/svc/MapProcessMemoryEx.h b/sysmodules/rosalina/kernel_extension/include/svc/MapProcessMemoryEx.h new file mode 100644 index 000000000..189d7db36 --- /dev/null +++ b/sysmodules/rosalina/kernel_extension/include/svc/MapProcessMemoryEx.h @@ -0,0 +1,33 @@ +/* +* 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 . +* +* 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 "utils.h" +#include "kernel.h" +#include "svc.h" + +Result MapProcessMemoryEx(Handle processHandle, void *dst, void *src, u32 size); diff --git a/sysmodules/rosalina/kernel_extension/include/svc/SendSyncRequest.h b/sysmodules/rosalina/kernel_extension/include/svc/SendSyncRequest.h new file mode 100644 index 000000000..a0e1a3dba --- /dev/null +++ b/sysmodules/rosalina/kernel_extension/include/svc/SendSyncRequest.h @@ -0,0 +1,33 @@ +/* +* 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 . +* +* 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 "utils.h" +#include "kernel.h" +#include "svc.h" + +Result SendSyncRequestHook(Handle handle); diff --git a/sysmodules/rosalina/kernel_extension/include/svc/SetGpuProt.h b/sysmodules/rosalina/kernel_extension/include/svc/SetGpuProt.h new file mode 100644 index 000000000..0e8c223d6 --- /dev/null +++ b/sysmodules/rosalina/kernel_extension/include/svc/SetGpuProt.h @@ -0,0 +1,33 @@ +/* +* 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 . +* +* 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 "utils.h" +#include "kernel.h" +#include "svc.h" + +Result SetGpuProt(bool prot); diff --git a/sysmodules/rosalina/kernel_extension/include/svc/SetWifiEnabled.h b/sysmodules/rosalina/kernel_extension/include/svc/SetWifiEnabled.h new file mode 100644 index 000000000..c7d31e165 --- /dev/null +++ b/sysmodules/rosalina/kernel_extension/include/svc/SetWifiEnabled.h @@ -0,0 +1,33 @@ +/* +* 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 . +* +* 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 "utils.h" +#include "kernel.h" +#include "svc.h" + +void SetWifiEnabled(bool enable); diff --git a/sysmodules/rosalina/kernel_extension/include/svc/TranslateHandle.h b/sysmodules/rosalina/kernel_extension/include/svc/TranslateHandle.h new file mode 100644 index 000000000..8ab134266 --- /dev/null +++ b/sysmodules/rosalina/kernel_extension/include/svc/TranslateHandle.h @@ -0,0 +1,34 @@ +/* +* 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 . +* +* 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 "utils.h" +#include "kernel.h" +#include "svc.h" + +Result TranslateHandleWrapper(u32 *outKAddr, char *outClassName, Handle handle); +Result TranslateHandle(u32 *outKAddr, char *outClassName, Handle handle); diff --git a/sysmodules/rosalina/kernel_extension/include/svc/UnmapProcessMemoryEx.h b/sysmodules/rosalina/kernel_extension/include/svc/UnmapProcessMemoryEx.h new file mode 100644 index 000000000..ef7f151b0 --- /dev/null +++ b/sysmodules/rosalina/kernel_extension/include/svc/UnmapProcessMemoryEx.h @@ -0,0 +1,33 @@ +/* +* 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 . +* +* 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 "utils.h" +#include "kernel.h" +#include "svc.h" + +Result UnmapProcessMemoryEx(Handle processHandle, void *dst, u32 size); diff --git a/exceptions/arm11/source/types.h b/sysmodules/rosalina/kernel_extension/include/svcHandler.h similarity index 56% rename from exceptions/arm11/source/types.h rename to sysmodules/rosalina/kernel_extension/include/svcHandler.h index 2b89edbd4..e15dfb403 100644 --- a/exceptions/arm11/source/types.h +++ b/sysmodules/rosalina/kernel_extension/include/svcHandler.h @@ -1,6 +1,6 @@ /* * This file is part of Luma3DS -* Copyright (C) 2016 Aurora Wright, TuxSH +* 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 @@ -15,23 +15,15 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * -* Additional Terms 7.b of GPLv3 applies 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. +* 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 -#include -#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 +void svcHandler(void); diff --git a/sysmodules/rosalina/kernel_extension/include/synchronization.h b/sysmodules/rosalina/kernel_extension/include/synchronization.h new file mode 100644 index 000000000..96e11f3e5 --- /dev/null +++ b/sysmodules/rosalina/kernel_extension/include/synchronization.h @@ -0,0 +1,61 @@ +/* +* 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 . +* +* 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" +#include "kernel.h" + +typedef KSchedulableInterruptEvent* (*SGI0Handler_t)(KBaseInterruptEvent *this, u32 interruptID); + +// http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0360f/CCHDIFIJ.html +void executeFunctionOnCores(SGI0Handler_t func, u8 targetList, u8 targetListFilter); + +// Taken from ctrulib: + +static inline void __dsb(void) +{ + __asm__ __volatile__("mcr p15, 0, %[val], c7, c10, 4" :: [val] "r" (0) : "memory"); +} + +static inline void __clrex(void) +{ + __asm__ __volatile__("clrex" ::: "memory"); +} + +static inline s32 __ldrex(s32* addr) +{ + s32 val; + __asm__ __volatile__("ldrex %[val], %[addr]" : [val] "=r" (val) : [addr] "Q" (*addr)); + return val; +} + +static inline bool __strex(s32* addr, s32 val) +{ + bool res; + __asm__ __volatile__("strex %[res], %[val], %[addr]" : [res] "=&r" (res) : [val] "r" (val), [addr] "Q" (*addr)); + return res; +} diff --git a/sysmodules/rosalina/kernel_extension/include/types.h b/sysmodules/rosalina/kernel_extension/include/types.h new file mode 100644 index 000000000..68cb36434 --- /dev/null +++ b/sysmodules/rosalina/kernel_extension/include/types.h @@ -0,0 +1,97 @@ +/* +* 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 . +* +* 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. +*/ + +// Taken from ctrulib + +#pragma once + +#include +#include +#include + +/// The maximum value of a u64. +#define U64_MAX UINT64_MAX + +/// would be nice if newlib had this already +#ifndef SSIZE_MAX +#ifdef SIZE_MAX +#define SSIZE_MAX ((SIZE_MAX) >> 1) +#endif +#endif + +typedef uint8_t u8; ///< 8-bit unsigned integer +typedef uint16_t u16; ///< 16-bit unsigned integer +typedef uint32_t u32; ///< 32-bit unsigned integer +typedef uint64_t u64; ///< 64-bit unsigned integer + +typedef int8_t s8; ///< 8-bit signed integer +typedef int16_t s16; ///< 16-bit signed integer +typedef int32_t s32; ///< 32-bit signed integer +typedef int64_t s64; ///< 64-bit signed integer + +typedef volatile u8 vu8; ///< 8-bit volatile unsigned integer. +typedef volatile u16 vu16; ///< 16-bit volatile unsigned integer. +typedef volatile u32 vu32; ///< 32-bit volatile unsigned integer. +typedef volatile u64 vu64; ///< 64-bit volatile unsigned integer. + +typedef volatile s8 vs8; ///< 8-bit volatile signed integer. +typedef volatile s16 vs16; ///< 16-bit volatile signed integer. +typedef volatile s32 vs32; ///< 32-bit volatile signed integer. +typedef volatile s64 vs64; ///< 64-bit volatile signed integer. + +typedef u32 Handle; ///< Resource handle. +typedef s32 Result; ///< Function result. + +/// Creates a bitmask from a bit number. +#define BIT(n) (1U<<(n)) + +/// Aligns a struct (and other types?) to m, making sure that the size of the struct is a multiple of m. +#define ALIGN(m) __attribute__((aligned(m))) +/// Packs a struct (and other types?) so it won't include padding bytes. +#define PACKED __attribute__((packed)) +#define USED __attribute__((used)) +#define UNUSED __attribute__((unused)) +/// Packs a system version from its components. +#define SYSTEM_VERSION(major, minor, revision) \ + (((major)<<24)|((minor)<<16)|((revision)<<8)) + +#define CUR_THREAD_HANDLE 0xFFFF8000 +#define CUR_PROCESS_HANDLE 0xFFFF8001 + +#define MPCORE_REGS_BASE (0x17E00000 | (1u << 31)) +#define MPCORE_SCU_CFG (*(vu32 *)(MPCORE_REGS_BASE + 4)) +#define MPCORE_INT_ACK (*(vu32 *)(MPCORE_REGS_BASE + 0x10C)) + +#define MPCORE_GID_REGS_BASE (MPCORE_REGS_BASE + 0x1000) +#define MPCORE_GID_SGI (*(vu32 *)(MPCORE_GID_REGS_BASE + 0xF00)) + +#define CFG11_REGS_BASE (0x10140000 | (1u << 31)) +#define CFG11_WIFICNT (*(vu8 *)(CFG11_REGS_BASE + 0x180)) +#define CFG11_MPCORE_CFG (*(vu16 *)(CFG11_REGS_BASE + 0xFFC)) +#define CFG11_MPCORE_CLKCNT (*(vu16 *)(CFG11_REGS_BASE + 0x1300)) + +#define L2C_REGS_BASE (0x17E10000 | (1u << 31)) +#define L2C_CTRL (*(vu32 *)(L2C_REGS_BASE + 0x100)) diff --git a/sysmodules/rosalina/kernel_extension/include/utils.h b/sysmodules/rosalina/kernel_extension/include/utils.h new file mode 100644 index 000000000..4b17442ed --- /dev/null +++ b/sysmodules/rosalina/kernel_extension/include/utils.h @@ -0,0 +1,87 @@ +/* +* 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 . +* +* 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" +#include "kernel.h" + +// For accessing physmem uncached (and directly) +#define PA_PTR(addr) (void *)((u32)(addr) | 1u << 31) +#define PA_FROM_VA_PTR(addr) PA_PTR(convertVAToPA(addr, false)) + +static inline u32 makeARMBranch(const void *src, const void *dst, bool link) // the macros for those are ugly and buggy +{ + u32 instrBase = link ? 0xEB000000 : 0xEA000000; + u32 off = (u32)((const u8 *)dst - ((const u8 *)src + 8)); // the PC is always two instructions ahead of the one being executed + + return instrBase | ((off >> 2) & 0xFFFFFF); +} + +static inline void *decodeARMBranch(const void *src) +{ + u32 instr = *(const u32 *)src; + s32 off = (instr & 0xFFFFFF) << 2; + off = (off << 6) >> 6; // sign extend + + return (void *)((const u8 *)src + 8 + off); +} + +// For ARM prologs in the form of: push {regs} ... sub sp, #off (this obviously doesn't intend to cover all cases) +static inline u32 computeARMFrameSize(const u32 *prolog) +{ + const u32 *off; + + for(off = prolog; (*off >> 16) != 0xE92D; off++); // look for stmfd sp! = push + u32 nbPushedRegs = 0; + for(u32 val = *off & 0xFFFF; val != 0; val >>= 1) // 1 bit = 1 pushed register + nbPushedRegs += val & 1; + for(; (*off >> 8) != 0xE24DD0; off++); // look for sub sp, #offset + u32 localVariablesSpaceSize = *off & 0xFF; + + return 4 * nbPushedRegs + localVariablesSpaceSize; +} + +static inline u32 getNumberOfCores(void) +{ + return (MPCORE_SCU_CFG & 3) + 1; +} + +static inline u32 getCurrentCoreID(void) +{ + u32 coreId; + __asm__ volatile("mrc p15, 0, %0, c0, c0, 5" : "=r"(coreId)); + return coreId & 3; +} + +u32 convertVAToPA(const void *addr, bool writeCheck); + +u32 safecpy(void *dst, const void *src, u32 len); +void KObjectMutex__Acquire(KObjectMutex *this); +void KObjectMutex__Release(KObjectMutex *this); + +void flushEntireDataCache(void); +void invalidateEntireInstructionCache(void); diff --git a/exceptions/arm11/linker.ld b/sysmodules/rosalina/kernel_extension/linker.ld similarity index 94% rename from exceptions/arm11/linker.ld rename to sysmodules/rosalina/kernel_extension/linker.ld index fb780cd3f..f11a495ef 100644 --- a/exceptions/arm11/linker.ld +++ b/sysmodules/rosalina/kernel_extension/linker.ld @@ -4,11 +4,11 @@ OUTPUT_ARCH(arm) ENTRY(_start) SECTIONS { - . = 0; + . = 0x40000000; .text : ALIGN(4) { *(.text.start) *(.text*); . = ALIGN(4); } .rodata : ALIGN(4) { *(.rodata*); . = ALIGN(4); } .data : ALIGN(4) { *(.data*); . = ALIGN(8); *(.bss* COMMON); . = ALIGN(8); } - + . = ALIGN(4); } diff --git a/sysmodules/rosalina/kernel_extension/source/fatalExceptionHandlers.s b/sysmodules/rosalina/kernel_extension/source/fatalExceptionHandlers.s new file mode 100644 index 000000000..9a0c45549 --- /dev/null +++ b/sysmodules/rosalina/kernel_extension/source/fatalExceptionHandlers.s @@ -0,0 +1,249 @@ +@ 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 . +@ +@ 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. + +.macro TEST_IF_MODE_AND_ARM_INST_OR_JUMP lbl, mode + cpsid aif + mrs sp, spsr + tst sp, #0x20 + bne \lbl + and sp, #0x1f @ get previous processor mode + cmp sp, #\mode + bne \lbl + + sub sp, lr, #4 + mcr p15, 0, sp, c7, c8, 0 @ VA to PA translation with privileged read permission check + mrc p15, 0, sp, c7, c4, 0 @ read PA register + tst sp, #1 @ failure bit + bne \lbl +.endm + + +.macro GEN_USUAL_HANDLER name, index, pos + \name\()Handler: + ldr sp, =exceptionStackTop + ldr sp, [sp] + sub sp, #0x100 + + push {r0-r12, lr} + mrs r0, spsr + bl isExceptionFatal + cmp r0, #0 + pop {r0-r12, lr} + bne _exc_is_fatal_\name + + ldr sp, =originalHandlers + ldr sp, [sp, #\pos] + bx sp + + _exc_is_fatal_\name: + push {r8, r9} + mov r8, #\index + b _commonHandler +.endm + +.text +.arm +.balign 4 + +_die: + cpsid aif +_die_loop: + wfi + b _die_loop + +_commonHandler: + cpsid aif + + push {r0} + ldr r0, =_fatalExceptionOccured + ldr r0, [r0] + cmp r0, #0 + bne _die_loop + pop {r0} + + ldr r9, =_regs + stmia r9, {r0-r7} + mov r1, r8 + pop {r8,r9} + + ldr r0, =_fatalExceptionOccured + mov r4, #1 + + _try_lock: + ldrex r2, [r0] + strex r3, r4, [r0] + cmp r3, #0 + bne _try_lock + + push {r1, r12, lr} @ attempt to hang the other cores + adr r0, _die + mov r1, #0xf + mov r2, #1 + mov r3, #0 + bl executeFunctionOnCores + pop {r1, r12, lr} + + mrs r2, spsr + mrs r3, cpsr + ldr r6, =_regs + add r6, #0x20 + + ands r4, r2, #0xf @ get the mode that triggered the exception + moveq r4, #0xf @ usr => sys + bic r5, r3, #0xf + orr r5, r4 + msr cpsr_c, r5 @ change processor mode + stmia r6!, {r8-lr} + msr cpsr_c, r3 @ restore processor mode + + str lr, [r6], #4 + str r2, [r6], #4 + + mov r0, r6 + + mrc p15, 0, r4, c5, c0, 0 @ dfsr + mrc p15, 0, r5, c5, c0, 1 @ ifsr + mrc p15, 0, r6, c6, c0, 0 @ far + fmrx r7, fpexc + fmrx r8, fpinst + fmrx r9, fpinst2 + bic r3, #(1<<31) + fmxr fpexc, r3 @ clear the VFP11 exception flag (if it's set) + + stmia r0!, {r4-r9} + + mov r0, #0 + mcr p15, 0, r0, c7, c14, 0 @ Clean and Invalidate Entire Data Cache + mcr p15, 0, r0, c7, c10, 4 @ Drain Synchronization Barrier + + ldr r0, =isN3DS + ldr r0, [r0] + cmp r0, #0 + beq _no_L2C + ldr r0, =(0x17e10100 | 1 << 31) + ldr r0, [r0] + tst r0, #1 @ is the L2C enabled? + beq _no_L2C + + ldr r0, =0xffff + ldr r2, =(0x17e10730 | 1 << 31) + str r0, [r2, #0x4c] @ invalidate by way + + _L2C_sync: + ldr r0, [r2] @ L2C cache sync register + tst r0, #1 + bne _L2C_sync + + _no_L2C: + + cps #0x1F + ldr sp, =exceptionStackTop + ldr sp, [sp] + sub sp, #0x100 + + mov r0, #0 + mcr p15, 0, r0, c7, c10, 5 @ Drain Memory Barrier + ldr r0, =_regs + mrc p15, 0, r2, c0, c0, 5 @ CPU ID register + bl fatalExceptionHandlersMain + + ldr r12, =mcuReboot + ldr r12, [r12] + bx r12 + +.global FIQHandler +.type FIQHandler, %function +GEN_USUAL_HANDLER FIQ, 0, 28 + +.global undefinedInstructionHandler +.type undefinedInstructionHandler, %function +undefinedInstructionHandler: + TEST_IF_MODE_AND_ARM_INST_OR_JUMP _undefinedInstructionNormalHandler, 0x10 + + ldr sp, [lr, #-4] @ test if it's an VFP instruction that was aborted + lsl sp, #4 + sub sp, #0xc0000000 + cmp sp, #0x30000000 + bcs _undefinedInstructionNormalHandler + fmrx sp, fpexc + tst sp, #0x40000000 + bne _undefinedInstructionNormalHandler + + @ FPU init + sub lr, #4 + srsfd sp!, #0x13 + cps #0x13 + stmfd sp, {r0-r3, r11-lr}^ + sub sp, #0x20 + ldr r12, =initFPU + ldr r12, [r12] + blx r12 + ldmfd sp, {r0-r3, r11-lr}^ + add sp, #0x20 + rfefd sp! @ retry aborted instruction + + GEN_USUAL_HANDLER _undefinedInstructionNormal, 1, 4 + +.global prefetchAbortHandler +.type prefetchAbortHandler, %function +prefetchAbortHandler: + TEST_IF_MODE_AND_ARM_INST_OR_JUMP _prefetchAbortNormalHandler, 0x13 + + ldr sp, =(Break + 3*4 + 4) + cmp lr, sp + bne _prefetchAbortNormalHandler + + sub sp, r0, #0x110 + pop {r0-r7, r12, lr} + pop {r8-r11} + ldr lr, [sp, #8]! + ldr sp, [sp, #4] + msr spsr, sp + addne lr, #2 @ adjust address for later + + GEN_USUAL_HANDLER _prefetchAbortNormal, 2, 12 + +.global dataAbortHandler +.type dataAbortHandler, %function +dataAbortHandler: + ldr sp, =exceptionStackTop + ldr sp, [sp] + push {r0-r12, lr} + mrs r0, spsr + sub r1, lr, #8 + bl isDataAbortExceptionRangeControlled + cmp r0, #0 + pop {r0-r12, lr} + beq _dataAbortNormalHandler + + msr spsr_f, #(1 << 30) + mov r12, #0 + subs pc, lr, #4 + + GEN_USUAL_HANDLER _dataAbortNormal, 3, 16 + +.bss +.balign 4 +_regs: .skip (4 * 23) +_fatalExceptionOccured: .word 0 diff --git a/sysmodules/rosalina/kernel_extension/source/fatalExceptionHandlersMain.c b/sysmodules/rosalina/kernel_extension/source/fatalExceptionHandlersMain.c new file mode 100644 index 000000000..8879ae7ab --- /dev/null +++ b/sysmodules/rosalina/kernel_extension/source/fatalExceptionHandlersMain.c @@ -0,0 +1,125 @@ +/* +* 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 . +* +* 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. +*/ + +#include "fatalExceptionHandlers.h" +#include "utils.h" +#include "kernel.h" +#include "memory.h" +#include "globals.h" + +#define REG_DUMP_SIZE 4 * 23 +#define CODE_DUMP_SIZE 48 + +bool isExceptionFatal(u32 spsr) +{ + if((spsr & 0x1f) != 0x10) return true; + + KThread *thread = currentCoreContext->objectContext.currentThread; + KProcess *currentProcess = currentCoreContext->objectContext.currentProcess; + + if(thread != NULL && thread->threadLocalStorage != NULL && *((vu32 *)thread->threadLocalStorage + 0x10) != 0) + return false; + + if(currentProcess != NULL) + { + if(debugOfProcess(currentProcess) != NULL) + return false; + + thread = KPROCESS_GET_RVALUE(currentProcess, mainThread); + if(thread != NULL && thread->threadLocalStorage != NULL && *((vu32 *)thread->threadLocalStorage + 0x10) != 0) + return false; + } + + return true; +} + +extern u32 safecpy_sz; +bool isDataAbortExceptionRangeControlled(u32 spsr, u32 addr) +{ + return ((spsr & 0x1F) != 0x10) && ( + ((u32)kernelUsrCopyFuncsStart <= addr && addr < (u32)kernelUsrCopyFuncsEnd) || + ((u32)safecpy <= addr && addr < (u32)safecpy + safecpy_sz) + ); +} +void fatalExceptionHandlersMain(u32 *registerDump, u32 type, u32 cpuId) +{ + ExceptionDumpHeader dumpHeader; + + u8 codeDump[CODE_DUMP_SIZE]; + u8 *finalBuffer = (u8 *)PA_PTR(0x25000000); + u8 *final = finalBuffer; + + dumpHeader.magic[0] = 0xDEADC0DE; + dumpHeader.magic[1] = 0xDEADCAFE; + dumpHeader.versionMajor = 1; + dumpHeader.versionMinor = 2; + + dumpHeader.processor = 11; + dumpHeader.core = cpuId & 0xF; + dumpHeader.type = type; + + dumpHeader.registerDumpSize = REG_DUMP_SIZE; + dumpHeader.codeDumpSize = CODE_DUMP_SIZE; + + u32 cpsr = registerDump[16]; + u32 pc = registerDump[15] - (type < 3 ? (((cpsr & 0x20) != 0 && type == 1) ? 2 : 4) : 8); + + registerDump[15] = pc; + + //Dump code + u8 *instr = (u8 *)pc + ((cpsr & 0x20) ? 2 : 4) - dumpHeader.codeDumpSize; //Doesn't work well on 32-bit Thumb instructions, but it isn't much of a problem + dumpHeader.codeDumpSize = ((u32)instr & (((cpsr & 0x20) != 0) ? 1 : 3)) != 0 ? 0 : safecpy(codeDump, instr, dumpHeader.codeDumpSize); + + //Copy register dump and code dump + final = (u8 *)(finalBuffer + sizeof(ExceptionDumpHeader)); + memcpy(final, registerDump, dumpHeader.registerDumpSize); + final += dumpHeader.registerDumpSize; + memcpy(final, codeDump, dumpHeader.codeDumpSize); + final += dumpHeader.codeDumpSize; + + //Dump stack in place + dumpHeader.stackDumpSize = safecpy(final, (const void *)registerDump[13], 0x1000 - (registerDump[13] & 0xFFF)); + final += dumpHeader.stackDumpSize; + + if(currentCoreContext->objectContext.currentProcess) + { + vu64 *additionalData = (vu64 *)final; + KCodeSet *currentCodeSet = codeSetOfProcess(currentCoreContext->objectContext.currentProcess); + if(currentCodeSet != NULL) + { + dumpHeader.additionalDataSize = 16; + memcpy((void *)additionalData, currentCodeSet->processName, 8); + additionalData[1] = currentCodeSet->titleId; + } + else dumpHeader.additionalDataSize = 0; + } + else dumpHeader.additionalDataSize = 0; + + dumpHeader.totalSize = sizeof(ExceptionDumpHeader) + dumpHeader.registerDumpSize + dumpHeader.codeDumpSize + dumpHeader.stackDumpSize + dumpHeader.additionalDataSize; + + //Copy header (actually optimized by the compiler) + *(ExceptionDumpHeader *)finalBuffer = dumpHeader; +} diff --git a/sysmodules/rosalina/kernel_extension/source/globals.c b/sysmodules/rosalina/kernel_extension/source/globals.c new file mode 100644 index 000000000..f6fa070a1 --- /dev/null +++ b/sysmodules/rosalina/kernel_extension/source/globals.c @@ -0,0 +1,104 @@ +/* +* 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 . +* +* 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. +*/ + +#include "globals.h" + +KRecursiveLock *criticalSectionLock; +KObjectList *threadList; +KObjectMutex *synchronizationMutex; + +void (*KRecursiveLock__Lock)(KRecursiveLock *this); +void (*KRecursiveLock__Unlock)(KRecursiveLock *this); + +void (*KAutoObject__AddReference)(KAutoObject *this); +KProcess * (*KProcessHandleTable__ToKProcess)(KProcessHandleTable *this, Handle processHandle); +KThread * (*KProcessHandleTable__ToKThread)(KProcessHandleTable *this, Handle threadHandle); +KAutoObject * (*KProcessHandleTable__ToKAutoObject)(KProcessHandleTable *this, Handle handle); +void (*KSynchronizationObject__Signal)(KSynchronizationObject *this, bool isPulse); +Result (*WaitSynchronization1)(void *this_unused, KThread *thread, KSynchronizationObject *syncObject, s64 timeout); +Result (*KProcessHandleTable__CreateHandle)(KProcessHandleTable *this, Handle *out, KAutoObject *obj, u8 token); +Result (*KProcessHwInfo__MapProcessMemory)(KProcessHwInfo *this, KProcessHwInfo *other, void *dst, void *src, u32 nbPages); +Result (*KProcessHwInfo__UnmapProcessMemory)(KProcessHwInfo *this, void *addr, u32 nbPages); +Result (*KEvent__Clear)(KEvent *this); +void (*KObjectMutex__WaitAndAcquire)(KObjectMutex *this); +void (*KObjectMutex__ErrorOccured)(void); + +void (*KScheduler__AdjustThread)(KScheduler *this, KThread *thread, u32 oldSchedulingMask); +void (*KScheduler__AttemptSwitchingThreadContext)(KScheduler *this); + +Result (*ControlMemory)(u32 *addrOut, u32 addr0, u32 addr1, u32 size, MemOp op, MemPerm perm, bool isLoader); +void (*SleepThread)(s64 ns); +Result (*CloseHandle)(Handle handle); +Result (*GetSystemInfo)(s64 *out, s32 type, s32 param); +Result (*GetProcessInfo)(s64 *out, Handle processHandle, u32 type); +Result (*GetThreadInfo)(s64 *out, Handle threadHandle, u32 type); +Result (*ConnectToPort)(Handle *out, const char *name); +Result (*SendSyncRequest)(Handle handle); +Result (*OpenProcess)(Handle *out, u32 processId); +Result (*GetProcessId)(u32 *out, Handle process); +Result (*DebugActiveProcess)(Handle *out, u32 processId); +Result (*KernelSetState)(u32 type, u32 varg1, u32 varg2, u32 varg3); + +void (*flushDataCacheRange)(void *addr, u32 len); +void (*invalidateInstructionCacheRange)(void *addr, u32 len); + +bool (*usrToKernelMemcpy8)(void *dst, const void *src, u32 len); +bool (*usrToKernelMemcpy32)(u32 *dst, const u32 *src, u32 len); +s32 (*usrToKernelStrncpy)(char *dst, const char *src, u32 len); +bool (*kernelToUsrMemcpy8)(void *dst, const void *src, u32 len); +bool (*kernelToUsrMemcpy32)(u32 *dst, const u32 *src, u32 len); +s32 (*kernelToUsrStrncpy)(char *dst, const char *src, u32 len); + +Result (*CustomBackdoor)(void *function, ...); + +void (*svcFallbackHandler)(u8 svcId); +void (*kernelpanic)(void); +void (*PostprocessSvc)(void); + +Result (*SignalDebugEvent)(DebugEventType type, u32 info, ...); + +bool isN3DS; +u32 *exceptionStackTop; + +u32 TTBCR; +u32 L1MMUTableAddrs[4]; + +u32 kernelVersion; +void *kernelUsrCopyFuncsStart, *kernelUsrCopyFuncsEnd; + +bool *isDevUnit; + +InterruptManager *interruptManager; +KBaseInterruptEvent *customInterruptEvent; + +void (*initFPU)(void); +void (*mcuReboot)(void); +void (*coreBarrier)(void); + +CfwInfo cfwInfo; + +u32 rosalinaState; +bool hasStartedRosalinaNetworkFuncsOnce; diff --git a/sysmodules/rosalina/kernel_extension/source/ipc.c b/sysmodules/rosalina/kernel_extension/source/ipc.c new file mode 100644 index 000000000..9fbb51db9 --- /dev/null +++ b/sysmodules/rosalina/kernel_extension/source/ipc.c @@ -0,0 +1,321 @@ +/* +* 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 . +* +* 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. +*/ + +#include "ipc.h" +#include "memory.h" + +static SessionInfo sessionInfos[MAX_SESSION] = { {NULL} }; +static u32 nbActiveSessions = 0; +static KRecursiveLock sessionInfosLock = { NULL }; + +KRecursiveLock processLangemuLock; +LangemuAttributes processLangemuAttributes[0x40]; + +static void *customSessionVtable[0x10] = { NULL }; // should be enough + +static u32 SessionInfo_FindClosestSlot(KSession *session) +{ + if(nbActiveSessions == 0 || session <= sessionInfos[0].session) + return 0; + else if(session > sessionInfos[nbActiveSessions - 1].session) + return nbActiveSessions; + + u32 a = 0, b = nbActiveSessions - 1, m; + + do + { + m = (a + b) / 2; + if(sessionInfos[m].session < session) + a = m; + else if(sessionInfos[m].session > session) + b = m; + else + return m; + } + while(b - a > 1); + + return b; +} + +SessionInfo *SessionInfo_Lookup(KSession *session) +{ + KRecursiveLock__Lock(criticalSectionLock); + KRecursiveLock__Lock(&sessionInfosLock); + + SessionInfo *ret; + u32 id = SessionInfo_FindClosestSlot(session); + if(id == nbActiveSessions) + ret = NULL; + else + ret = (void **)(sessionInfos[id].session->autoObject.vtable) == customSessionVtable ? &sessionInfos[id] : NULL; + + KRecursiveLock__Unlock(&sessionInfosLock); + KRecursiveLock__Unlock(criticalSectionLock); + + return ret; +} + +SessionInfo *SessionInfo_FindFirst(const char *name) +{ + KRecursiveLock__Lock(criticalSectionLock); + KRecursiveLock__Lock(&sessionInfosLock); + + SessionInfo *ret; + u32 id; + for(id = 0; id < nbActiveSessions && strncmp(sessionInfos[id].name, name, 12) != 0; id++); + if(id == nbActiveSessions) + ret = NULL; + else + ret = (void **)(sessionInfos[id].session->autoObject.vtable) == customSessionVtable ? &sessionInfos[id] : NULL; + + KRecursiveLock__Unlock(&sessionInfosLock); + KRecursiveLock__Unlock(criticalSectionLock); + + return ret; +} + +void SessionInfo_Add(KSession *session, const char *name) +{ + KAutoObject__AddReference(&session->autoObject); + SessionInfo_ChangeVtable(session); + session->autoObject.vtable->DecrementReferenceCount(&session->autoObject); + + KRecursiveLock__Lock(criticalSectionLock); + KRecursiveLock__Lock(&sessionInfosLock); + + if(nbActiveSessions == MAX_SESSION) + { + KRecursiveLock__Unlock(&sessionInfosLock); + KRecursiveLock__Unlock(criticalSectionLock); + return; + } + + u32 id = SessionInfo_FindClosestSlot(session); + + if(id != nbActiveSessions && sessionInfos[id].session == session) + { + KRecursiveLock__Unlock(&sessionInfosLock); + KRecursiveLock__Unlock(criticalSectionLock); + return; + } + + for(u32 i = nbActiveSessions; i > id && i != 0; i--) + sessionInfos[i] = sessionInfos[i - 1]; + + nbActiveSessions++; + + sessionInfos[id].session = session; + strncpy(sessionInfos[id].name, name, 12); + + KRecursiveLock__Unlock(&sessionInfosLock); + KRecursiveLock__Unlock(criticalSectionLock); +} + +void SessionInfo_Remove(KSession *session) +{ + KRecursiveLock__Lock(criticalSectionLock); + KRecursiveLock__Lock(&sessionInfosLock); + + if(nbActiveSessions == MAX_SESSION) + { + KRecursiveLock__Unlock(&sessionInfosLock); + KRecursiveLock__Unlock(criticalSectionLock); + return; + } + + u32 id = SessionInfo_FindClosestSlot(session); + + if(id == nbActiveSessions) + { + KRecursiveLock__Unlock(&sessionInfosLock); + KRecursiveLock__Unlock(criticalSectionLock); + return; + } + + for(u32 i = id; i < nbActiveSessions - 1; i++) + sessionInfos[i] = sessionInfos[i + 1]; + + memset(&sessionInfos[--nbActiveSessions], 0, sizeof(SessionInfo)); + + KRecursiveLock__Unlock(&sessionInfosLock); + KRecursiveLock__Unlock(criticalSectionLock); +} + +static void (*KSession__dtor_orig)(KAutoObject *this); +static void KSession__dtor_hook(KAutoObject *this) +{ + KSession__dtor_orig(this); + SessionInfo_Remove((KSession *)this); +} + +void SessionInfo_ChangeVtable(KSession *session) +{ + if(customSessionVtable[2] == NULL) + { + memcpy(customSessionVtable, session->autoObject.vtable, 0x40); + KSession__dtor_orig = session->autoObject.vtable->dtor; + customSessionVtable[2] = (void *)KSession__dtor_hook; + } + session->autoObject.vtable = (Vtable__KAutoObject *)customSessionVtable; +} + +bool doLangEmu(Result *res, Handle handle, u32 *cmdbuf) +{ + KRecursiveLock__Lock(criticalSectionLock); + KRecursiveLock__Lock(&processLangemuLock); + + u64 titleId = codeSetOfProcess(currentCoreContext->objectContext.currentProcess)->titleId; + LangemuAttributes *attribs = NULL; + bool skip = true; + + *res = 0; + for(u32 i = 0; i < 0x40; i++) + { + if(processLangemuAttributes[i].titleId == titleId) + attribs = &processLangemuAttributes[i]; + } + + if(attribs == NULL) + { + KRecursiveLock__Unlock(&processLangemuLock); + KRecursiveLock__Unlock(criticalSectionLock); + return false; + } + + if((cmdbuf[0] == 0x20000 || cmdbuf[0] == 0x4060000 || cmdbuf[0] == 0x8160000) && (attribs->mask & 1)) // SecureInfoGetRegion + { + cmdbuf[0] = (cmdbuf[0] & 0xFFFF0000) | 0x80; + cmdbuf[1] = 0; + cmdbuf[2] = attribs->region; + } + else if(cmdbuf[1] == 1 && cmdbuf[2] == 0xA0002 && cmdbuf[3] == 0x1C && (attribs->mask & 2)) + { + cmdbuf[0] = (cmdbuf[0] & 0xFFFF0000) | 0x40; + cmdbuf[1] = 0; + *(u8 *)cmdbuf[4] = attribs->language; + } + else if(cmdbuf[1] == 4 && cmdbuf[2] == 0xB0000 && cmdbuf[3] == 0x4C && (attribs->mask & 0xC)) + { + u8 *ptr = (u8 *)cmdbuf[4]; + *res = SendSyncRequest(handle); + flushEntireDataCache(); // looks like it's needed. WTF?! + if(*res == 0) + { + if(attribs->mask & 4) + ptr[3] = attribs->country; + if(attribs->mask & 8) + ptr[2] = attribs->state; + } + } + else + skip = false; + + KRecursiveLock__Unlock(&processLangemuLock); + KRecursiveLock__Unlock(criticalSectionLock); + return skip; +} + +Result doPublishToProcessHook(Handle handle, u32 *cmdbuf) +{ + Result res = 0; + u32 pid; + bool terminateRosalina = cmdbuf[1] == 0x100 && cmdbuf[2] == 0; // cmdbuf[2] to check for well-formed requests + u32 savedCmdbuf[4]; + memcpy(savedCmdbuf, cmdbuf, 16); + + if(!terminateRosalina || GetProcessId(&pid, cmdbuf[3]) != 0) + terminateRosalina = false; + else + { + KProcessHandleTable *handleTable = handleTableOfProcess(currentCoreContext->objectContext.currentProcess); + KProcess *process = KProcessHandleTable__ToKProcess(handleTable, cmdbuf[3]); + if((strcmp(codeSetOfProcess(process)->processName, "socket") == 0 && (rosalinaState & 2)) || + strcmp(codeSetOfProcess(process)->processName, "pxi") == 0) + terminateRosalina = true; + else + terminateRosalina = false; + ((KAutoObject *)process)->vtable->DecrementReferenceCount((KAutoObject *)process); + } + + if(terminateRosalina) + { + Handle rosalinaProcessHandle; + res = OpenProcess(&rosalinaProcessHandle, 5); + if(res == 0) + { + cmdbuf[0] = cmdbuf[0]; + cmdbuf[1] = 0x100; + cmdbuf[2] = 0; + cmdbuf[3] = rosalinaProcessHandle; + + res = SendSyncRequest(handle); + CloseHandle(rosalinaProcessHandle); + memcpy(cmdbuf, savedCmdbuf, 16); + } + } + + return SendSyncRequest(handle); +} + +bool doErrfThrowHook(u32 *cmdbuf) +{ + // If fatalErrorInfo->type is "card removed" or "logged", returning from ERRF:Throw is a no-op + // for the SDK function + + // r6 (arm) or r4 (thumb) is copied into cmdbuf[1..31] + u32 *r0_to_r7_r12_usr = (u32 *)((u8 *)currentCoreContext->objectContext.currentThread->endOfThreadContext - 0x110); + u32 spsr = *(u32 *)((u8 *)currentCoreContext->objectContext.currentThread->endOfThreadContext - 0xCC); + u8 *srcerrbuf = (u8 *)r0_to_r7_r12_usr[(spsr & 0x20) ? 4 : 6]; + const char *pname = codeSetOfProcess(currentCoreContext->objectContext.currentProcess)->processName; + + static const struct + { + const char *name; + Result errCode; + } errorCodesToIgnore[] = + { + /* + If you're getting this error, you have broken your head-tracking hardware, + and should uncomment the following line: + */ + //{ "qtm", (Result)0xF96183FE }, + + { "", 0 }, // impossible case to ensure the array has at least 1 element + }; + + for(u32 i = 0; i < sizeof(errorCodesToIgnore) / sizeof(errorCodesToIgnore[0]); i++) + { + if(strcmp(pname, errorCodesToIgnore[i].name) == 0 && (Result)cmdbuf[2] == errorCodesToIgnore[i].errCode) + { + srcerrbuf[0] = 5; + cmdbuf[0] = 0x10040; + cmdbuf[1] = 0; + return true; + } + } + + return false; +} diff --git a/sysmodules/rosalina/kernel_extension/source/main.c b/sysmodules/rosalina/kernel_extension/source/main.c new file mode 100644 index 000000000..0b20ef94a --- /dev/null +++ b/sysmodules/rosalina/kernel_extension/source/main.c @@ -0,0 +1,310 @@ +/* +* 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 . +* +* 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. +*/ + +#include "utils.h" +#include "globals.h" +#include "synchronization.h" +#include "fatalExceptionHandlers.h" +#include "svc.h" +#include "svc/ConnectToPort.h" +#include "svcHandler.h" +#include "memory.h" + +static const u32 *const exceptionsPage = (const u32 *)0xFFFF0000; +void *originalHandlers[8] = {NULL}; + +enum VECTORS { RESET = 0, UNDEFINED_INSTRUCTION, SVC, PREFETCH_ABORT, DATA_ABORT, RESERVED, IRQ, FIQ }; + +static void setupSGI0Handler(void) +{ + for(u32 i = 0; i < getNumberOfCores(); i++) + interruptManager->N3DS.privateInterrupts[i][0].interruptEvent = customInterruptEvent; +} + +static inline void **getHandlerDestination(enum VECTORS vector) +{ + u32 *branch_dst = (u32 *)decodeARMBranch((u32 *)exceptionsPage + (u32)vector); + return (void **)(branch_dst + 2); +} + +static inline void swapHandlerInVeneer(enum VECTORS vector, void *handler) +{ + void **dst = getHandlerDestination(vector); + originalHandlers[(u32)vector] = *dst; + if(handler != NULL) + *(void**)PA_FROM_VA_PTR(dst) = handler; +} + +static u32 *trampo_; +static bool **enableUserExceptionHandlersForCPUExcLoc; +static bool enableUserExceptionHandlersForCPUExc = true; + +static void setupSvcHandler(void) +{ + swapHandlerInVeneer(SVC, svcHandler); + + void **arm11SvcTable = (void**)originalHandlers[(u32)SVC]; + while(*arm11SvcTable != NULL) arm11SvcTable++; //Look for SVC0 (NULL) + memcpy(officialSVCs, arm11SvcTable, 4 * 0x7E); + + u32 *off; + for(off = (u32 *)officialSVCs[0x2D]; *off != 0x65736162; off++); + *(void **)PA_FROM_VA_PTR(arm11SvcTable + 0x2D) = officialSVCs[0x2D] = (void *)off[1]; + trampo_ = (u32 *)PA_FROM_VA_PTR(off + 3); + + CustomBackdoor = (Result (*)(void *, ...))((u32 *)officialSVCs[0x2F] + 2); + *(void **)PA_FROM_VA_PTR(arm11SvcTable + 0x2F) = officialSVCs[0x2F] = (void *)*((u32 *)officialSVCs[0x2F] + 1); + + off = (u32 *)originalHandlers[(u32) SVC]; + while(*off++ != 0xE1A00009); + svcFallbackHandler = (void (*)(u8))decodeARMBranch(off); + for(; *off != 0xE92D000F; off++); + PostprocessSvc = (void (*)(void))decodeARMBranch(off + 1); +} + +static void setupExceptionHandlers(void) +{ + swapHandlerInVeneer(FIQ, FIQHandler); + swapHandlerInVeneer(UNDEFINED_INSTRUCTION, undefinedInstructionHandler); + swapHandlerInVeneer(PREFETCH_ABORT, prefetchAbortHandler); + swapHandlerInVeneer(DATA_ABORT, dataAbortHandler); + + setupSvcHandler(); +} + +static void findUsefulSymbols(void) +{ + u32 *off; + + KProcessHandleTable__ToKProcess = (KProcess * (*)(KProcessHandleTable *, Handle))decodeARMBranch(5 + (u32 *)officialSVCs[0x76]); + + for(off = (u32 *)KProcessHandleTable__ToKProcess; *off != 0xE28DD014; off++); + KAutoObject__AddReference = (void (*)(KAutoObject *))decodeARMBranch(off - 1); + + for(; *off != 0xE8BD80F0; off++); + KProcessHandleTable__ToKAutoObject = (KAutoObject * (*)(KProcessHandleTable *, Handle))decodeARMBranch(off + 2); + + for(off = (u32 *)decodeARMBranch(3 + (u32 *)officialSVCs[9]); /* KThread::Terminate */ *off != 0xE5D42034; off++); + off -= 2; + criticalSectionLock = (KRecursiveLock *)off[2 + (off[0] & 0xFF) / 4]; + KRecursiveLock__Lock = (void (*)(KRecursiveLock *))decodeARMBranch(off + 1); + off += 4; + + for(; (*off >> 16) != 0xE59F; off++); + KRecursiveLock__Unlock = (void (*)(KRecursiveLock *))decodeARMBranch(off + 1); + + for(; *off != 0xE5C4007D; off++); + KSynchronizationObject__Signal = (void (*)(KSynchronizationObject *, bool))decodeARMBranch(off + 3); + + for(off = (u32 *)officialSVCs[0x19]; *off != 0xE1A04005; off++); + KEvent__Clear = (Result (*)(KEvent *))decodeARMBranch(off + 1); + for(off = (u32 *)KEvent__Clear; *off != 0xE8BD8070; off++) + synchronizationMutex = *(KObjectMutex **)(off + 1); + + for(off = (u32 *)officialSVCs[0x24]; *off != 0xE59F004C; off++); + WaitSynchronization1 = (Result (*)(void *, KThread *, KSynchronizationObject *, s64))decodeARMBranch(off + 6); + + for(off = (u32 *)decodeARMBranch(3 + (u32 *)officialSVCs[0x33]) /* OpenProcess */ ; *off != 0xE20030FF; off++); + KProcessHandleTable__CreateHandle = (Result (*)(KProcessHandleTable *, Handle *, KAutoObject *, u8))decodeARMBranch(off + 2); + + for(off = (u32 *)decodeARMBranch(3 + (u32 *)officialSVCs[0x34]) /* OpenThread */; *off != 0xD9001BF7; off++); + threadList = *(KObjectList **)(off + 1); + + KProcessHandleTable__ToKThread = (KThread * (*)(KProcessHandleTable *, Handle))decodeARMBranch((u32 *)decodeARMBranch((u32 *)officialSVCs[0x37] + 3) /* GetThreadId */ + 5); + + for(off = (u32 *)officialSVCs[0x54]; *off != 0xE8BD8008; off++); + flushDataCacheRange = (void (*)(void *, u32))(*(u32 **)(off[1]) + 3); + + for(off = (u32 *)officialSVCs[0x71]; *off != 0xE2101102; off++); + KProcessHwInfo__MapProcessMemory = (Result (*)(KProcessHwInfo *, KProcessHwInfo *, void *, void *, u32))decodeARMBranch(off - 1); + + for(off = (u32 *)officialSVCs[0x72]; *off != 0xE2041102; off++); + KProcessHwInfo__UnmapProcessMemory = (Result (*)(KProcessHwInfo *, void *, u32))decodeARMBranch(off - 1); + + for(off = (u32 *)officialSVCs[0x7C]; *off != 0x03530000; off++); + KObjectMutex__WaitAndAcquire = (void (*)(KObjectMutex *))decodeARMBranch(++off); + for(; *off != 0xE320F000; off++); + KObjectMutex__ErrorOccured = (void (*)(void))decodeARMBranch(off + 1); + + for(off = (u32 *)originalHandlers[(u32) DATA_ABORT]; *off != (u32)exceptionStackTop; off++); + kernelUsrCopyFuncsStart = (void *)off[1]; + kernelUsrCopyFuncsEnd = (void *)off[2]; + + u32 n_cmp_0; + for(off = (u32 *)kernelUsrCopyFuncsStart, n_cmp_0 = 1; n_cmp_0 <= 6; off++) + { + if(*off == 0xE3520000) + { + // We're missing some funcs + switch(n_cmp_0) + { + case 1: + usrToKernelMemcpy8 = (bool (*)(void *, const void *, u32))off; + break; + case 2: + usrToKernelMemcpy32 = (bool (*)(u32 *, const u32 *, u32))off; + break; + case 3: + usrToKernelStrncpy = (s32 (*)(char *, const char *, u32))off; + break; + case 4: + kernelToUsrMemcpy8 = (bool (*)(void *, const void *, u32))off; + break; + case 5: + kernelToUsrMemcpy32 = (bool (*)(u32 *, const u32 *, u32))off; + break; + case 6: + kernelToUsrStrncpy = (s32 (*)(char *, const char *, u32))off; + break; + default: break; + } + n_cmp_0++; + } + } + + // The official prototype of ControlMemory doesn't have that extra param' + ControlMemory = (Result (*)(u32 *, u32, u32, u32, MemOp, MemPerm, bool)) + decodeARMBranch((u32 *)officialSVCs[0x01] + 5); + SleepThread = (void (*)(s64))officialSVCs[0x0A]; + CloseHandle = (Result (*)(Handle))officialSVCs[0x23]; + GetSystemInfo = (Result (*)(s64 *, s32, s32))decodeARMBranch((u32 *)officialSVCs[0x2A] + 3); + GetProcessInfo = (Result (*)(s64 *, Handle, u32))decodeARMBranch((u32 *)officialSVCs[0x2B] + 3); + GetThreadInfo = (Result (*)(s64 *, Handle, u32))decodeARMBranch((u32 *)officialSVCs[0x2C] + 3); + ConnectToPort = (Result (*)(Handle *, const char*))decodeARMBranch((u32 *)officialSVCs[0x2D] + 3); + SendSyncRequest = (Result (*)(Handle))officialSVCs[0x32]; + OpenProcess = (Result (*)(Handle *, u32))decodeARMBranch((u32 *)officialSVCs[0x33] + 3); + GetProcessId = (Result (*)(u32 *, Handle))decodeARMBranch((u32 *)officialSVCs[0x35] + 3); + DebugActiveProcess = (Result (*)(Handle *, u32))decodeARMBranch((u32 *)officialSVCs[0x60] + 3); + KernelSetState = (Result (*)(u32, u32, u32, u32))((u32 *)officialSVCs[0x7C] + 1); + + for(off = (u32 *)svcFallbackHandler; *off != 0xE8BD4010; off++); + kernelpanic = (void (*)(void))off; + + for(off = (u32 *)0xFFFF0000; off[0] != 0xE3A01002 || off[1] != 0xE3A00004; off++); + SignalDebugEvent = (Result (*)(DebugEventType type, u32 info, ...))decodeARMBranch(off + 2); + + for(; *off != 0x96007F9; off++); + isDevUnit = *(bool **)(off - 1); + enableUserExceptionHandlersForCPUExcLoc = (bool **)(off + 1); + + /////////////////////////////////////////// + + // Shitty/lazy heuristic but it works on even 4.5, so... + u32 textStart = ((u32)originalHandlers[(u32) SVC]) & ~0xFFFF; + u32 rodataStart = (u32)(interruptManager->N3DS.privateInterrupts[0][6].interruptEvent->vtable) & ~0xFFF; + + u32 textSize = rodataStart - textStart; + for(off = (u32 *)textStart; off < (u32 *)(textStart + textSize) - 3; off++) + { + if(off[0] == 0xE5D13034 && off[1] == 0xE1530002) + KScheduler__AdjustThread = (void (*)(KScheduler *, KThread *, u32))off; + else if(off[0] == (u32)interruptManager && off[1] == (u32)¤tCoreContext->objectContext) + KScheduler__AttemptSwitchingThreadContext = (void (*)(KScheduler *))(off - 2); + else if(off[0] == 0xE3510B1A && off[1] == 0xE3A06000) + { + u32 *off2; + for(off2 = off; *off2 != 0xE92D40F8; off2--); + invalidateInstructionCacheRange = (void (*)(void *, u32))off2; + } + } +} + +struct Parameters +{ + void (*SGI0HandlerCallback)(struct Parameters *, u32 *); + InterruptManager *interruptManager; + u32 *L2MMUTable; // bit31 mapping + + void (*initFPU)(void); + void (*mcuReboot)(void); + void (*coreBarrier)(void); + + u32 TTBCR; + u32 L1MMUTableAddrs[4]; + + u32 kernelVersion; + + CfwInfo cfwInfo; +}; + +static void enableDebugFeatures(void) +{ + *isDevUnit = true; // for debug SVCs and user exc. handlers, etc. + *(bool **)PA_FROM_VA_PTR(enableUserExceptionHandlersForCPUExcLoc) = &enableUserExceptionHandlersForCPUExc; + + u32 *off; + for(off = (u32 *)officialSVCs[0x7C]; off[0] != 0xE5D00001 || off[1] != 0xE3500000; off++); + *(u32 *)PA_FROM_VA_PTR(off + 2) = 0xE1A00000; // in case 6: beq -> nop + + for(off = (u32 *)DebugActiveProcess; *off != 0xE3110001; off++); + *(u32 *)PA_FROM_VA_PTR(off) = 0xE3B01001; // tst r1, #1 -> movs r1, #1 +} + +static void doOtherPatches(void) +{ + u32 *kpanic = (u32 *)kernelpanic; + *(u32 *)PA_FROM_VA_PTR(kpanic) = 0xE12FFF7E; // bkpt 0xFFFE + + u32 *off; + for(off = (u32 *)ControlMemory; (off[0] & 0xFFF0FFFF) != 0xE3500001 || (off[1] & 0xFFFF0FFF) != 0x13A00000; off++); + off -= 2; + + /* + Here we replace currentProcess->processID == 1 by additionnalParameter == 1. + This patch should be generic enough to work even on firmware version 5.0. + + It effectively changes the prototype of the ControlMemory function which + only caller is the svc 0x01 handler on OFW. + */ + *(u32 *)PA_FROM_VA_PTR(off) = 0xE59D0000 | (*off & 0x0000F000) | (8 + computeARMFrameSize((u32 *)ControlMemory)); // ldr r0, [sp, #(frameSize + 8)] + +} + +void main(volatile struct Parameters *p) +{ + isN3DS = getNumberOfCores() == 4; + interruptManager = p->interruptManager; + + initFPU = p->initFPU; + mcuReboot = p->mcuReboot; + coreBarrier = p->coreBarrier; + + TTBCR = p->TTBCR; + memcpy(L1MMUTableAddrs, (const void *)p->L1MMUTableAddrs, 16); + exceptionStackTop = (u32 *)0xFFFF2000 + (1 << (32 - TTBCR - 20)); + kernelVersion = p->kernelVersion; + cfwInfo = p->cfwInfo; + + setupSGI0Handler(); + setupExceptionHandlers(); + findUsefulSymbols(); + enableDebugFeatures(); + doOtherPatches(); + + rosalinaState = 0; + hasStartedRosalinaNetworkFuncsOnce = false; + *trampo_ = (u32)ConnectToPortHookWrapper; +} diff --git a/sysmodules/rosalina/kernel_extension/source/memory.c b/sysmodules/rosalina/kernel_extension/source/memory.c new file mode 100644 index 000000000..4f6b8a027 --- /dev/null +++ b/sysmodules/rosalina/kernel_extension/source/memory.c @@ -0,0 +1,176 @@ +/* +* 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 . +* +* 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. +*/ + +#include "memory.h" +#include "utils.h" + +void *memcpy(void *dest, const void *src, u32 size) +{ + u8 *destc = (u8 *)dest; + const u8 *srcc = (const u8 *)src; + + for(u32 i = 0; i < size; i++) + destc[i] = srcc[i]; + + return dest; +} + +int memcmp(const void *buf1, const void *buf2, u32 size) +{ + const u8 *buf1c = (const u8 *)buf1; + const u8 *buf2c = (const u8 *)buf2; + + for(u32 i = 0; i < size; i++) + { + int cmp = buf1c[i] - buf2c[i]; + if(cmp) + return cmp; + } + + return 0; +} + +void *memset(void *dest, u32 value, u32 size) +{ + u8 *destc = (u8 *)dest; + + for(u32 i = 0; i < size; i++) destc[i] = (u8)value; + + return dest; +} + +void *memset32(void *dest, u32 value, u32 size) +{ + u32 *dest32 = (u32 *)dest; + + for(u32 i = 0; i < size/4; i++) dest32[i] = value; + + return dest; +} + +//Boyer-Moore Horspool algorithm, adapted from http://www-igm.univ-mlv.fr/~lecroq/string/node18.html#SECTION00180 +u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSize) +{ + const u8 *patternc = (const u8 *)pattern; + u32 table[256]; + + //Preprocessing + for(u32 i = 0; i < 256; i++) + table[i] = patternSize; + for(u32 i = 0; i < patternSize - 1; i++) + table[patternc[i]] = patternSize - i - 1; + + //Searching + u32 j = 0; + while(j <= size - patternSize) + { + u8 c = startPos[j + patternSize - 1]; + if(patternc[patternSize - 1] == c && memcmp(pattern, startPos + j, patternSize - 1) == 0) + return startPos + j; + j += table[c]; + } + + return NULL; +} + +char *strcpy(char *dest, const char *src) +{ + u32 i; + for(i = 0; src[i] != 0; i++) + dest[i] = src[i]; + + dest[i] = 0; + + return dest; +} + +char *strncpy(char *dest, const char *src, u32 size) +{ + u32 i; + for(i = 0; i < size && src[i] != 0; i++) + dest[i] = src[i]; + + for(; i < size; i++) + dest[i] = 0; + + return dest; +} + +s32 strnlen(const char *string, s32 maxlen) +{ + s32 size; + for(size = 0; *string && size < maxlen; string++, size++); + + return size; +} + +s32 strlen(const char *string) +{ + char *stringEnd = (char *)string; + while(*stringEnd) stringEnd++; + + return stringEnd - string; +} + +s32 strcmp(const char *str1, const char *str2) +{ + while(*str1 && (*str1 == *str2)) + { + str1++; + str2++; + } + + return *str1 - *str2; +} + +s32 strncmp(const char *str1, const char *str2, u32 size) +{ + while(size && *str1 && (*str1 == *str2)) + { + str1++; + str2++; + size--; + } + if (!size) + return 0; + else + return *str1 - *str2; +} + +void hexItoa(u64 number, char *out, u32 digits, bool uppercase) +{ + const char hexDigits[] = "0123456789ABCDEF"; + const char hexDigitsLowercase[] = "0123456789abcdef"; + u32 i = 0; + + while(number > 0) + { + out[digits - 1 - i++] = uppercase ? hexDigits[number & 0xF] : hexDigitsLowercase[number & 0xF]; + number >>= 4; + } + + while(i < digits) out[digits - 1 - i++] = '0'; +} diff --git a/sysmodules/rosalina/kernel_extension/source/start.s b/sysmodules/rosalina/kernel_extension/source/start.s new file mode 100644 index 000000000..8c7aedf91 --- /dev/null +++ b/sysmodules/rosalina/kernel_extension/source/start.s @@ -0,0 +1,55 @@ +@ 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 . +@ +@ 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. + +.section .text.start +.balign 4 +.global _start +_start: + push {r4, lr} + + mrc p15, 0, r4, c0, c0, 5 @ CPUID register + and r4, #3 + cmp r4, #1 + beq _core1_only + + _waitLoop: + wfe + ldr r0, =_setupFinished + ldr r0, [r0] + cmp r0, #0 + beq _waitLoop + b end + + _core1_only: + bl main + ldr r0, =_setupFinished + str r4, [r0] + sev + + end: + pop {r4, pc} + +.bss +.balign 4 +_setupFinished: .word 0 diff --git a/sysmodules/rosalina/kernel_extension/source/svc.c b/sysmodules/rosalina/kernel_extension/source/svc.c new file mode 100644 index 000000000..835ed7186 --- /dev/null +++ b/sysmodules/rosalina/kernel_extension/source/svc.c @@ -0,0 +1,155 @@ +/* +* 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 . +* +* 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. +*/ + +#include "svc.h" +#include "svc/ControlMemory.h" +#include "svc/GetProcessInfo.h" +#include "svc/GetThreadInfo.h" +#include "svc/GetSystemInfo.h" +#include "svc/GetCFWInfo.h" +#include "svc/ConnectToPort.h" +#include "svc/SendSyncRequest.h" +#include "svc/Break.h" +#include "svc/SetGpuProt.h" +#include "svc/SetWifiEnabled.h" +#include "svc/Backdoor.h" +#include "svc/KernelSetState.h" +#include "svc/MapProcessMemoryEx.h" +#include "svc/UnmapProcessMemoryEx.h" +#include "svc/ControlService.h" +#include "svc/CopyHandle.h" +#include "svc/TranslateHandle.h" + +void *officialSVCs[0x7E] = {NULL}; + +static inline void yieldDuringRosalinaMenu(void) +{ + KProcess *currentProcess = currentCoreContext->objectContext.currentProcess; + + u64 titleId = codeSetOfProcess(currentProcess)->titleId; + u32 highTitleId = (u32)(titleId >> 32), lowTitleId = (u32)titleId; + while((rosalinaState & 1) && idOfProcess(currentProcess) >= 6 && + (highTitleId != 0x00040130 || (highTitleId == 0x00040130 && (lowTitleId == 0x1A02 || lowTitleId == 0x1C02)))) + SleepThread(25 * 1000 * 1000LL); +} + +void signalSvcEntry(u8 *pageEnd) +{ + u32 svcId = (u32) *(u8 *)(pageEnd - 0xB5); + KProcess *currentProcess = currentCoreContext->objectContext.currentProcess; + + yieldDuringRosalinaMenu(); + + if(svcId == 0xFE) + svcId = *(u32 *)(pageEnd - 0x110 + 8 * 4); // r12 ; note: max theortical SVC atm: 0x3FFFFFFF. We don't support catching svcIds >= 0x100 atm either + + // Since DBGEVENT_SYSCALL_ENTRY is non blocking, we'll cheat using EXCEVENT_UNDEFINED_SYSCALL (debug->svcId is fortunately an u16!) + if(debugOfProcess(currentProcess) != NULL && shouldSignalSyscallDebugEvent(currentProcess, svcId)) + SignalDebugEvent(DBGEVENT_OUTPUT_STRING, 0xFFFFFFFE, svcId); +} + +void signalSvcReturn(u8 *pageEnd) +{ + u32 svcId = (u32) *(u8 *)(pageEnd - 0xB5); + KProcess *currentProcess = currentCoreContext->objectContext.currentProcess; + + yieldDuringRosalinaMenu(); + + if(svcId == 0xFE) + svcId = *(u32 *)(pageEnd - 0x110 + 8 * 4); // r12 ; note: max theortical SVC atm: 0x1FFFFFFF. We don't support catching svcIds >= 0x100 atm either + + // Since DBGEVENT_SYSCALL_RETURN is non blocking, we'll cheat using EXCEVENT_UNDEFINED_SYSCALL (debug->svcId is fortunately an u16!) + if(debugOfProcess(currentProcess) != NULL && shouldSignalSyscallDebugEvent(currentProcess, svcId)) + SignalDebugEvent(DBGEVENT_OUTPUT_STRING, 0xFFFFFFFF, svcId); +} + +void *svcHook(u8 *pageEnd) +{ + KProcess *currentProcess = currentCoreContext->objectContext.currentProcess; + + u32 svcId = *(u8 *)(pageEnd - 0xB5); + if(svcId == 0xFE) + svcId = *(u32 *)(pageEnd - 0x110 + 8 * 4); // r12 ; note: max theortical SVC atm: 0x3FFFFFFF. We don't support catching svcIds >= 0x100 atm either + switch(svcId) + { + case 0x01: + return ControlMemoryHookWrapper; + case 0x2A: + return GetSystemInfoHookWrapper; + case 0x2B: + return GetProcessInfoHookWrapper; + case 0x2C: + return GetThreadInfoHookWrapper; + case 0x2D: + return ConnectToPortHookWrapper; + case 0x2E: + return GetCFWInfo; // DEPRECATED + case 0x32: + return SendSyncRequestHook; + case 0x3C: + return (debugOfProcess(currentProcess) != NULL) ? officialSVCs[0x3C] : (void *)Break; + case 0x59: + return SetGpuProt; + case 0x5A: + return SetWifiEnabled; + case 0x7B: + return Backdoor; + case 0x7C: + return KernelSetStateHook; + + + case 0x80: + return CustomBackdoor; + + case 0x90: + return convertVAToPA; + case 0x91: + return flushDataCacheRange; + case 0x92: + return flushEntireDataCache; + case 0x93: + return invalidateInstructionCacheRange; + case 0x94: + return invalidateEntireInstructionCache; + + case 0xA0: + return MapProcessMemoryEx; + case 0xA1: + return UnmapProcessMemoryEx; + case 0xA2: + return ControlMemoryEx; + + case 0xB0: + return ControlService; + case 0xB1: + return CopyHandleWrapper; + case 0xB2: + return TranslateHandleWrapper; + + default: + return (svcId <= 0x7D) ? officialSVCs[svcId] : NULL; + } +} diff --git a/sysmodules/rosalina/kernel_extension/source/svc/Backdoor.s b/sysmodules/rosalina/kernel_extension/source/svc/Backdoor.s new file mode 100644 index 000000000..5228f0d4f --- /dev/null +++ b/sysmodules/rosalina/kernel_extension/source/svc/Backdoor.s @@ -0,0 +1,43 @@ +@ 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 . +@ +@ 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. + +.text +.arm +.balign 4 + +.global Backdoor +.type Backdoor, %function +Backdoor: + @ Nintendo's code + bic r1, sp, #0xff + orr r1, r1, #0xf00 + add r1, r1, #0x28 @ get user stack. + + ldr r2, [r1] + stmdb r2!, {sp, lr} + mov sp, r2 @ sp_svc = sp_usr. You'll get nice crashes if an interrupt or context switch occurs during svcBackdoor + blx r0 + pop {r0, r1} + mov sp, r0 + bx r1 diff --git a/exceptions/arm11/source/start.s b/sysmodules/rosalina/kernel_extension/source/svc/Break.s similarity index 50% rename from exceptions/arm11/source/start.s rename to sysmodules/rosalina/kernel_extension/source/svc/Break.s index 3d320067e..781b8d06a 100644 --- a/exceptions/arm11/source/start.s +++ b/sysmodules/rosalina/kernel_extension/source/svc/Break.s @@ -1,5 +1,5 @@ @ This file is part of Luma3DS -@ Copyright (C) 2016 Aurora Wright, TuxSH +@ 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 @@ -14,18 +14,22 @@ @ You should have received a copy of the GNU General Public License @ along with this program. If not, see . @ -@ Additional Terms 7.b of GPLv3 applies 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. +@ 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. -.section .text.start -.align 4 -.global _start -_start: - add pc, r0, #(handlers - .) @ Dummy instruction to prevent compiler optimizations +.text +.arm +.balign 4 -handlers: - .word FIQHandler - .word undefinedInstructionHandler - .word prefetchAbortHandler - .word dataAbortHandler +.global Break +.type Break, %function +Break: + bic r0, sp, #0xf00 + bic r0, #0xff + add r0, #0x1000 @ get page context top + bkpt 0xffff diff --git a/sysmodules/rosalina/kernel_extension/source/svc/ConnectToPort.c b/sysmodules/rosalina/kernel_extension/source/svc/ConnectToPort.c new file mode 100644 index 000000000..9575cf6d0 --- /dev/null +++ b/sysmodules/rosalina/kernel_extension/source/svc/ConnectToPort.c @@ -0,0 +1,56 @@ +/* +* 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 . +* +* 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. +*/ + +#include "svc/ConnectToPort.h" +#include "memory.h" +#include "ipc.h" + +Result ConnectToPortHook(Handle *out, const char *name) +{ + char portName[12] = {0}; + Result res = 0; + if(name != NULL) + { + s32 nb = usrToKernelStrncpy(portName, name, 12); + if(nb < 0) + return 0xD9001814; + else if(nb == 12 && portName[11] != 0) + return 0xE0E0181E; + } + res = ConnectToPort(out, name); + if(res != 0) + return res; + + KProcessHandleTable *handleTable = handleTableOfProcess(currentCoreContext->objectContext.currentProcess); + KClientSession *clientSession = (KClientSession *)KProcessHandleTable__ToKAutoObject(handleTable, *out); + if(clientSession != NULL) + { + SessionInfo_Add(clientSession->parentSession, portName); + clientSession->syncObject.autoObject.vtable->DecrementReferenceCount(&clientSession->syncObject.autoObject); + } + + return res; +} diff --git a/sysmodules/rosalina/kernel_extension/source/svc/ControlMemory.c b/sysmodules/rosalina/kernel_extension/source/svc/ControlMemory.c new file mode 100644 index 000000000..ab7626de7 --- /dev/null +++ b/sysmodules/rosalina/kernel_extension/source/svc/ControlMemory.c @@ -0,0 +1,34 @@ +/* +* 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 . +* +* 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. +*/ + +#include "svc/ControlMemory.h" + +Result ControlMemoryHook(u32 *addrOut, u32 addr0, u32 addr1, u32 size, MemOp op, MemPerm perm) +{ + KProcess *currentProcess = currentCoreContext->objectContext.currentProcess; + return ControlMemory(addrOut, addr0, addr1, size, op, perm, idOfProcess(currentProcess) == 1); +} + diff --git a/sysmodules/rosalina/kernel_extension/source/svc/ControlService.c b/sysmodules/rosalina/kernel_extension/source/svc/ControlService.c new file mode 100644 index 000000000..1eb46cddc --- /dev/null +++ b/sysmodules/rosalina/kernel_extension/source/svc/ControlService.c @@ -0,0 +1,108 @@ +/* +* 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 . +* +* 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. +*/ + +#include "svc/ControlService.h" +#include "memory.h" +#include "ipc.h" + +Result ControlService(ServiceOp op, u32 varg1, u32 varg2) +{ + Result res = 0; + KProcessHandleTable *handleTable = handleTableOfProcess(currentCoreContext->objectContext.currentProcess); + + switch(op) + { + case SERVICEOP_GET_NAME: + { + KSession *session = NULL; + SessionInfo *info = NULL; + KAutoObject *obj = KProcessHandleTable__ToKAutoObject(handleTable, (Handle)varg2); + if(obj == NULL) + return 0xD8E007F7; // invalid handle + else if(kernelVersion >= SYSTEM_VERSION(2, 46, 0)) + { + KClassToken tok; + obj->vtable->GetClassToken(&tok, obj); + if(tok.flags == 0x95) + session = ((KServerSession *)obj)->parentSession; + else if(tok.flags == 0xA5) + session = ((KClientSession *)obj)->parentSession; + } + else + { // not the exact same tests but it should work + if(strcmp(obj->vtable->GetClassName(obj), "KServerSession") == 0) + session = ((KServerSession *)obj)->parentSession; + else if(strcmp(obj->vtable->GetClassName(obj), "KClientSession") == 0) + session = ((KClientSession *)obj)->parentSession; + } + + if(session != NULL) + info = SessionInfo_Lookup(session); + + if(info == NULL) + res = 0xD8E007F7; + else + { + // names are limited to 11 characters (for ports) + // kernelToUsrStrncpy doesn't clear trailing bytes + char name[12] = { 0 }; + strncpy(name, info->name, 12); + res = kernelToUsrMemcpy8((void *)varg1, name, strlen(name) + 1) ? 0 : 0xE0E01BF5; + } + + obj->vtable->DecrementReferenceCount(obj); + return res; + } + + case SERVICEOP_STEAL_CLIENT_SESSION: + { + char name[12] = { 0 }; + SessionInfo *info = NULL; + if(name != NULL) + { + s32 nb = usrToKernelStrncpy(name, (const char *)varg2, 12); + if(nb < 0) + return 0xD9001814; + else if(nb == 12 && name[11] != 0) + return 0xE0E0181E; + } + + info = SessionInfo_FindFirst(name); + + if(info == NULL) + return 0x9401BFE; // timeout (the wanted service is likely not initalized) + else + { + Handle out; + res = createHandleForThisProcess(&out, &info->session->clientSession.syncObject.autoObject); + return (res != 0) ? res : (kernelToUsrMemcpy32((u32 *)varg1, (u32 *)&out, 4) ? 0 : (Result)0xE0E01BF5); + } + } + + default: + return 0xF8C007F4; + } +} diff --git a/sysmodules/rosalina/kernel_extension/source/svc/CopyHandle.c b/sysmodules/rosalina/kernel_extension/source/svc/CopyHandle.c new file mode 100644 index 000000000..25b08da1b --- /dev/null +++ b/sysmodules/rosalina/kernel_extension/source/svc/CopyHandle.c @@ -0,0 +1,76 @@ +/* +* 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 . +* +* 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. +*/ + +#include "svc/CopyHandle.h" +#include "memory.h" + +Result CopyHandle(Handle *outHandle, Handle outProcessHandle, Handle inHandle, Handle inProcessHandle) +{ + KProcessHandleTable *handleTable = handleTableOfProcess(currentCoreContext->objectContext.currentProcess); + KProcess *inProcess, *outProcess; + Result res; + + if(inProcessHandle == CUR_PROCESS_HANDLE) + { + inProcess = currentCoreContext->objectContext.currentProcess; + KAutoObject__AddReference((KAutoObject *)inProcess); + } + else + inProcess = KProcessHandleTable__ToKProcess(handleTable, inProcessHandle); + + if(inProcess == NULL) + return 0xD8E007F7; // invalid handle + + if(outProcessHandle == CUR_PROCESS_HANDLE) + { + outProcess = currentCoreContext->objectContext.currentProcess; + KAutoObject__AddReference((KAutoObject *)outProcess); + } + else + outProcess = KProcessHandleTable__ToKProcess(handleTable, outProcessHandle); + + if(outProcess == NULL) + { + ((KAutoObject *)inProcess)->vtable->DecrementReferenceCount((KAutoObject *)inProcess); + return 0xD8E007F7; // invalid handle + } + + KAutoObject *obj = KProcessHandleTable__ToKAutoObject(handleTableOfProcess(inProcess), inHandle); + if(obj == NULL) + { + ((KAutoObject *)inProcess)->vtable->DecrementReferenceCount((KAutoObject *)inProcess); + ((KAutoObject *)outProcess)->vtable->DecrementReferenceCount((KAutoObject *)outProcess); + return 0xD8E007F7; // invalid handle + } + + res = createHandleForProcess(outHandle, outProcess, obj); + + obj->vtable->DecrementReferenceCount(obj); + ((KAutoObject *)inProcess)->vtable->DecrementReferenceCount((KAutoObject *)inProcess); + ((KAutoObject *)outProcess)->vtable->DecrementReferenceCount((KAutoObject *)outProcess); + + return res; +} diff --git a/sysmodules/rosalina/kernel_extension/source/svc/GetCFWInfo.c b/sysmodules/rosalina/kernel_extension/source/svc/GetCFWInfo.c new file mode 100644 index 000000000..a7bc7edba --- /dev/null +++ b/sysmodules/rosalina/kernel_extension/source/svc/GetCFWInfo.c @@ -0,0 +1,33 @@ +/* +* 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 . +* +* 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. +*/ + +#include "svc/GetCFWInfo.h" + +// DEPRECATED +Result GetCFWInfo(CfwInfo *out) +{ + return kernelToUsrMemcpy8(out, &cfwInfo, 16) ? 0 : 0xE0E01BF5; +} diff --git a/sysmodules/rosalina/kernel_extension/source/svc/GetProcessInfo.c b/sysmodules/rosalina/kernel_extension/source/svc/GetProcessInfo.c new file mode 100644 index 000000000..ecb4835a6 --- /dev/null +++ b/sysmodules/rosalina/kernel_extension/source/svc/GetProcessInfo.c @@ -0,0 +1,94 @@ +/* +* 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 . +* +* 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. +*/ + +#include "svc/GetProcessInfo.h" +#include "memory.h" + +Result GetProcessInfoHook(s64 *out, Handle processHandle, u32 type) +{ + Result res = 0; + + if(type >= 0x10000) + { + KProcessHandleTable *handleTable = handleTableOfProcess(currentCoreContext->objectContext.currentProcess); + KProcess *process; + if(processHandle == CUR_PROCESS_HANDLE) + { + process = currentCoreContext->objectContext.currentProcess; + KAutoObject__AddReference((KAutoObject *)process); + } + else + process = KProcessHandleTable__ToKProcess(handleTable, processHandle); + + if(process == NULL) + return 0xD8E007F7; // invalid handle + + switch(type) + { + case 0x10000: + memcpy(out, codeSetOfProcess(process)->processName, 8); + break; + case 0x10001: + *(u64 *)out = codeSetOfProcess(process)->titleId; + break; + case 0x10002: + *out = codeSetOfProcess(process)->nbTextPages << 12; + break; + case 0x10003: + *out = codeSetOfProcess(process)->nbRodataPages << 12; + break; + case 0x10004: + *out = codeSetOfProcess(process)->nbRwPages << 12; + break; + case 0x10005: + *out = (s64)(u64)(u32)codeSetOfProcess(process)->textSection.section.loadAddress; + break; + case 0x10006: + *out = (s64)(u64)(u32)codeSetOfProcess(process)->rodataSection.section.loadAddress; + break; + case 0x10007: + *out = (s64)(u64)(u32)codeSetOfProcess(process)->dataSection.section.loadAddress; + break; + case 0x10008: + *out = (isN3DS ? hwInfoOfProcess(process)->N3DS.translationTableBase : + (kernelVersion >= SYSTEM_VERSION(2, 44, 6) + ? hwInfoOfProcess(process)->O3DS8x.translationTableBase + : hwInfoOfProcess(process)->O3DSPre8x.translationTableBase) + ) & ~((1 << (14 - TTBCR)) - 1); + break; + default: + res = 0xD8E007ED; // invalid enum value + break; + } + + ((KAutoObject *)process)->vtable->DecrementReferenceCount((KAutoObject *)process); + } + + else + res = GetProcessInfo(out, processHandle, type); + + return res; +} diff --git a/sysmodules/rosalina/kernel_extension/source/svc/GetSystemInfo.c b/sysmodules/rosalina/kernel_extension/source/svc/GetSystemInfo.c new file mode 100644 index 000000000..a090bb5ac --- /dev/null +++ b/sysmodules/rosalina/kernel_extension/source/svc/GetSystemInfo.c @@ -0,0 +1,123 @@ +/* +* 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 . +* +* 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. +*/ + +#include "svc/GetSystemInfo.h" +#include "utils.h" +#include "ipc.h" +#include "synchronization.h" + +Result GetSystemInfoHook(s64 *out, s32 type, s32 param) +{ + Result res = 0; + + switch(type) + { + case 0x10000: + { + switch(param) + { + case 0: + *out = SYSTEM_VERSION(cfwInfo.versionMajor, cfwInfo.versionMinor, cfwInfo.versionBuild); + break; + case 1: + *out = cfwInfo.commitHash; + break; + case 2: + *out = cfwInfo.config; + break; + case 3: // isRelease + *out = cfwInfo.flags & 1; + break; + case 4: // isN3DS + *out = (cfwInfo.flags >> 4) & 1; + break; + case 5: // isSafeMode + *out = (cfwInfo.flags >> 5) & 1; + break; + case 6: // isSdMode + *out = (cfwInfo.flags >> 6) & 1; + break; + default: + res = 0xF8C007F4; // not implemented + break; + } + break; + } + + case 0x10001: // N3DS-related info + { + if(isN3DS) + { + switch(param) + { + case 0: // current clock rate + *out = (((CFG11_MPCORE_CLKCNT >> 1) & 3) + 1) * 268; + break; + case 1: // higher clock rate + *out = (((CFG11_MPCORE_CFG >> 2) & 1) + 2) * 268; + break; + case 2: // L2C enabled status + *out = L2C_CTRL & 1; + break; + default: + res = 0xF8C007F4; + break; + } + } + else + res = 0xF8C007F4; + + break; + } + + case 0x10002: // MMU config (cached values from booting) + { + switch(param) + { + case 0: + *out = TTBCR; + break; + + default: + { + if((u32)param <= getNumberOfCores()) + *out = L1MMUTableAddrs[param - 1]; + else + res = 0xF8C007F4; + + break; + } + } + + break; + } + default: + GetSystemInfo(out, type, param); + break; + } + + return res; +} diff --git a/sysmodules/rosalina/kernel_extension/source/svc/GetThreadInfo.c b/sysmodules/rosalina/kernel_extension/source/svc/GetThreadInfo.c new file mode 100644 index 000000000..267431ecf --- /dev/null +++ b/sysmodules/rosalina/kernel_extension/source/svc/GetThreadInfo.c @@ -0,0 +1,60 @@ +/* +* 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 . +* +* 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. +*/ + +#include "svc/GetThreadInfo.h" +#include "memory.h" + +Result GetThreadInfoHook(s64 *out, Handle threadHandle, u32 type) +{ + Result res = 0; + + if(type == 0x10000) // Get TLS + { + KProcessHandleTable *handleTable = handleTableOfProcess(currentCoreContext->objectContext.currentProcess); + KThread *thread; + + if(threadHandle == CUR_THREAD_HANDLE) + { + thread = currentCoreContext->objectContext.currentThread; + KAutoObject__AddReference(&thread->syncObject.autoObject); + } + else + thread = KProcessHandleTable__ToKThread(handleTable, threadHandle); + + if(thread == NULL) + return 0xD8E007F7; // invalid handle + + *out = (s64)(u64)(u32)thread->threadLocalStorage; + + KAutoObject *obj = (KAutoObject *)thread; + obj->vtable->DecrementReferenceCount(obj); + } + + else + res = GetThreadInfo(out, threadHandle, type); + + return res; +} diff --git a/sysmodules/rosalina/kernel_extension/source/svc/KernelSetState.c b/sysmodules/rosalina/kernel_extension/source/svc/KernelSetState.c new file mode 100644 index 000000000..bd228bcbf --- /dev/null +++ b/sysmodules/rosalina/kernel_extension/source/svc/KernelSetState.c @@ -0,0 +1,149 @@ +/* +* 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 . +* +* 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. +*/ + +#include "svc/KernelSetState.h" +#include "synchronization.h" +#include "ipc.h" +#include "memory.h" + +#define MAX_DEBUG 3 + +static u32 nbEnabled = 0; +static u32 maskedPids[MAX_DEBUG]; +static u32 masks[MAX_DEBUG][8] = {0}; + +bool shouldSignalSyscallDebugEvent(KProcess *process, u8 svcId) +{ + u32 pid = idOfProcess(process); + u32 id; + for(id = 0; id < nbEnabled && maskedPids[id] != pid; id++); + if(id == MAX_DEBUG) + return false; + else + return ((masks[id][svcId / 32] >> (31 - (svcId % 32))) & 1) != 0; +} + +Result SetSyscallDebugEventMask(u32 pid, bool enable, const u32 *mask) +{ + static KRecursiveLock syscallDebugEventMaskLock = { NULL }; + + u32 tmpMask[8]; + if(enable && nbEnabled == MAX_DEBUG) + return 0xC86018FF; // Out of resource (255) + + if(enable && !usrToKernelMemcpy8(&tmpMask, mask, 32)) + return 0xE0E01BF5; + + KRecursiveLock__Lock(criticalSectionLock); + KRecursiveLock__Lock(&syscallDebugEventMaskLock); + + if(enable) + { + maskedPids[nbEnabled] = pid; + memcpy(&masks[nbEnabled++], tmpMask, 32); + } + else + { + u32 id; + for(id = 0; id < nbEnabled && maskedPids[id] != pid; id++); + if(id == nbEnabled) + { + KRecursiveLock__Unlock(&syscallDebugEventMaskLock); + KRecursiveLock__Unlock(criticalSectionLock); + return 0xE0E01BFD; // out of range (it's not fully technically correct but meh) + } + + for(u32 i = id; i < nbEnabled - 1; i++) + { + maskedPids[i] = maskedPids[i + 1]; + memcpy(&masks[i], &masks[i + 1], 32); + } + maskedPids[--nbEnabled] = 0; + memset(&masks[nbEnabled], 0, 32); + } + + KRecursiveLock__Unlock(&syscallDebugEventMaskLock); + KRecursiveLock__Unlock(criticalSectionLock); + return 0; +} + +Result KernelSetStateHook(u32 type, u32 varg1, u32 varg2, u32 varg3) +{ + Result res = 0; + + switch(type) + { + case 0x10000: + { + do + { + __ldrex((s32 *)&rosalinaState); + } + while(__strex((s32 *)&rosalinaState, (s32)(rosalinaState ^ varg1))); + + if(rosalinaState & 2) + hasStartedRosalinaNetworkFuncsOnce = true; + + break; + } + case 0x10001: + { + KRecursiveLock__Lock(criticalSectionLock); + KRecursiveLock__Lock(&processLangemuLock); + + u32 i; + for(i = 0; i < 0x40 && processLangemuAttributes[i].titleId != 0ULL; i++); + if(i < 0x40) + { + processLangemuAttributes[i].titleId = ((u64)varg3 << 32) | (u32)varg2; + processLangemuAttributes[i].state = (u8)(varg1 >> 24); + processLangemuAttributes[i].country = (u8)(varg1 >> 16); + processLangemuAttributes[i].language = (u8)(varg1 >> 8); + processLangemuAttributes[i].region = (u8)(varg1 >> 4); + processLangemuAttributes[i].mask = (u8)(varg1 & 0xf); + } + else + res = 0xD8609013; + + KRecursiveLock__Unlock(&processLangemuLock); + KRecursiveLock__Unlock(criticalSectionLock); + break; + } + case 0x10002: + { + res = SetSyscallDebugEventMask(varg1, (bool)varg2, (const u32 *)varg3); + break; + } + + default: + { + res = KernelSetState(type, varg1, varg2, varg3); + break; + } + } + + return res; +} diff --git a/sysmodules/rosalina/kernel_extension/source/svc/MapProcessMemoryEx.c b/sysmodules/rosalina/kernel_extension/source/svc/MapProcessMemoryEx.c new file mode 100644 index 000000000..abc5558ec --- /dev/null +++ b/sysmodules/rosalina/kernel_extension/source/svc/MapProcessMemoryEx.c @@ -0,0 +1,44 @@ +/* +* 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 . +* +* 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. +*/ + +#include "svc/MapProcessMemoryEx.h" + +Result MapProcessMemoryEx(Handle processHandle, void *dst, void *src, u32 size) +{ + KProcessHandleTable *handleTable = handleTableOfProcess(currentCoreContext->objectContext.currentProcess); + KProcessHwInfo *currentHwInfo = hwInfoOfProcess(currentCoreContext->objectContext.currentProcess); + KProcess *process = KProcessHandleTable__ToKProcess(handleTable, processHandle); + + if(process == NULL) + return 0xD8E007F7; + + Result res = KProcessHwInfo__MapProcessMemory(currentHwInfo, hwInfoOfProcess(process), dst, src, size >> 12); + + KAutoObject *obj = (KAutoObject *)process; + obj->vtable->DecrementReferenceCount(obj); + + return res; +} diff --git a/sysmodules/rosalina/kernel_extension/source/svc/SendSyncRequest.c b/sysmodules/rosalina/kernel_extension/source/svc/SendSyncRequest.c new file mode 100644 index 000000000..a70c8aa26 --- /dev/null +++ b/sysmodules/rosalina/kernel_extension/source/svc/SendSyncRequest.c @@ -0,0 +1,237 @@ +/* +* 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 . +* +* 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. +*/ + +#include "svc/SendSyncRequest.h" +#include "memory.h" +#include "ipc.h" + +Result SendSyncRequestHook(Handle handle) +{ + KProcessHandleTable *handleTable = handleTableOfProcess(currentCoreContext->objectContext.currentProcess); + KClientSession *clientSession = (KClientSession *)KProcessHandleTable__ToKAutoObject(handleTable, handle); + + u32 *cmdbuf = (u32 *)((u8 *)currentCoreContext->objectContext.currentThread->threadLocalStorage + 0x80); + bool skip = false; + Result res = 0; + + bool isValidClientSession = false; + if(clientSession != NULL && kernelVersion >= SYSTEM_VERSION(2, 46, 0)) + { + KClassToken tok; + clientSession->syncObject.autoObject.vtable->GetClassToken(&tok, &clientSession->syncObject.autoObject); + isValidClientSession = tok.flags == 0xA5; + } + else if(clientSession != NULL) // not the exact same test but it should work + isValidClientSession = strcmp(clientSession->syncObject.autoObject.vtable->GetClassName(&clientSession->syncObject.autoObject), "KClientSession"); + + if(isValidClientSession) + { + switch (cmdbuf[0]) + { + case 0x10042: + { + SessionInfo *info = SessionInfo_Lookup(clientSession->parentSession); + if(info != NULL && strcmp(info->name, "srv:pm") == 0) + { + res = doPublishToProcessHook(handle, cmdbuf); + skip = true; + } + else if(info != NULL && strcmp(info->name, "ndm:u") == 0 && hasStartedRosalinaNetworkFuncsOnce) + { + cmdbuf[0] = 0x10040; + cmdbuf[1] = 0; + skip = true; + } + + break; + } + + case 0x10082: + { + SessionInfo *info = SessionInfo_Lookup(clientSession->parentSession); + if(info != NULL && (strcmp(info->name, "cfg:u") == 0 || strcmp(info->name, "cfg:s") == 0 || strcmp(info->name, "cfg:i") == 0)) // GetConfigInfoBlk2 + skip = doLangEmu(&res, handle, cmdbuf); + + break; + } + + case 0x10800: + { + SessionInfo *info = SessionInfo_Lookup(clientSession->parentSession); + if(info != NULL && strcmp(info->name, "err:f") == 0) // Throw + skip = doErrfThrowHook(cmdbuf); + + break; + } + + case 0x20000: + { + SessionInfo *info = SessionInfo_Lookup(clientSession->parentSession); + if(info != NULL && (strcmp(info->name, "cfg:u") == 0 || strcmp(info->name, "cfg:s") == 0 || strcmp(info->name, "cfg:i") == 0)) // SecureInfoGetRegion + skip = doLangEmu(&res, handle, cmdbuf); + + break; + } + + case 0x20002: + { + SessionInfo *info = SessionInfo_Lookup(clientSession->parentSession); + if(info != NULL && strcmp(info->name, "ndm:u") == 0 && hasStartedRosalinaNetworkFuncsOnce) + { + cmdbuf[0] = 0x20040; + cmdbuf[1] = 0; + skip = true; + } + + break; + } + + case 0x50100: + { + SessionInfo *info = SessionInfo_Lookup(clientSession->parentSession); + if(info != NULL && strcmp(info->name, "srv:") == 0) + { + char name[9] = { 0 }; + memcpy(name, cmdbuf + 1, 8); + + skip = true; + res = SendSyncRequest(handle); + if(res == 0) + { + KClientSession *outClientSession; + + outClientSession = (KClientSession *)KProcessHandleTable__ToKAutoObject(handleTable, (Handle)cmdbuf[3]); + if(outClientSession != NULL) + { + SessionInfo_Add(outClientSession->parentSession, name); + outClientSession->syncObject.autoObject.vtable->DecrementReferenceCount(&outClientSession->syncObject.autoObject); + } + } + } + + break; + } + + case 0x80040: + { + if(!hasStartedRosalinaNetworkFuncsOnce) + break; + SessionInfo *info = SessionInfo_Lookup(clientSession->parentSession); + skip = info != NULL && strcmp(info->name, "ndm:u") == 0; // SuspendScheduler + if(skip) + cmdbuf[1] = 0; + break; + } + + case 0x90000: + { + if(!hasStartedRosalinaNetworkFuncsOnce) + break; + SessionInfo *info = SessionInfo_Lookup(clientSession->parentSession); + if(info != NULL && strcmp(info->name, "ndm:u") == 0) // ResumeScheduler + { + cmdbuf[0] = 0x90040; + cmdbuf[1] = 0; + skip = true; + } + break; + } + + case 0x4010042: + { + SessionInfo *info = SessionInfo_Lookup(clientSession->parentSession); + if(info != NULL && strcmp(info->name, "srv:pm") == 0) + { + res = doPublishToProcessHook(handle, cmdbuf); + skip = true; + } + + break; + } + + case 0x4010082: + { + SessionInfo *info = SessionInfo_Lookup(clientSession->parentSession); + if(info != NULL && (strcmp(info->name, "cfg:s") == 0 || strcmp(info->name, "cfg:i") == 0)) // GetConfigInfoBlk4 + skip = doLangEmu(&res, handle, cmdbuf); + + break; + } + + case 0x4020082: + { + SessionInfo *info = SessionInfo_Lookup(clientSession->parentSession); + if(info != NULL && (strcmp(info->name, "cfg:s") == 0 || strcmp(info->name, "cfg:i") == 0)) // GetConfigInfoBlk8 + skip = doLangEmu(&res, handle, cmdbuf); + + break; + } + + case 0x8010082: + { + SessionInfo *info = SessionInfo_Lookup(clientSession->parentSession); + if(info != NULL && (strcmp(info->name, "cfg:s") == 0 || strcmp(info->name, "cfg:i") == 0)) // GetConfigInfoBlk4 + skip = doLangEmu(&res, handle, cmdbuf); + + break; + } + + case 0x8020082: + { + SessionInfo *info = SessionInfo_Lookup(clientSession->parentSession); + if(info != NULL && strcmp(info->name, "cfg:i") == 0) // GetConfigInfoBlk8 + skip = doLangEmu(&res, handle, cmdbuf); + + break; + } + + case 0x4060000: + { + SessionInfo *info = SessionInfo_Lookup(clientSession->parentSession); // SecureInfoGetRegion + if(info != NULL && (strcmp(info->name, "cfg:s") == 0 || strcmp(info->name, "cfg:i") == 0)) + skip = doLangEmu(&res, handle, cmdbuf); + + break; + } + + case 0x8160000: + { + SessionInfo *info = SessionInfo_Lookup(clientSession->parentSession); // SecureInfoGetRegion + if(info != NULL && strcmp(info->name, "cfg:i") == 0) + skip = doLangEmu(&res, handle, cmdbuf); + + break; + } + } + } + + if(clientSession != NULL) + clientSession->syncObject.autoObject.vtable->DecrementReferenceCount(&clientSession->syncObject.autoObject); + + res = skip ? res : SendSyncRequest(handle); + + return res; +} diff --git a/sysmodules/rosalina/kernel_extension/source/svc/SetGpuProt.c b/sysmodules/rosalina/kernel_extension/source/svc/SetGpuProt.c new file mode 100644 index 000000000..17ef2f77a --- /dev/null +++ b/sysmodules/rosalina/kernel_extension/source/svc/SetGpuProt.c @@ -0,0 +1,32 @@ +/* +* 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 . +* +* 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. +*/ + +#include "svc/SetGpuProt.h" + +Result SetGpuProt(bool prot UNUSED) +{ + return 0; +} diff --git a/sysmodules/rosalina/kernel_extension/source/svc/SetWifiEnabled.c b/sysmodules/rosalina/kernel_extension/source/svc/SetWifiEnabled.c new file mode 100644 index 000000000..59596d715 --- /dev/null +++ b/sysmodules/rosalina/kernel_extension/source/svc/SetWifiEnabled.c @@ -0,0 +1,35 @@ +/* +* 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 . +* +* 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. +*/ + +#include "svc/SetWifiEnabled.h" + +void SetWifiEnabled(bool enable) +{ + if(enable) + CFG11_WIFICNT |= 1; + else + CFG11_WIFICNT &= ~1; +} diff --git a/sysmodules/rosalina/kernel_extension/source/svc/TranslateHandle.c b/sysmodules/rosalina/kernel_extension/source/svc/TranslateHandle.c new file mode 100644 index 000000000..62d703c2f --- /dev/null +++ b/sysmodules/rosalina/kernel_extension/source/svc/TranslateHandle.c @@ -0,0 +1,70 @@ +/* +* 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 . +* +* 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. +*/ + +#include "svc/TranslateHandle.h" +#include "memory.h" + +Result TranslateHandle(u32 *outKAddr, char *outClassName, Handle handle) +{ + KProcessHandleTable *handleTable = handleTableOfProcess(currentCoreContext->objectContext.currentProcess); + KAutoObject *obj; + Result res; + const char *name; + + if(handle == CUR_THREAD_HANDLE) + { + obj = (KAutoObject *)currentCoreContext->objectContext.currentProcess; + KAutoObject__AddReference(obj); + } + else if(handle == CUR_PROCESS_HANDLE) + { + obj = (KAutoObject *)currentCoreContext->objectContext.currentProcess; + KAutoObject__AddReference(obj); + } + else + obj = KProcessHandleTable__ToKAutoObject(handleTable, handle); + + if(obj == NULL) + return 0xD8E007F7; // invalid handle + + if(kernelVersion >= SYSTEM_VERSION(2, 46, 0)) + { + KClassToken tok; + obj->vtable->GetClassToken(&tok, obj); + name = tok.name; + } + else + name = obj->vtable->GetClassName(obj); + + if(name == NULL) // shouldn't happen + name = "KAutoObject"; + + *outKAddr = (u32)obj; + res = kernelToUsrMemcpy8(outClassName, name, strlen(name) + 1) ? 0 : 0xE0E01BF5; + + obj->vtable->DecrementReferenceCount(obj); + return res; +} diff --git a/sysmodules/rosalina/kernel_extension/source/svc/UnmapProcessMemoryEx.c b/sysmodules/rosalina/kernel_extension/source/svc/UnmapProcessMemoryEx.c new file mode 100644 index 000000000..780237cf9 --- /dev/null +++ b/sysmodules/rosalina/kernel_extension/source/svc/UnmapProcessMemoryEx.c @@ -0,0 +1,39 @@ +/* +* 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 . +* +* 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. +*/ + +#include "svc/MapProcessMemoryEx.h" + +Result UnmapProcessMemoryEx(Handle processHandle UNUSED, void *dst, u32 size) +{ + KProcessHwInfo *currentHwInfo = hwInfoOfProcess(currentCoreContext->objectContext.currentProcess); + + Result res = KProcessHwInfo__UnmapProcessMemory(currentHwInfo, dst, size >> 12); + + invalidateEntireInstructionCache(); + flushEntireDataCache(); + + return res; +} diff --git a/sysmodules/rosalina/kernel_extension/source/svc/wrappers.s b/sysmodules/rosalina/kernel_extension/source/svc/wrappers.s new file mode 100644 index 000000000..50367a246 --- /dev/null +++ b/sysmodules/rosalina/kernel_extension/source/svc/wrappers.s @@ -0,0 +1,85 @@ +@ 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 . +@ +@ 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. + +.text +.arm +.balign 4 + +.macro GEN_GETINFO_WRAPPER, name + .global Get\name\()InfoHookWrapper + .type Get\name\()InfoHookWrapper, %function + Get\name\()InfoHookWrapper: + push {r12, lr} + sub sp, #8 + mov r0, sp + bl Get\name\()InfoHook + pop {r1, r2, r12, pc} +.endm + +GEN_GETINFO_WRAPPER System +GEN_GETINFO_WRAPPER Process +GEN_GETINFO_WRAPPER Thread + +.macro GEN_OUT1_WRAPPER, name + .global \name\()Wrapper + .type \name\()Wrapper, %function + \name\()Wrapper: + push {lr} + sub sp, #4 + mov r0, sp + bl \name + pop {r1, pc} +.endm + +GEN_OUT1_WRAPPER ConnectToPortHook +GEN_OUT1_WRAPPER CopyHandle +GEN_OUT1_WRAPPER TranslateHandle + +.global ControlMemoryHookWrapper +.type ControlMemoryHookWrapper, %function +ControlMemoryHookWrapper: + push {lr} + sub sp, #12 + stmia sp, {r0, r4} + add r0, sp, #8 + bl ControlMemoryHook + ldr r1, [sp, #8] + add sp, #12 + pop {pc} + +.global ControlMemoryEx +.type ControlMemoryEx, %function +ControlMemoryEx: + push {lr} + sub sp, #8 + cmp r5, #0 + movne r5, #1 + push {r0, r4, r5} + add r0, sp, #12 + ldr r12, =ControlMemory + ldr r12, [r12] + blx r12 + ldr r1, [sp, #12] + add sp, #20 + pop {pc} diff --git a/sysmodules/rosalina/kernel_extension/source/svcHandler.s b/sysmodules/rosalina/kernel_extension/source/svcHandler.s new file mode 100644 index 000000000..b8b5a6998 --- /dev/null +++ b/sysmodules/rosalina/kernel_extension/source/svcHandler.s @@ -0,0 +1,127 @@ +@ 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 . +@ +@ 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. + +.text +.arm +.balign 4 + +.global svcHandler +.type svcHandler, %function +svcHandler: + srsdb sp!, #0x13 + stmfd sp, {r8-r11, sp, lr}^ + sub sp, #0x18 + mrs r9, spsr + ands r9, #0x20 + ldrneb r9, [lr, #-2] + ldreqb r9, [lr, #-4] + + mov lr, #0 @ do stuff as if the "allow debug" flag is always set + push {r0-r7, r12, lr} + mov r10, #1 + strb r9, [sp, #0x58+3] @ page end - 0xb8 + 3: svc being handled + strb r10, [sp, #0x58+1] @ page end - 0xb8 + 1: "allow debug" flag + + @ sp = page end - 0x110 + add r0, sp, #0x110 @ page end + bl svcHook + cpsid i + mov r8, r0 + ldmfd sp, {r0-r7, r12, lr} + cmp r8, #0 + beq _fallback @ invalid svc, or svc 0xff (stop point) + + _handled_svc: @ unused label, just here for formatting + push {r0-r12, lr} + add r0, sp, #0x148 + cpsie i + bl signalSvcEntry + cpsid i + pop {r0-r12, lr} + + cpsie i + blx r8 + cpsid i + + ldrb lr, [sp, #0x58+0] @ page end - 0xb8 + 0: scheduling flags + b _fallback_end + + _fallback: + mov r0, r9 + ldr r8, =svcFallbackHandler + ldr r8, [r8] + blx r8 + mov lr, #0 + + _fallback_end: + + ldr r8, [sp, #0x24] @ page_end - 0xec: saved lr (see above) : should reload regs + cmp r8, #0 + addeq sp, #0x24 + popne {r0-r7, r12} + add sp, #4 + + cmp r9, #0xff + beq _no_signal_return + + push {r0-r7, r12, lr} + add r0, sp, #0x110 @ page end + cpsie i + bl signalSvcReturn + cpsid i + pop {r0-r7, r12} + add sp, #4 + + _no_signal_return: + + mov r8, #0 + strb r8, [sp, #0x30+3] @ page_end - 0xb8 + 3: svc being handled + + _svc_finished: + + ldmfd sp, {r8-r11, sp, lr}^ + cmp lr, #0 + bne _postprocess_svc + + _svc_return: + add sp, #0x18 + rfefd sp! @ return to user mode + + _postprocess_svc: + mov lr, #0 + push {r0-r7, r12, lr} + + push {r0-r3} + ldr r0, =PostprocessSvc + ldr r0, [r0] + blx r0 + pop {r0-r3} + + ldrb lr, [sp, #0x58+0] @ page end - 0xb8 + 0: scheduling flags + ldr r8, [sp, #0x24] @ page_end - 0xec: saved lr (see above) : should reload regs + cmp r8, #0 + addeq sp, #0x24 + popne {r0-r7, r12} + add sp, #4 + b _svc_finished diff --git a/sysmodules/rosalina/kernel_extension/source/synchronization.c b/sysmodules/rosalina/kernel_extension/source/synchronization.c new file mode 100644 index 000000000..82b76870c --- /dev/null +++ b/sysmodules/rosalina/kernel_extension/source/synchronization.c @@ -0,0 +1,41 @@ +/* +* 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 . +* +* 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. +*/ + +#include "synchronization.h" +#include "utils.h" +#include "kernel.h" + +extern SGI0Handler_t SGI0Handler; + +void executeFunctionOnCores(SGI0Handler_t handler, u8 targetList, u8 targetListFilter) +{ + u32 coreID = getCurrentCoreID(); + SGI0Handler = handler; + + if(targetListFilter == 0 && (targetListFilter & (1 << coreID)) != 0) + __asm__ volatile("cpsie i"); // make sure interrupts aren't masked + MPCORE_GID_SGI = (targetListFilter << 24) | (targetList << 16) | 0; +} diff --git a/sysmodules/rosalina/kernel_extension/source/utils.s b/sysmodules/rosalina/kernel_extension/source/utils.s new file mode 100644 index 000000000..f5ea72a38 --- /dev/null +++ b/sysmodules/rosalina/kernel_extension/source/utils.s @@ -0,0 +1,139 @@ +@ 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 . +@ +@ 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. + +.text +.arm +.balign 4 + +.global convertVAToPA +.type convertVAToPA, %function +convertVAToPA: + mov r3, r1 + mov r1, #0xf00 + orr r1, #0xff + and r2, r0, r1 + bic r0, r1 + cmp r3, #1 + beq _convertVAToPA_write_check + _convertVAToPA_read_check: + mcr p15, 0, r0, c7, c8, 0 @ VA to PA translation with privileged read permission check + b _convertVAToPA_end_check + _convertVAToPA_write_check: + mcr p15, 0, r0, c7, c8, 1 @ VA to PA translation with privileged write permission check + _convertVAToPA_end_check: + mrc p15, 0, r0, c7, c4, 0 @ read PA register + tst r0, #1 @ failure bit + bic r0, r1 + addeq r0, r2 + movne r0, #0 + bx lr + +.global flushEntireDataCache +.type flushEntireDataCache, %function +flushEntireDataCache: + mvn r1, #0 @ this is translated to a full cache flush + ldr r12, =flushDataCacheRange + ldr r12, [r12] + bx r12 + +.global invalidateEntireInstructionCache +.type invalidateEntireInstructionCache, %function +invalidateEntireInstructionCache: + mvn r1, #0 @ this is translated to a full cache flush + ldr r12, =invalidateInstructionCacheRange + ldr r12, [r12] + bx r12 + +.global KObjectMutex__Acquire +.type KObjectMutex__Acquire, %function +KObjectMutex__Acquire: + ldr r1, =0xFFFF9000 @ current thread addr + + ldr r1, [r1] + ldrex r2, [r0] + cmp r2, #0 + strexeq r3, r1, [r0] @ store current thread + strexne r3, r2, [r0] @ stored thread != NULL, no change + cmpeq r3, #0 + bxeq lr + + ldr r12, =KObjectMutex__WaitAndAcquire + ldr r12, [r12] + bx r12 + +.global KObjectMutex__Release +.type KObjectMutex__Release, %function +KObjectMutex__Release: + mov r1, #0 + str r1, [r0] + ldrh r1, [r0, #4] + cmp r1, #0 + bxle lr + + ldr r12, =KObjectMutex__ErrorOccured + ldr r12, [r12] + blx r12 + bx lr + +.global safecpy +.type safecpy, %function +safecpy: + push {r4, lr} + mov r3, #0 + movs r12, #1 + + _safecpy_loop: + ldrb r4, [r1, r3] + cmp r12, #0 + beq _safecpy_loop_end + strb r4, [r0, r3] + add r3, #1 + cmp r3, r2 + blo _safecpy_loop + + _safecpy_loop_end: + mov r0, r3 + pop {r4, pc} + +_safecpy_end: + +.section .rodata + +.global safecpy_sz +safecpy_sz: .word _safecpy_end - safecpy + +.bss +.balign 4 + +.global SGI0Handler +SGI0Handler: .word 0 @ see synchronization.c + +.balign 4 + +.section .data +.balign 4 + +_customInterruptEventObj: .word SGI0Handler +.global customInterruptEvent +customInterruptEvent: .word _customInterruptEventObj diff --git a/sysmodules/rosalina/rosalina.rsf b/sysmodules/rosalina/rosalina.rsf new file mode 100644 index 000000000..6600b602a --- /dev/null +++ b/sysmodules/rosalina/rosalina.rsf @@ -0,0 +1,65 @@ +BasicInfo: + Title : rosalina + CompanyCode : "00" + ProductCode : 0828builder + ContentType : Application + Logo : None + +TitleInfo: + UniqueId : 0x69 + Category : Base + Version : 2 + +Option: + UseOnSD : false + FreeProductCode : true # Removes limitations on ProductCode + MediaFootPadding : false # If true CCI files are created with padding + EnableCrypt : false # Enables encryption for NCCH and CIA + EnableCompress : true # Compresses exefs code + +AccessControlInfo: + IdealProcessor : 1 + AffinityMask : 3 + + Priority : 20 + + DisableDebug : false + EnableForceDebug : true + CanWriteSharedPage : true + CanUsePrivilegedPriority : true + CanUseNonAlphabetAndNumber : false + PermitMainFunctionArgument : false + CanShareDeviceMemory : false + RunnableOnSleep : true + SpecialMemoryArrange : true + ResourceLimitCategory : Other + + CoreVersion : 2 + DescVersion : 2 + + MemoryType : System # Application / System / Base + HandleTableSize: 150 + + MemoryMapping: + - 0x1F000000 - 0x1F5FFFFF # VRAM (cached) + + IORegisterMapping: + # We're using the global custom bit31 mapping + + SystemCallAccess: + # The kernel extension removes svc perms checks, so... + SendSyncRequest2: 47 # CustomBackdoor + UnmapProcessMemory: 114 + + InterruptNumbers: + ServiceAccessControl: + - srv:pm + FileSystemAccess: + - DirectSdmc + - CtrNandRw + - CategorySystemApplication + +SystemControlInfo: + SaveDataSize: 0KB # It doesn't use any save data. + RemasterVersion: 0 + StackSize: 0x1000 diff --git a/sysmodules/rosalina/source/3dsx.c b/sysmodules/rosalina/source/3dsx.c new file mode 100644 index 000000000..8abddbc8d --- /dev/null +++ b/sysmodules/rosalina/source/3dsx.c @@ -0,0 +1,284 @@ +/* +* 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 . +* +* 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. +*/ + +/* This file was entirely written by fincs */ + +#include <3ds.h> +#include "3dsx.h" +#include "memory.h" + +#define Log_PrintP(...) ((void)0) + +#define MAXRELOCS 512 +static _3DSX_Reloc s_relocBuf[MAXRELOCS]; +u32 ldrArgvBuf[ARGVBUF_SIZE/4]; + +#define SEC_ASSERT(x) do { if (!(x)) { Log_PrintP("Assertion failed: %s", #x); return false; } } while (0) + +typedef struct +{ + void* segPtrs[3]; // code, rodata & data + u32 segAddrs[3]; + u32 segSizes[3]; +} _3DSX_LoadInfo; + +static inline u32 TranslateAddr(u32 off, _3DSX_LoadInfo* d, u32* offsets) +{ + if (off < offsets[0]) + return d->segAddrs[0] + off; + if (off < offsets[1]) + return d->segAddrs[1] + off - offsets[0]; + return d->segAddrs[2] + off - offsets[1]; +} + +u32 IFile_Read2(IFile *file, void* buffer, u32 size, u32 offset) +{ + Result res; + u64 total = 0; + file->pos = offset; + res = IFile_Read(file, &total, buffer, size); + return R_SUCCEEDED(res) ? total : 0; +} + +bool Ldr_Get3dsxSize(u32* pSize, IFile *file) +{ + _3DSX_Header hdr; + + if (IFile_Read2(file, &hdr, sizeof(hdr), 0) != sizeof(hdr)) + { + Log_PrintP("Cannot read 3DSX header"); + return false; + } + + if (hdr.magic != _3DSX_MAGIC) + { + Log_PrintP("Not a valid 3DSX file"); + return false; + } + + u32 segSizes[3]; + segSizes[0] = (hdr.codeSegSize+0xFFF) &~ 0xFFF; + segSizes[1] = (hdr.rodataSegSize+0xFFF) &~ 0xFFF; + segSizes[2] = (hdr.dataSegSize+0xFFF) &~ 0xFFF; + SEC_ASSERT(segSizes[0] >= hdr.codeSegSize); + SEC_ASSERT(segSizes[1] >= hdr.rodataSegSize); + SEC_ASSERT(segSizes[2] >= hdr.dataSegSize); + + // TODO: Check int overflow + *pSize = segSizes[0] + segSizes[1] + segSizes[2] + 0x1000; // One extra page reserved for settings/etc + + return true; +} + +static inline u32 min(u32 a, u32 b) +{ + return a < b ? a : b; +} + +Handle Ldr_CodesetFrom3dsx(const char* name, u32* codePages, u32 baseAddr, IFile *file, u64 tid) +{ + u32 i,j,k,m; + Result res; + _3DSX_Header hdr; + IFile_Read2(file, &hdr, sizeof(hdr), 0); + + _3DSX_LoadInfo d; + d.segSizes[0] = (hdr.codeSegSize+0xFFF) &~ 0xFFF; + d.segSizes[1] = (hdr.rodataSegSize+0xFFF) &~ 0xFFF; + d.segSizes[2] = (hdr.dataSegSize+0xFFF) &~ 0xFFF; + d.segPtrs[0] = codePages; + d.segPtrs[1] = (char*)d.segPtrs[0] + d.segSizes[0]; + d.segPtrs[2] = (char*)d.segPtrs[1] + d.segSizes[1]; + d.segAddrs[0] = baseAddr; + d.segAddrs[1] = d.segAddrs[0] + d.segSizes[0]; + d.segAddrs[2] = d.segAddrs[1] + d.segSizes[1]; + + u32 offsets[2] = { d.segSizes[0], d.segSizes[0] + d.segSizes[1] }; + u32* segLimit = d.segPtrs[2] + d.segSizes[2]; + + u32 readOffset = hdr.headerSize; + + u32 nRelocTables = hdr.relocHdrSize/4; + SEC_ASSERT((3*4*nRelocTables) <= 0x1000); + u32* extraPage = (u32*)((char*)d.segPtrs[2] + d.segSizes[2]); + u32 extraPageAddr = d.segAddrs[2] + d.segSizes[2]; + + // Read the relocation headers + for (i = 0; i < 3; i ++) + { + if (IFile_Read2(file, &extraPage[i*nRelocTables], hdr.relocHdrSize, readOffset) != hdr.relocHdrSize) + { + Log_PrintP("Cannot read relheader %d", i); + return 0; + } + readOffset += hdr.relocHdrSize; + } + + // Read the code segment + if (IFile_Read2(file, d.segPtrs[0], hdr.codeSegSize, readOffset) != hdr.codeSegSize) + { + Log_PrintP("Cannot read code segment"); + return 0; + } + readOffset += hdr.codeSegSize; + + // Read the rodata segment + if (IFile_Read2(file, d.segPtrs[1], hdr.rodataSegSize, readOffset) != hdr.rodataSegSize) + { + Log_PrintP("Cannot read rodata segment"); + return 0; + } + readOffset += hdr.rodataSegSize; + + // Read the data segment + u32 dataLoadSegSize = hdr.dataSegSize - hdr.bssSize; + if (IFile_Read2(file, d.segPtrs[2], dataLoadSegSize, readOffset) != dataLoadSegSize) + { + Log_PrintP("Cannot read data segment"); + return 0; + } + readOffset += dataLoadSegSize; + + // Relocate the segments + for (i = 0; i < 3; i ++) + { + for (j = 0; j < nRelocTables; j ++) + { + int nRelocs = extraPage[i*nRelocTables + j]; + if (j >= (sizeof(_3DSX_RelocHdr)/4)) + { + // Not using this header + readOffset += nRelocs; + continue; + } + + u32* pos = (u32*)d.segPtrs[i]; + u32* endPos = pos + (d.segSizes[i]/4); + SEC_ASSERT(endPos <= segLimit); + + while (nRelocs) + { + u32 toDo = nRelocs > MAXRELOCS ? MAXRELOCS : nRelocs; + nRelocs -= toDo; + + u32 readSize = toDo*sizeof(_3DSX_Reloc); + if (IFile_Read2(file, s_relocBuf, readSize, readOffset) != readSize) + { + Log_PrintP("Cannot read reloc table (%d,%d)", i, j); + return 0; + } + readOffset += readSize; + + for (k = 0; k < toDo && pos < endPos; k ++) + { + pos += s_relocBuf[k].skip; + u32 nPatches = s_relocBuf[k].patch; + for (m = 0; m < nPatches && pos < endPos; m ++) + { + u32 inAddr = baseAddr + 4*(pos - codePages); + u32 origData = *pos; + u32 subType = origData >> (32-4); + u32 addr = TranslateAddr(origData &~ 0xF0000000, &d, offsets); + //Log_PrintP("%08lX<-%08lX", inAddr, addr); + switch (j) + { + case 0: + { + if (subType != 0) + { + Log_PrintP("Unsupported absolute reloc subtype (%lu)", subType); + return 0; + } + *pos = addr; + break; + } + case 1: + { + u32 data = addr - inAddr; + switch (subType) + { + case 0: *pos = data; break; // 32-bit signed offset + case 1: *pos = data &~ BIT(31); break; // 31-bit signed offset + default: + Log_PrintP("Unsupported relative reloc subtype (%lu)", subType); + return 0; + } + break; + } + } + pos++; + } + } + } + } + } + + // Detect and fill _prm structure + PrmStruct* pst = (PrmStruct*) &codePages[1]; + if (pst->magic == _PRM_MAGIC) + { + memset(extraPage, 0, 0x1000); + memcpy(extraPage, ldrArgvBuf, sizeof(ldrArgvBuf)); + pst->pSrvOverride = extraPageAddr + 0xFFC; + pst->pArgList = extraPageAddr; + pst->runFlags |= RUNFLAG_APTCHAINLOAD; + s64 dummy; + bool isN3DS = svcGetSystemInfo(&dummy, 0x10001, 0) == 0; + if (isN3DS) + { + pst->heapSize = 48*1024*1024; + pst->linearHeapSize = 64*1024*1024; + } else + { + pst->heapSize = 24*1024*1024; + pst->linearHeapSize = 32*1024*1024; + } + } + + // Create the codeset + CodeSetInfo csinfo; + memset(&csinfo, 0, sizeof(csinfo)); + strncpy((char*)csinfo.name, name, 8); + csinfo.program_id = tid; + csinfo.text_addr = d.segAddrs[0]; + csinfo.text_size = d.segSizes[0] >> 12; + csinfo.ro_addr = d.segAddrs[1]; + csinfo.ro_size = d.segSizes[1] >> 12; + csinfo.rw_addr = d.segAddrs[2]; + csinfo.rw_size = (d.segSizes[2] >> 12) + 1; // One extra page reserved for settings/etc + csinfo.text_size_total = csinfo.text_size; + csinfo.ro_size_total = csinfo.ro_size; + csinfo.rw_size_total = csinfo.rw_size; + Handle hCodeset = 0; + res = svcCreateCodeSet(&hCodeset, &csinfo, d.segPtrs[0], d.segPtrs[1], d.segPtrs[2]); + if (res) + { + Log_PrintP("svcCreateCodeSet: %08lX", res); + return 0; + } + + return hCodeset; +} diff --git a/sysmodules/rosalina/source/MyThread.c b/sysmodules/rosalina/source/MyThread.c new file mode 100644 index 000000000..6d420f5ec --- /dev/null +++ b/sysmodules/rosalina/source/MyThread.c @@ -0,0 +1,60 @@ +/* +* 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 . +* +* 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. +*/ + +#include "MyThread.h" +#include "memory.h" + +static void _thread_begin(void* arg) +{ + MyThread *t = (MyThread *)arg; + t->ep(); + MyThread_Exit(); +} + +Result MyThread_Create(MyThread *t, void (*entrypoint)(void), void *stack, u32 stackSize, int prio, int affinity) +{ + t->ep = entrypoint; + t->stacktop = (u8 *)stack + stackSize; + + return svcCreateThread(&t->handle, _thread_begin, (u32)t, (u32*)t->stacktop, prio, affinity); +} + +Result MyThread_Join(MyThread *thread, s64 timeout_ns) +{ + if (thread == NULL) return 0; + Result res = svcWaitSynchronization(thread->handle, timeout_ns); + if(R_FAILED(res)) return res; + + svcCloseHandle(thread->handle); + thread->handle = (Handle)0; + + return res; +} + +void MyThread_Exit(void) +{ + svcExitThread(); +} diff --git a/sysmodules/rosalina/source/csvc.s b/sysmodules/rosalina/source/csvc.s new file mode 100644 index 000000000..658992f35 --- /dev/null +++ b/sysmodules/rosalina/source/csvc.s @@ -0,0 +1,101 @@ +@ This paricular file is licensed under the following terms: + +@ This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable +@ for any damages arising from the use of this software. +@ +@ Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it +@ and redistribute it freely, subject to the following restrictions: +@ +@ The origin of this software must not be misrepresented; you must not claim that you wrote the original software. +@ If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +@ +@ Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +@ This notice may not be removed or altered from any source distribution. + +.arm +.balign 4 + +.macro SVC_BEGIN name + .section .text.\name, "ax", %progbits + .global \name + .type \name, %function + .align 2 + .cfi_startproc +\name: +.endm + +.macro SVC_END + .cfi_endproc +.endm + +SVC_BEGIN svcCustomBackdoor + svc 0x80 + bx lr +SVC_END + +SVC_BEGIN svcConvertVAToPA + svc 0x90 + bx lr +SVC_END + +SVC_BEGIN svcFlushDataCacheRange + svc 0x91 + bx lr +SVC_END + +SVC_BEGIN svcFlushEntireDataCache + svc 0x92 + bx lr +SVC_END + +SVC_BEGIN svcInvalidateInstructionCacheRange + svc 0x93 + bx lr +SVC_END + +SVC_BEGIN svcInvalidateEntireInstructionCache + svc 0x94 + bx lr +SVC_END + +SVC_BEGIN svcMapProcessMemoryEx + svc 0xA0 + bx lr +SVC_END + +SVC_BEGIN svcUnmapProcessMemoryEx + svc 0xA1 + bx lr +SVC_END + +SVC_BEGIN svcControlMemoryEx + push {r0, r4, r5} + ldr r0, [sp, #0xC] + ldr r4, [sp, #0xC+0x4] + ldr r5, [sp, #0xC+0x8] + svc 0xA2 + pop {r2, r4, r5} + str r1, [r2] + bx lr +SVC_END + +SVC_BEGIN svcControlService + svc 0xB0 + bx lr +SVC_END + +SVC_BEGIN svcCopyHandle + str r0, [sp, #-4]! + svc 0xB1 + ldr r2, [sp], #4 + str r1, [r2] + bx lr +SVC_END + +SVC_BEGIN svcTranslateHandle + str r0, [sp, #-4]! + svc 0xB2 + ldr r2, [sp], #4 + str r1, [r2] + bx lr +SVC_END diff --git a/sysmodules/rosalina/source/draw.c b/sysmodules/rosalina/source/draw.c new file mode 100644 index 000000000..d154ca47e --- /dev/null +++ b/sysmodules/rosalina/source/draw.c @@ -0,0 +1,277 @@ +/* +* 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 . +* +* 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. +*/ + +#include <3ds.h> +#include +#include "fmt.h" +#include "draw.h" +#include "font.h" +#include "memory.h" +#include "menu.h" +#include "utils.h" + +u8 framebuffer_cache[FB_BOTTOM_SIZE]; + +static u32 gpuSavedFramebufferAddr1, gpuSavedFramebufferSelect, gpuSavedFramebufferFormat, gpuSavedFramebufferStride; + +static RecursiveLock lock; + +void Draw_Lock(void) +{ + static bool lockInitialized = false; + if(!lockInitialized) + { + RecursiveLock_Init(&lock); + lockInitialized = true; + } + + RecursiveLock_Lock(&lock); +} + +void Draw_Unlock(void) +{ + RecursiveLock_Unlock(&lock); +} + +void Draw_DrawCharacter(u32 posX, u32 posY, u32 color, char character) +{ + volatile u16 *const fb = (volatile u16 *const)FB_BOTTOM_VRAM_ADDR; + + s32 y; + for(y = 0; y < 10; y++) + { + char charPos = font[character * 10 + y]; + + s32 x; + for(x = 6; x >= 1; x--) + { + u32 screenPos = (posX * SCREEN_BOT_HEIGHT * 2 + (SCREEN_BOT_HEIGHT - y - posY - 1) * 2) + (5 - x) * 2 * SCREEN_BOT_HEIGHT; + u32 pixelColor = ((charPos >> x) & 1) ? color : COLOR_BLACK; + fb[screenPos / 2] = pixelColor; + } + } +} + +u32 Draw_DrawString(u32 posX, u32 posY, u32 color, const char *string) +{ + for(u32 i = 0, line_i = 0; i < ((u32) strlen(string)); i++) + { + if(string[i] == '\n') + { + posY += SPACING_Y; + line_i = 0; + continue; + } + else if(line_i >= (SCREEN_BOT_WIDTH - posX) / SPACING_X) + { + // Make sure we never get out of the screen. + posY += SPACING_Y; + line_i = 0; + if(string[i] == ' ') + continue; // Spaces at the start look weird + } + + Draw_DrawCharacter(posX + line_i * SPACING_X, posY, color, string[i]); + line_i++; + } + + return posY; +} + +u32 Draw_DrawFormattedString(u32 posX, u32 posY, u32 color, const char *fmt, ...) +{ + char buf[DRAW_MAX_FORMATTED_STRING_SIZE + 1]; + va_list args; + va_start(args, fmt); + vsprintf(buf, fmt, args); + va_end(args); + + return Draw_DrawString(posX, posY, color, buf); +} + +void Draw_FillFramebuffer(u32 value) +{ + memset32(FB_BOTTOM_VRAM_ADDR, value, FB_BOTTOM_SIZE); +} + +void Draw_ClearFramebuffer(void) +{ + Draw_FillFramebuffer(0); +} + +void Draw_SetupFramebuffer(void) +{ + while((GPU_PSC0_CNT | GPU_PSC1_CNT | GPU_TRANSFER_CNT | GPU_CMDLIST_CNT) & 1); + + memcpy(framebuffer_cache, FB_BOTTOM_VRAM_ADDR, FB_BOTTOM_SIZE); + gpuSavedFramebufferAddr1 = GPU_FB_BOTTOM_ADDR_1; + gpuSavedFramebufferSelect = GPU_FB_BOTTOM_SEL; + gpuSavedFramebufferFormat = GPU_FB_BOTTOM_FMT; + gpuSavedFramebufferStride = GPU_FB_BOTTOM_STRIDE; + + GPU_FB_BOTTOM_SEL &= ~1; + GPU_FB_BOTTOM_ADDR_1 = FB_BOTTOM_VRAM_PA; + GPU_FB_BOTTOM_FMT = 0x80302; + GPU_FB_BOTTOM_STRIDE = 240 * 2; + + Draw_FlushFramebuffer(); +} + +void Draw_RestoreFramebuffer(void) +{ + memcpy(FB_BOTTOM_VRAM_ADDR, framebuffer_cache, FB_BOTTOM_SIZE); + + GPU_FB_BOTTOM_ADDR_1 = gpuSavedFramebufferAddr1; + GPU_FB_BOTTOM_FMT = gpuSavedFramebufferFormat; + GPU_FB_BOTTOM_STRIDE = gpuSavedFramebufferStride; + GPU_FB_BOTTOM_SEL = gpuSavedFramebufferSelect; + + Draw_FlushFramebuffer(); +} + +void Draw_FlushFramebuffer(void) +{ + svcFlushProcessDataCache(CUR_PROCESS_HANDLE, FB_BOTTOM_VRAM_ADDR, FB_BOTTOM_SIZE); +} + +u32 Draw_GetCurrentFramebufferAddress(bool top, bool left) +{ + if(GPU_FB_BOTTOM_SEL & 1) + { + if(left) + return top ? GPU_FB_TOP_LEFT_ADDR_2 : GPU_FB_BOTTOM_ADDR_2; + else + return top ? GPU_FB_TOP_RIGHT_ADDR_2 : GPU_FB_BOTTOM_ADDR_2; + } + else + { + if(left) + return top ? GPU_FB_TOP_LEFT_ADDR_1 : GPU_FB_BOTTOM_ADDR_1; + else + return top ? GPU_FB_TOP_RIGHT_ADDR_1 : GPU_FB_BOTTOM_ADDR_1; + } +} + +static inline void Draw_WriteUnaligned(u8 *dst, u32 tmp, u32 size) +{ + memcpy(dst, &tmp, size); +} + +void Draw_CreateBitmapHeader(u8 *dst, u32 width, u32 heigth) +{ + static const u8 bmpHeaderTemplate[54] = { + 0x42, 0x4D, 0xCC, 0xCC, 0xCC, 0xCC, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x28, 0x00, + 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x01, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0x12, 0x0B, 0x00, 0x00, 0x12, 0x0B, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + memcpy(dst, bmpHeaderTemplate, 54); + Draw_WriteUnaligned(dst + 2, 54 + 3 * width * heigth, 4); + Draw_WriteUnaligned(dst + 0x12, width, 4); + Draw_WriteUnaligned(dst + 0x16, heigth, 4); + Draw_WriteUnaligned(dst + 0x22, 3 * width * heigth, 4); +} + +static inline void Draw_ConvertPixelToBGR8(u8 *dst, const u8 *src, GSPGPU_FramebufferFormats srcFormat) +{ + u8 red, green, blue; + switch(srcFormat) + { + case GSP_RGBA8_OES: + { + u32 px = *(u32 *)src; + dst[0] = (px >> 8) & 0xFF; + dst[1] = (px >> 16) & 0xFF; + dst[2] = (px >> 24) & 0xFF; + break; + } + case GSP_BGR8_OES: + { + dst[2] = src[2]; + dst[1] = src[1]; + dst[0] = src[0]; + break; + } + case GSP_RGB565_OES: + { + // thanks neobrain + u16 px = *(u16 *)src; + blue = px & 0x1F; + green = (px >> 5) & 0x3F; + red = (px >> 11) & 0x1F; + + dst[0] = (blue << 3) | (blue >> 2); + dst[1] = (green << 2) | (green >> 4); + dst[2] = (red << 3) | (red >> 2); + + break; + } + case GSP_RGB5_A1_OES: + { + u16 px = *(u16 *)src; + blue = px & 0x1F; + green = (px >> 5) & 0x1F; + red = (px >> 10) & 0x1F; + + dst[0] = (blue << 3) | (blue >> 2); + dst[1] = (green << 3) | (green >> 2); + dst[2] = (red << 3) | (red >> 2); + + break; + } + case GSP_RGBA4_OES: + { + u16 px = *(u32 *)src; + blue = px & 0xF; + green = (px >> 4) & 0xF; + red = (px >> 8) & 0xF; + + dst[0] = (blue << 4) | (blue >> 4); + dst[1] = (green << 4) | (green >> 4); + dst[2] = (red << 4) | (red >> 4); + + break; + } + default: break; + } +} + +static u8 line[3 * 400]; + +u8 *Draw_ConvertFrameBufferLine(bool top, bool left, u32 y) +{ + GSPGPU_FramebufferFormats fmt = top ? (GSPGPU_FramebufferFormats)(GPU_FB_TOP_FMT & 7) : (GSPGPU_FramebufferFormats)(GPU_FB_BOTTOM_FMT & 7); + u32 width = top ? 400 : 320; + u8 formatSizes[] = { 4, 3, 2, 2, 2 }; + + u32 pa = Draw_GetCurrentFramebufferAddress(top, left); + u8 *addr = (u8 *)PA_PTR(pa); + + for(u32 x = 0; x < width; x++) + Draw_ConvertPixelToBGR8(line + x * 3 , addr + (x * 240 + y) * formatSizes[(u8)fmt], fmt); + return line; +} diff --git a/sysmodules/rosalina/source/errdisp.c b/sysmodules/rosalina/source/errdisp.c new file mode 100644 index 000000000..5a1d19537 --- /dev/null +++ b/sysmodules/rosalina/source/errdisp.c @@ -0,0 +1,283 @@ +/* +* 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 . +* +* 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. +*/ + +#include <3ds.h> +#include "errdisp.h" +#include "draw.h" +#include "menu.h" +#include "memory.h" + +static inline void assertSuccess(Result res) +{ + if(R_FAILED(res)) + svcBreak(USERBREAK_PANIC); +} + +static MyThread errDispThread; +static u8 ALIGN(8) errDispThreadStack[THREAD_STACK_SIZE]; + +static char userString[0x100 + 1] = {0}; + +MyThread *errDispCreateThread(void) +{ + if(R_FAILED(MyThread_Create(&errDispThread, errDispThreadMain, errDispThreadStack, THREAD_STACK_SIZE, 0x18, CORE_SYSTEM))) + svcBreak(USERBREAK_PANIC); + return &errDispThread; +} + +static inline u32 ERRF_DisplayRegisterValue(u32 posX, u32 posY, const char *name, u32 value) +{ + return Draw_DrawFormattedString(posX, posY, COLOR_WHITE, "%-9s %08x", name, value); +} + +void ERRF_DisplayError(ERRF_FatalErrInfo *info) +{ + Draw_Lock(); + + u32 posY = Draw_DrawString(10, 10, COLOR_RED, userString[0] == 0 ? "An error occurred (ErrDisp)" : userString); + + static const char *types[] = { + "generic", "corrupted", "card removed", "exception", "result failure", "logged", "invalid" + }; + + static const char *exceptionTypes[] = { + "prefetch abort", "data abort", "undefined instruction", "VFP", "invalid" + }; + + const char *type = (u32)info->type > (u32)ERRF_ERRTYPE_LOGGED ? types[6] : types[(u32)info->type]; + posY = posY < 30 ? 30 : posY; + + if(info->type == ERRF_ERRTYPE_EXCEPTION) + { + const char *exceptionType = (u32)info->data.exception_data.excep.type > (u32)ERRF_EXCEPTION_VFP ? + exceptionTypes[4] : exceptionTypes[(u32)info->data.exception_data.excep.type]; + + Draw_DrawFormattedString(10, posY, COLOR_WHITE, "Error type: exception (%s)", exceptionType); + } + else + Draw_DrawFormattedString(10, posY, COLOR_WHITE, "Error type: %s", type); + + if(info->type != ERRF_ERRTYPE_CARD_REMOVED) + { + Handle processHandle; + Result res; + + posY += SPACING_Y; + posY = Draw_DrawFormattedString(10, posY + SPACING_Y, COLOR_WHITE, "Process ID: %u", info->procId); + + res = svcOpenProcess(&processHandle, info->procId); + if(R_SUCCEEDED(res)) + { + u64 titleId; + char name[9] = { 0 }; + svcGetProcessInfo((s64 *)name, processHandle, 0x10000); + svcGetProcessInfo((s64 *)&titleId, processHandle, 0x10001); + svcCloseHandle(processHandle); + posY = Draw_DrawFormattedString(10, posY + SPACING_Y, COLOR_WHITE, "Process name: %s", name); + posY = Draw_DrawFormattedString(10, posY + SPACING_Y, COLOR_WHITE, "Process title ID: 0x%016llx", titleId); + } + + posY += SPACING_Y; + } + + if(info->type == ERRF_ERRTYPE_EXCEPTION) + { + static const char *registerNames[] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", + "sp", "lr", "pc", "cpsr" + }; + + u32 *regs = (u32 *)(&info->data.exception_data.regs); + for(u32 i = 0; i < 17; i += 2) + { + posY = ERRF_DisplayRegisterValue(10, posY + SPACING_Y, registerNames[i], regs[i]); + + if(i != 16) + ERRF_DisplayRegisterValue(10 + 28 * SPACING_X, posY, registerNames[i + 1], i == 16 ? regs[20] : regs[i + 1]); + } + + if(info->data.exception_data.excep.type == ERRF_EXCEPTION_PREFETCH_ABORT + || info->data.exception_data.excep.type == ERRF_EXCEPTION_DATA_ABORT) + { + ERRF_DisplayRegisterValue(10 + 28 * SPACING_X, posY, "far", info->data.exception_data.excep.far); + posY = ERRF_DisplayRegisterValue(10, posY + SPACING_Y, "fsr", info->data.exception_data.excep.fsr); + } + + else if(info->data.exception_data.excep.type == ERRF_EXCEPTION_VFP) + { + ERRF_DisplayRegisterValue(10 + 28 * SPACING_X, posY, "fpexc", info->data.exception_data.excep.fpexc); + posY = ERRF_DisplayRegisterValue(10, posY + SPACING_Y, "fpinst", info->data.exception_data.excep.fpinst); + ERRF_DisplayRegisterValue(10 + 28 * SPACING_X, posY, "fpinst2", info->data.exception_data.excep.fpinst2); + } + } + + else if(info->type != ERRF_ERRTYPE_CARD_REMOVED) + { + if(info->type != ERRF_ERRTYPE_FAILURE) + posY = Draw_DrawFormattedString(10, posY + SPACING_Y, COLOR_WHITE, "Address: 0x%08x", info->pcAddr); + + posY = Draw_DrawFormattedString(10, posY + SPACING_Y, COLOR_WHITE, "Error code: 0x%08x", info->resCode); + } + + const char *desc; + switch(info->type) + { + case ERRF_ERRTYPE_CARD_REMOVED: + desc = "The Game Card was removed."; + break; + case ERRF_ERRTYPE_MEM_CORRUPT: + desc = "The System Memory has been damaged."; + break; + case ERRF_ERRTYPE_FAILURE: + info->data.failure_mesg[0x60] = 0; // make sure the last byte in the IPC buffer is NULL + desc = info->data.failure_mesg; + break; + default: + desc = ""; + break; + } + + posY += SPACING_Y; + if(desc[0] != 0) + posY = Draw_DrawString(10, posY + SPACING_Y, COLOR_WHITE, desc) + SPACING_Y; + posY = Draw_DrawString(10, posY + SPACING_Y, COLOR_WHITE, "Press any button to reboot"); + + Draw_FlushFramebuffer(); + Draw_Unlock(); +} + +void ERRF_HandleCommands(void) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + switch(cmdbuf[0] >> 16) + { + case 1: // Throw + { + ERRF_FatalErrInfo *info = (ERRF_FatalErrInfo *)(cmdbuf + 1); + menuEnter(); + + Draw_Lock(); + Draw_ClearFramebuffer(); + Draw_FlushFramebuffer(); + + ERRF_DisplayError(info); + + /* + If we ever wanted to return: + draw_unlock(); + menuLeave(); + + cmdbuf[0] = 0x10040; + cmdbuf[1] = 0; + + but we don't + */ + waitInput(); + svcKernelSetState(7); + __builtin_unreachable(); + break; + } + + case 2: // SetUserString + { + if(cmdbuf[0] != 0x20042 || (cmdbuf[2] & 0x3C0F) != 2) + { + cmdbuf[0] = 0x40; + cmdbuf[1] = 0xD9001830; + } + else + { + cmdbuf[0] = 0x20040; + u32 sz = cmdbuf[1] <= 0x100 ? sz : 0x100; + memcpy(userString, cmdbuf + 3, sz); + userString[sz] = 0; + } + break; + } + } +} + +void errDispThreadMain(void) +{ + Handle handles[2]; + Handle serverHandle, clientHandle, sessionHandle = 0; + + u32 replyTarget = 0; + s32 index; + + Result res; + u32 *cmdbuf = getThreadCommandBuffer(); + + assertSuccess(svcCreatePort(&serverHandle, &clientHandle, "err:f", 1)); + + do + { + handles[0] = serverHandle; + handles[1] = sessionHandle; + + if(replyTarget == 0) // k11 + cmdbuf[0] = 0xFFFF0000; + res = svcReplyAndReceive(&index, handles, sessionHandle == 0 ? 1 : 2, replyTarget); + + if(R_FAILED(res)) + { + if((u32)res == 0xC920181A) // session closed by remote + { + svcCloseHandle(sessionHandle); + sessionHandle = 0; + replyTarget = 0; + } + + else + svcBreak(USERBREAK_PANIC); + } + + else + { + if(index == 0) + { + Handle session; + assertSuccess(svcAcceptSession(&session, serverHandle)); + + if(sessionHandle == 0) + sessionHandle = session; + else + svcCloseHandle(session); + } + else + { + ERRF_HandleCommands(); + replyTarget = sessionHandle; + } + } + } + while(!terminationRequest); + + svcCloseHandle(sessionHandle); + svcCloseHandle(clientHandle); + svcCloseHandle(serverHandle); +} diff --git a/sysmodules/rosalina/source/fmt.c b/sysmodules/rosalina/source/fmt.c new file mode 100644 index 000000000..9403054da --- /dev/null +++ b/sysmodules/rosalina/source/fmt.c @@ -0,0 +1,315 @@ +/* +* 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 . +* +* 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. +*/ + +/* File : barebones/ee_printf.c + This file contains an implementation of ee_printf that only requires a method to output a char to a UART without pulling in library code. +This code is based on a file that contains the following: + Copyright (C) 2002 Michael Ringgaard. All rights reserved. + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the project nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. +*/ + +//TuxSH's changes: add support for 64-bit numbers, remove floating-point code + +#include <3ds/types.h> +#include "memory.h" +#include "fmt.h" + +#define ZEROPAD (1<<0) //Pad with zero +#define SIGN (1<<1) //Unsigned/signed long +#define PLUS (1<<2) //Show plus +#define SPACE (1<<3) //Spacer +#define LEFT (1<<4) //Left justified +#define HEX_PREP (1<<5) //0x +#define UPPERCASE (1<<6) //'ABCDEF' + +#define IS_DIGIT(c) ((c) >= '0' && (c) <= '9') + +static s32 skipAtoi(const char **s) +{ + s32 i = 0; + + while(IS_DIGIT(**s)) i = i * 10 + *((*s)++) - '0'; + + return i; +} + +static char *processNumber(char *str, s64 num, bool isHex, s32 size, s32 precision, u32 type) +{ + char sign = 0; + + if(type & SIGN) + { + if(num < 0) + { + sign = '-'; + num = -num; + size--; + } + else if(type & PLUS) + { + sign = '+'; + size--; + } + else if(type & SPACE) + { + sign = ' '; + size--; + } + } + + static const char *lowerDigits = "0123456789abcdef", + *upperDigits = "0123456789ABCDEF"; + + s32 i = 0; + char tmp[20]; + const char *dig = (type & UPPERCASE) ? upperDigits : lowerDigits; + + if(num == 0) + { + if(precision != 0) tmp[i++] = '0'; + type &= ~HEX_PREP; + } + else + { + while(num != 0) + { + u64 base = isHex ? 16ULL : 10ULL; + tmp[i++] = dig[(u64)num % base]; + num = (s64)((u64)num / base); + } + } + + if(type & LEFT || precision != -1) type &= ~ZEROPAD; + if(type & HEX_PREP && isHex) size -= 2; + if(i > precision) precision = i; + size -= precision; + if(!(type & (ZEROPAD | LEFT))) while(size-- > 0) *str++ = ' '; + if(sign) *str++ = sign; + + if(type & HEX_PREP && isHex) + { + *str++ = '0'; + *str++ = 'x'; + } + + if(type & ZEROPAD) while(size-- > 0) *str++ = '0'; + while(i < precision--) *str++ = '0'; + while(i-- > 0) *str++ = tmp[i]; + while(size-- > 0) *str++ = ' '; + + return str; +} + +int vsprintf(char *buf, const char *fmt, va_list args) +{ + char *str; + + for(str = buf; *fmt; fmt++) + { + if(*fmt != '%') + { + *str++ = *fmt; + continue; + } + + //Process flags + u32 flags = 0; //Flags to number() + bool loop = true; + + while(loop) + { + switch(*++fmt) + { + case '-': flags |= LEFT; break; + case '+': flags |= PLUS; break; + case ' ': flags |= SPACE; break; + case '#': flags |= HEX_PREP; break; + case '0': flags |= ZEROPAD; break; + default: loop = false; break; + } + } + + //Get field width + s32 fieldWidth = -1; //Width of output field + if(IS_DIGIT(*fmt)) fieldWidth = skipAtoi(&fmt); + else if(*fmt == '*') + { + fmt++; + + fieldWidth = va_arg(args, s32); + + if(fieldWidth < 0) + { + fieldWidth = -fieldWidth; + flags |= LEFT; + } + } + + //Get the precision + s32 precision = -1; //Min. # of digits for integers; max number of chars for from string + if(*fmt == '.') + { + fmt++; + + if(IS_DIGIT(*fmt)) precision = skipAtoi(&fmt); + else if(*fmt == '*') + { + fmt++; + precision = va_arg(args, s32); + } + + if(precision < 0) precision = 0; + } + + //Get the conversion qualifier + u32 integerType = 0; + if(*fmt == 'l') + { + if(*++fmt == 'l') + { + fmt++; + integerType = 1; + } + + } + else if(*fmt == 'h') + { + if(*++fmt == 'h') + { + fmt++; + integerType = 3; + } + else integerType = 2; + } + + bool isHex; + + switch(*fmt) + { + case 'c': + if(!(flags & LEFT)) while(--fieldWidth > 0) *str++ = ' '; + *str++ = (u8)va_arg(args, s32); + while(--fieldWidth > 0) *str++ = ' '; + continue; + + case 's': + { + char *s = va_arg(args, char *); + if(!s) s = ""; + u32 len = (precision != -1) ? strnlen(s, precision) : strlen(s); + if(!(flags & LEFT)) while((s32)len < fieldWidth--) *str++ = ' '; + for(u32 i = 0; i < len; i++) *str++ = *s++; + while((s32)len < fieldWidth--) *str++ = ' '; + continue; + } + + case 'p': + if(fieldWidth == -1) + { + fieldWidth = 8; + flags |= ZEROPAD; + } + str = processNumber(str, va_arg(args, u32), true, fieldWidth, precision, flags); + continue; + + //Integer number formats - set up the flags and "break" + case 'X': + flags |= UPPERCASE; + + case 'x': + isHex = true; + break; + + case 'd': + case 'i': + flags |= SIGN; + + case 'u': + isHex = false; + break; + + default: + if(*fmt != '%') *str++ = '%'; + if(*fmt) *str++ = *fmt; + else fmt--; + continue; + } + + s64 num; + + if(flags & SIGN) + { + if(integerType == 1) num = va_arg(args, s64); + else num = va_arg(args, s32); + + if(integerType == 2) num = (s16)num; + else if(integerType == 3) num = (s8)num; + } + else + { + if(integerType == 1) num = va_arg(args, u64); + else num = va_arg(args, u32); + + if(integerType == 2) num = (u16)num; + else if(integerType == 3) num = (u8)num; + } + + str = processNumber(str, num, isHex, fieldWidth, precision, flags); + } + + *str = 0; + return str - buf; +} + +int sprintf(char *buf, const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + int res = vsprintf(buf, fmt, args); + va_end(args); + return res; +} diff --git a/sysmodules/rosalina/source/fsreg.c b/sysmodules/rosalina/source/fsreg.c new file mode 100644 index 000000000..56d2829a3 --- /dev/null +++ b/sysmodules/rosalina/source/fsreg.c @@ -0,0 +1,179 @@ +/* +* 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 . +* +* 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. +*/ + +#include <3ds.h> +#include +#include "fsreg.h" +#include "services.h" +#include "csvc.h" + +static Handle fsregHandle; +static int fsregRefCount; + +Result fsregInit(void) +{ + Result ret = 0; + + if(AtomicPostIncrement(&fsregRefCount)) + return 0; + + ret = svcControlService(SERVICEOP_STEAL_CLIENT_SESSION, &fsregHandle, "fs:REG"); + while(ret == 0x9401BFE) + { + svcSleepThread(500 * 1000LL); + ret = svcControlService(SERVICEOP_STEAL_CLIENT_SESSION, &fsregHandle, "fs:REG"); + } + + if(R_FAILED(ret)) + AtomicDecrement(&fsregRefCount); + return ret; +} + +void fsregExit(void) +{ + if(AtomicDecrement(&fsregRefCount) || !fsregHandle) + return; + svcCloseHandle(fsregHandle); +} + +Handle fsregGetHandle(void) +{ + return fsregHandle; +} + +Result fsregSetupPermissions(void) +{ + u32 pid; + Result res; + FS_ProgramInfo info; + u32 storage[8] = {0}; + + storage[6] = 0x800 | 0x400 | 0x80 | 0x1; // SDMC access and NAND access flags + info.programId = 0x0004013000006902LL; // Rosalina TID + info.mediaType = MEDIATYPE_NAND; + + if(R_SUCCEEDED(res = svcGetProcessId(&pid, 0xFFFF8001))) // 0xFFFF8001 is an handle to the active process + res = FSREG_Register(pid, 0xFFFF000000000000LL, &info, (u8*)storage); + + return res; +} + +Result FSREG_CheckHostLoadId(u64 prog_handle) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x406,2,0); // 0x4060080 + cmdbuf[1] = (u32) (prog_handle); + cmdbuf[2] = (u32) (prog_handle >> 32); + + Result ret = 0; + if(R_FAILED(ret = svcSendSyncRequest(fsregHandle))) + return ret; + + return cmdbuf[1]; +} + +Result FSREG_LoadProgram(u64 *prog_handle, FS_ProgramInfo *title) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x404,4,0); // 0x4040100 + memcpy(&cmdbuf[1], &title->programId, sizeof(u64)); + *(u8 *)&cmdbuf[3] = title->mediaType; + memcpy(((u8 *)&cmdbuf[3])+1, &title->padding, 7); + + Result ret = 0; + if(R_FAILED(ret = svcSendSyncRequest(fsregHandle))) + return ret; + *prog_handle = *(u64 *)&cmdbuf[2]; + + return cmdbuf[1]; +} + +Result FSREG_GetProgramInfo(exheader_header *exheader, u32 entry_count, u64 prog_handle) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x403,3,0); // 0x40300C0 + cmdbuf[1] = entry_count; + *(u64 *)&cmdbuf[2] = prog_handle; + cmdbuf[64] = ((entry_count << 10) << 14) | 2; + cmdbuf[65] = (u32) exheader; + + Result ret = 0; + if(R_FAILED(ret = svcSendSyncRequest(fsregHandle))) + return ret; + + return cmdbuf[1]; +} + +Result FSREG_UnloadProgram(u64 prog_handle) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x405,2,0); // 0x4050080 + cmdbuf[1] = (u32) (prog_handle); + cmdbuf[2] = (u32) (prog_handle >> 32); + + Result ret = 0; + if(R_FAILED(ret = svcSendSyncRequest(fsregHandle))) + return ret; + + return cmdbuf[1]; +} + +Result FSREG_Unregister(u32 pid) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x402,1,0); // 0x4020040 + cmdbuf[1] = pid; + + Result ret = 0; + if(R_FAILED(ret = svcSendSyncRequest(fsregHandle))) + return ret; + + return cmdbuf[1]; +} + +Result FSREG_Register(u32 pid, u64 prog_handle, FS_ProgramInfo *info, void *storageinfo) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x401,0xf,0); // 0x40103C0 + cmdbuf[1] = pid; + *(u64 *)&cmdbuf[2] = prog_handle; + memcpy(&cmdbuf[4], &info->programId, sizeof(u64)); + *(u8 *)&cmdbuf[6] = info->mediaType; + memcpy(((u8 *)&cmdbuf[6])+1, &info->padding, 7); + memcpy((u8 *)&cmdbuf[8], storageinfo, 32); + + Result ret = 0; + if(R_FAILED(ret = svcSendSyncRequest(fsregHandle))) + return ret; + + return cmdbuf[1]; +} diff --git a/sysmodules/rosalina/source/gdb.c b/sysmodules/rosalina/source/gdb.c new file mode 100644 index 000000000..1ed24bc48 --- /dev/null +++ b/sysmodules/rosalina/source/gdb.c @@ -0,0 +1,60 @@ +/* +* 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 . +* +* 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. +*/ + +#include "gdb.h" +#include "gdb/net.h" + +void GDB_InitializeContext(GDBContext *ctx) +{ + RecursiveLock_Init(&ctx->lock); + + RecursiveLock_Lock(&ctx->lock); + + svcCreateEvent(&ctx->continuedEvent, RESET_ONESHOT); + svcCreateEvent(&ctx->clientAcceptedEvent, RESET_STICKY); + + ctx->eventToWaitFor = ctx->clientAcceptedEvent; + ctx->continueFlags = (DebugFlags)(DBG_SIGNAL_FAULT_EXCEPTION_EVENTS | DBG_INHIBIT_USER_CPU_EXCEPTION_HANDLERS); + + RecursiveLock_Unlock(&ctx->lock); +} + +void GDB_FinalizeContext(GDBContext *ctx) +{ + RecursiveLock_Lock(&ctx->lock); + + svcClearEvent(ctx->clientAcceptedEvent); + + svcCloseHandle(ctx->clientAcceptedEvent); + svcCloseHandle(ctx->continuedEvent); + + RecursiveLock_Unlock(&ctx->lock); +} + +GDB_DECLARE_HANDLER(Unsupported) +{ + return GDB_ReplyEmpty(ctx); +} diff --git a/sysmodules/rosalina/source/gdb/breakpoints.c b/sysmodules/rosalina/source/gdb/breakpoints.c new file mode 100644 index 000000000..64b3e1d86 --- /dev/null +++ b/sysmodules/rosalina/source/gdb/breakpoints.c @@ -0,0 +1,130 @@ +/* +* 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 . +* +* 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. +*/ + +#include "gdb/breakpoints.h" + +#define _REENT_ONLY +#include + +u32 GDB_FindClosestBreakpointSlot(GDBContext *ctx, u32 address) +{ + if(ctx->nbBreakpoints == 0 || address <= ctx->breakpoints[0].address) + return 0; + else if(address > ctx->breakpoints[ctx->nbBreakpoints - 1].address) + return ctx->nbBreakpoints; + + u32 a = 0, b = ctx->nbBreakpoints - 1, m; + + do + { + m = (a + b) / 2; + if(ctx->breakpoints[m].address < address) + a = m; + else if(ctx->breakpoints[m].address > address) + b = m; + else + return m; + } + while(b - a > 1); + + return b; +} + +int GDB_GetBreakpointInstruction(u32 *instruction, GDBContext *ctx, u32 address) +{ + u32 id = GDB_FindClosestBreakpointSlot(ctx, address); + + if(id == ctx->nbBreakpoints || ctx->breakpoints[id].address != address) + return -EINVAL; + + if(instruction != NULL) + *instruction = ctx->breakpoints[id].savedInstruction; + + return 0; +} + +int GDB_AddBreakpoint(GDBContext *ctx, u32 address, bool thumb, bool persist) +{ + u32 id = GDB_FindClosestBreakpointSlot(ctx, address); + + if(id != ctx->nbBreakpoints && ctx->breakpoints[id].instructionSize != 0 && ctx->breakpoints[id].address == address) + return 0; + else if(ctx->nbBreakpoints == MAX_BREAKPOINT) + return -EBUSY; + else if((thumb && (address & 1) != 0) || (!thumb && (address & 3) != 0)) + return -EINVAL; + + for(u32 i = ctx->nbBreakpoints; i > id && i != 0; i--) + ctx->breakpoints[i] = ctx->breakpoints[i - 1]; + + ctx->nbBreakpoints++; + + Breakpoint *bkpt = &ctx->breakpoints[id]; + u32 instr = thumb ? BREAKPOINT_INSTRUCTION_THUMB : BREAKPOINT_INSTRUCTION_ARM; + if(R_FAILED(svcReadProcessMemory(&bkpt->savedInstruction, ctx->debug, address, thumb ? 2 : 4)) || + R_FAILED(svcWriteProcessMemory(ctx->debug, &instr, address, thumb ? 2 : 4))) + { + for(u32 i = id; i < ctx->nbBreakpoints - 1; i++) + ctx->breakpoints[i] = ctx->breakpoints[i + 1]; + + memset(&ctx->breakpoints[--ctx->nbBreakpoints], 0, sizeof(Breakpoint)); + return -EFAULT; + } + + bkpt->instructionSize = thumb ? 2 : 4; + bkpt->address = address; + bkpt->persistent = persist; + + return 0; +} + +int GDB_DisableBreakpointById(GDBContext *ctx, u32 id) +{ + Breakpoint *bkpt = &ctx->breakpoints[id]; + if(R_FAILED(svcWriteProcessMemory(ctx->debug, &bkpt->savedInstruction, bkpt->address, bkpt->instructionSize))) + return -EFAULT; + else return 0; +} + +int GDB_RemoveBreakpoint(GDBContext *ctx, u32 address) +{ + u32 id = GDB_FindClosestBreakpointSlot(ctx, address); + if(id == ctx->nbBreakpoints || ctx->breakpoints[id].address != address) + return -EINVAL; + + int r = GDB_DisableBreakpointById(ctx, id); + if(r != 0) + return r; + else + { + for(u32 i = id; i < ctx->nbBreakpoints - 1; i++) + ctx->breakpoints[i] = ctx->breakpoints[i + 1]; + + memset(&ctx->breakpoints[--ctx->nbBreakpoints], 0, sizeof(Breakpoint)); + + return 0; + } +} diff --git a/sysmodules/rosalina/source/gdb/debug.c b/sysmodules/rosalina/source/gdb/debug.c new file mode 100644 index 000000000..0ac3a6368 --- /dev/null +++ b/sysmodules/rosalina/source/gdb/debug.c @@ -0,0 +1,512 @@ +/* +* 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 . +* +* 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. +*/ + +#include "gdb/debug.h" +#include "gdb/verbose.h" +#include "gdb/net.h" +#include "gdb/thread.h" +#include "gdb/mem.h" +#include "gdb/watchpoints.h" +#include "fmt.h" + +#include +#include + +/* + Since we can't select particular threads to continue (and that's uncompliant behavior): + - if we continue the current thread, continue all threads + - otherwise, leaves all threads stopped but make the client believe it's continuing +*/ + +GDB_DECLARE_HANDLER(Detach) +{ + ctx->state = GDB_STATE_CLOSING; + return GDB_ReplyOk(ctx); +} + +GDB_DECLARE_HANDLER(Kill) +{ + ctx->state = GDB_STATE_CLOSING; + ctx->flags |= GDB_FLAG_TERMINATE_PROCESS; + return 0; +} + +GDB_DECLARE_HANDLER(Break) +{ + if(!(ctx->flags & GDB_FLAG_PROCESS_CONTINUING)) + return GDB_SendPacket(ctx, "S02", 3); + else + { + ctx->flags &= ~GDB_FLAG_PROCESS_CONTINUING; + return 0; + } +} + +static void GDB_ContinueExecution(GDBContext *ctx) +{ + ctx->selectedThreadId = ctx->selectedThreadIdForContinuing = 0; + svcContinueDebugEvent(ctx->debug, ctx->continueFlags); + ctx->flags |= GDB_FLAG_PROCESS_CONTINUING; +} + +GDB_DECLARE_HANDLER(Continue) +{ + char *addrStart = NULL; + u32 addr = 0; + + if(ctx->selectedThreadIdForContinuing != 0 && ctx->selectedThreadIdForContinuing != ctx->currentThreadId) + return 0; + + if(ctx->commandData[-1] == 'C') + { + if(ctx->commandData[0] == 0 || ctx->commandData[1] == 0 || (ctx->commandData[2] != 0 && ctx->commandData[2] == ';')) + return GDB_ReplyErrno(ctx, EILSEQ); + + // Signal ignored... + + if(ctx->commandData[2] == ';') + addrStart = ctx->commandData + 3; + } + else + { + if(ctx->commandData[0] != 0) + addrStart = ctx->commandData; + } + + if(addrStart != NULL && ctx->currentThreadId != 0) + { + ThreadContext regs; + if(GDB_ParseHexIntegerList(&addr, ctx->commandData + 3, 1, 0) == NULL) + return GDB_ReplyErrno(ctx, EILSEQ); + + Result r = svcGetDebugThreadContext(®s, ctx->debug, ctx->currentThreadId, THREADCONTEXT_CONTROL_CPU_SPRS); + if(R_SUCCEEDED(r)) + { + regs.cpu_registers.pc = addr; + r = svcSetDebugThreadContext(ctx->debug, ctx->currentThreadId, ®s, THREADCONTEXT_CONTROL_CPU_SPRS); + } + } + + GDB_ContinueExecution(ctx); + return 0; +} + +GDB_DECLARE_VERBOSE_HANDLER(Continue) +{ + char *pos = ctx->commandData; + bool currentThreadFound = false; + while(pos != NULL && *pos != 0 && !currentThreadFound) + { + if(*pos != 'c' && *pos != 'C') + return GDB_ReplyErrno(ctx, EPERM); + + pos += *pos == 'C' ? 3 : 1; + + if(*pos++ != ':') // default action found + { + currentThreadFound = true; + break; + } + + char *nextpos = (char *)strchr(pos, ';'); + if(strncmp(pos, "-1", 2) == 0) + currentThreadFound = true; + else + { + u32 threadId; + if(GDB_ParseHexIntegerList(&threadId, pos, 1, ';') == NULL) + return GDB_ReplyErrno(ctx, EILSEQ); + currentThreadFound = currentThreadFound || threadId == ctx->currentThreadId; + } + + pos = nextpos; + } + + if(ctx->currentThreadId == 0 || currentThreadFound) + GDB_ContinueExecution(ctx); + + return 0; +} + +GDB_DECLARE_HANDLER(GetStopReason) +{ + return GDB_SendStopReply(ctx, &ctx->latestDebugEvent); +} + +static int GDB_ParseCommonThreadInfo(char *out, GDBContext *ctx, int sig) +{ + u32 threadId = ctx->currentThreadId; + ThreadContext regs; + s64 dummy; + u32 core; + Result r = svcGetDebugThreadContext(®s, ctx->debug, threadId, THREADCONTEXT_CONTROL_ALL); + int n = sprintf(out, "T%02xthread:%x;", sig, threadId); + + if(R_FAILED(r)) + return n; + + r = svcGetDebugThreadParam(&dummy, &core, ctx->debug, ctx->currentThreadId, DBGTHREAD_PARAMETER_CPU_CREATOR); // Creator = "first ran, and running the thread" + + if(R_SUCCEEDED(r)) + n += sprintf(out + n, "core:%x;", core); + + if(ctx->isGDB) + { + for(u32 i = 0; i <= 12; i++) + n += sprintf(out + n, "%x:%08x;", i, __builtin_bswap32(regs.cpu_registers.r[i])); + } + n += sprintf(out + n, "d:%08x;e:%08x;f:%08x;19:%08x;", + __builtin_bswap32(regs.cpu_registers.sp), __builtin_bswap32(regs.cpu_registers.lr), __builtin_bswap32(regs.cpu_registers.pc), + __builtin_bswap32(regs.cpu_registers.cpsr)); + + if(ctx->isGDB) + { + for(u32 i = 0; i < 16; i++) + { + u64 val; + memcpy(&val, ®s.fpu_registers.d[i], 8); + n += sprintf(out + n, "%x:%016llx;", 26 + i, __builtin_bswap64(val)); + } + + n += sprintf(out + n, "2a:%08x;2b:%08x;", __builtin_bswap32(regs.fpu_registers.fpscr), __builtin_bswap32(regs.fpu_registers.fpexc)); + } + return n; +} + +void GDB_PreprocessDebugEvent(GDBContext *ctx, DebugEventInfo *info) +{ + switch(info->type) + { + case DBGEVENT_ATTACH_THREAD: + { + if(ctx->nbThreads == MAX_DEBUG_THREAD) + svcBreak(USERBREAK_ASSERT); + else + { + ctx->threadInfos[ctx->nbThreads].id = info->thread_id; + ctx->threadInfos[ctx->nbThreads++].tls = info->attach_thread.thread_local_storage; + } + + break; + } + + case DBGEVENT_EXIT_THREAD: + { + u32 i; + for(i = 0; i < ctx->nbThreads && ctx->threadInfos[i].id != info->thread_id; i++); + if(i == ctx->nbThreads || ctx->threadInfos[i].id != info->thread_id) + svcBreak(USERBREAK_ASSERT); + else + { + for(u32 j = i; j < ctx->nbThreads - 1; j++) + memcpy(ctx->threadInfos + j, ctx->threadInfos + j + 1, sizeof(ThreadInfo)); + memset(ctx->threadInfos + --ctx->nbThreads, 0, sizeof(ThreadInfo)); + } + + break; + } + + case DBGEVENT_EXIT_PROCESS: + { + ctx->processEnded = true; + ctx->processExited = info->exit_process.reason == EXITPROCESS_EVENT_EXIT; + + break; + } + + case DBGEVENT_OUTPUT_STRING: + { + if(info->output_string.string_addr >= 0xFFFFFFFE) + { + u32 sz = info->output_string.string_size, addr = info->output_string.string_addr, threadId = info->thread_id; + memset(info, 0, sizeof(DebugEventInfo)); + info->type = (addr == 0xFFFFFFFF) ? DBGEVENT_SYSCALL_OUT : DBGEVENT_SYSCALL_IN; + info->thread_id = threadId; + info->flags = 1; + info->syscall.syscall = sz; + } + + break; + } + + case DBGEVENT_EXCEPTION: + { + switch(info->exception.type) + { + case EXCEVENT_UNDEFINED_INSTRUCTION: + { + // kernel bugfix for thumb mode + ThreadContext regs; + Result r = svcGetDebugThreadContext(®s, ctx->debug, info->thread_id, THREADCONTEXT_CONTROL_CPU_SPRS); + if(R_SUCCEEDED(r) && (regs.cpu_registers.cpsr & 0x20) != 0) + { + regs.cpu_registers.pc += 2; + r = svcSetDebugThreadContext(ctx->debug, info->thread_id, ®s, THREADCONTEXT_CONTROL_CPU_SPRS); + } + + break; + } + + default: + break; + } + } + default: + break; + } +} + +int GDB_SendStopReply(GDBContext *ctx, const DebugEventInfo *info) +{ + char buffer[GDB_BUF_LEN + 1]; + + switch(info->type) + { + case DBGEVENT_ATTACH_PROCESS: + break; // Dismissed + + case DBGEVENT_ATTACH_THREAD: + { + if(info->attach_thread.creator_thread_id == 0 || !ctx->catchThreadEvents) + break; // Dismissed + else + { + ctx->currentThreadId = info->thread_id; + return GDB_SendPacket(ctx, "T05create:;", 10); + } + } + + case DBGEVENT_EXIT_THREAD: + { + if(ctx->catchThreadEvents && info->exit_thread.reason < EXITTHREAD_EVENT_EXIT_PROCESS) + { + // no signal, SIGTERM, SIGQUIT (process exited), SIGTERM (process terminated) + static int threadExitRepliesSigs[] = { 0, SIGTERM, SIGQUIT, SIGTERM }; + return GDB_SendFormattedPacket(ctx, "w%02x;%x", threadExitRepliesSigs[(u32)info->exit_thread.reason], info->thread_id); + } + break; + } + + case DBGEVENT_EXIT_PROCESS: + { + // exited (no error / unhandled exception), SIGTERM (process terminated) * 2 + static const char *processExitReplies[] = { "W00", "X0f", "X0f" }; + return GDB_SendPacket(ctx, processExitReplies[(u32)info->exit_process.reason], 3); + } + + case DBGEVENT_EXCEPTION: + { + ExceptionEvent exc = info->exception; + + switch(exc.type) + { + case EXCEVENT_UNDEFINED_INSTRUCTION: + case EXCEVENT_PREFETCH_ABORT: // doesn't include hardware breakpoints + case EXCEVENT_DATA_ABORT: // doesn't include hardware watchpoints + case EXCEVENT_UNALIGNED_DATA_ACCESS: + case EXCEVENT_UNDEFINED_SYSCALL: + { + u32 signum = exc.type == EXCEVENT_UNDEFINED_INSTRUCTION ? SIGILL : + (exc.type == EXCEVENT_UNDEFINED_SYSCALL ? SIGSYS : SIGSEGV); + + ctx->currentThreadId = info->thread_id; + GDB_ParseCommonThreadInfo(buffer, ctx, signum); + return GDB_SendFormattedPacket(ctx, "%s", buffer); + } + + case EXCEVENT_ATTACH_BREAK: + return GDB_SendPacket(ctx, "S00", 3); + + case EXCEVENT_STOP_POINT: + { + ctx->currentThreadId = info->thread_id; + + switch(exc.stop_point.type) + { + case STOPPOINT_SVC_FF: + { + GDB_ParseCommonThreadInfo(buffer, ctx, SIGTRAP); + return GDB_SendFormattedPacket(ctx, "%sswbreak:;", buffer); + break; + } + + case STOPPOINT_BREAKPOINT: + { + // /!\ Not actually implemented (and will never be) + GDB_ParseCommonThreadInfo(buffer, ctx, SIGTRAP); + return GDB_SendFormattedPacket(ctx, "%shwbreak:;", buffer); + break; + } + + case STOPPOINT_WATCHPOINT: + { + const char *kinds = "arwa"; + WatchpointKind kind = GDB_GetWatchpointKind(ctx, exc.stop_point.fault_information); + if(kind == WATCHPOINT_DISABLED) + GDB_SendDebugString(ctx, "Warning: unknown watchpoint encountered!\n"); + + GDB_ParseCommonThreadInfo(buffer, ctx, SIGTRAP); + return GDB_SendFormattedPacket(ctx, "%s%cwatch:%08x;", buffer, kinds[(u32)kind], exc.stop_point.fault_information); + break; + } + + default: + break; + } + } + + case EXCEVENT_USER_BREAK: + { + ctx->currentThreadId = info->thread_id; + GDB_ParseCommonThreadInfo(buffer, ctx, SIGINT); + return GDB_SendFormattedPacket(ctx, "%s", buffer); + //TODO + } + + case EXCEVENT_DEBUGGER_BREAK: + { + u32 threadIds[4]; + u32 nbThreads = 0; + + for(u32 i = 0; i < 4; i++) + { + if(exc.debugger_break.thread_ids[i] > 0) + threadIds[nbThreads++] = (u32)exc.debugger_break.thread_ids[i]; + } + + u32 currentThreadId = nbThreads > 0 ? GDB_GetCurrentThreadFromList(ctx, threadIds, nbThreads) : GDB_GetCurrentThread(ctx); + s64 dummy; + u32 mask = 0; + + svcGetDebugThreadParam(&dummy, &mask, ctx->debug, currentThreadId, DBGTHREAD_PARAMETER_SCHEDULING_MASK_LOW); + + if(mask == 1) + { + ctx->currentThreadId = currentThreadId; + GDB_ParseCommonThreadInfo(buffer, ctx, SIGINT); + return GDB_SendFormattedPacket(ctx, "%s", buffer); + } + else + return GDB_SendPacket(ctx, "S02", 3); + } + + default: + break; + } + } + + case DBGEVENT_SYSCALL_IN: + { + ctx->currentThreadId = info->thread_id; + GDB_ParseCommonThreadInfo(buffer, ctx, SIGTRAP); + return GDB_SendFormattedPacket(ctx, "%ssyscall_entry:%02x;", buffer, info->syscall.syscall); + } + + case DBGEVENT_SYSCALL_OUT: + { + ctx->currentThreadId = info->thread_id; + GDB_ParseCommonThreadInfo(buffer, ctx, SIGTRAP); + return GDB_SendFormattedPacket(ctx, "%ssyscall_return:%02x;", buffer, info->syscall.syscall); + } + + case DBGEVENT_OUTPUT_STRING: + { + u32 addr = info->output_string.string_addr; + u32 remaining = info->output_string.string_size; + u32 sent = 0; + int total = 0; + while(remaining > 0) + { + u32 pending = (GDB_BUF_LEN - 1) / 2; + pending = pending < remaining ? pending : remaining; + + int res = GDB_SendMemory(ctx, "O", 1, addr + sent, pending); + if(res < 0 || (u32) res != 5 + 2 * pending) + break; + + sent += pending; + remaining -= pending; + total += res; + } + + return total; + } + default: + break; + } + + return 0; +} + +/* + Only 1 blocking event can be enqueued at a time: they preempt all the other threads. + The only "non-blocking" event that is implemented is EXIT PROCESS (but it's a very special case) +*/ +int GDB_HandleDebugEvents(GDBContext *ctx) +{ + if(ctx->state == GDB_STATE_CLOSING) + return -1; + + DebugEventInfo info; + Result rdbg = svcGetProcessDebugEvent(&info, ctx->debug); + + if(R_FAILED(rdbg)) + return -1; + + GDB_PreprocessDebugEvent(ctx, &info); + + int ret = 0; + bool continueAutomatically = info.type == DBGEVENT_OUTPUT_STRING || info.type == DBGEVENT_ATTACH_PROCESS || + (info.type == DBGEVENT_ATTACH_THREAD && (info.attach_thread.creator_thread_id == 0 || !ctx->catchThreadEvents)) || + (info.type == DBGEVENT_EXIT_THREAD && (info.exit_thread.reason >= EXITTHREAD_EVENT_EXIT_PROCESS || !ctx->catchThreadEvents)) || + info.type == DBGEVENT_EXIT_PROCESS || !(info.flags & 1); + + + if(continueAutomatically) + { + Result r = 0; + ret = GDB_SendStopReply(ctx, &info); + if(info.flags & 1) + r = svcContinueDebugEvent(ctx->debug, ctx->continueFlags); + + if(r == (Result)0xD8A02008) // process ended + return -2; + + return -ret - 3; + } + else + { + int ret; + + if(ctx->processEnded) + return -2; + + ctx->latestDebugEvent = info; + ret = GDB_SendStopReply(ctx, &info); + ctx->flags &= ~GDB_FLAG_PROCESS_CONTINUING; + return ret; + } +} diff --git a/sysmodules/rosalina/source/gdb/mem.c b/sysmodules/rosalina/source/gdb/mem.c new file mode 100644 index 000000000..c65cf13c5 --- /dev/null +++ b/sysmodules/rosalina/source/gdb/mem.c @@ -0,0 +1,292 @@ +/* +* 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 . +* +* 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. +*/ + +#include "gdb/mem.h" +#include "gdb/net.h" +#include "utils.h" + +static void *k_memcpy_no_interrupt(void *dst, const void *src, u32 len) +{ + __asm__ volatile("cpsid aif"); + return memcpy(dst, src, len); +} + +Result GDB_ReadMemoryInPage(void *out, GDBContext *ctx, u32 addr, u32 len) +{ + s64 TTBCR; + svcGetSystemInfo(&TTBCR, 0x10002, 0); + + if(addr < (1u << (32 - (u32)TTBCR))) + return svcReadProcessMemory(out, ctx->debug, addr, len); + else if(addr >= 0x80000000 && addr < 0xB0000000) + { + memcpy(out, (const void *)addr, len); + return 0; + } + else + { + u32 PA = svcConvertVAToPA((const void *)addr, false); + + if(PA == 0) + return -1; + else + { + svcCustomBackdoor(k_memcpy_no_interrupt, out, (const void *)addr, len); + return 0; + } + } +} + +Result GDB_WriteMemoryInPage(GDBContext *ctx, const void *in, u32 addr, u32 len) +{ + s64 TTBCR; + svcGetSystemInfo(&TTBCR, 0x10002, 0); + + if(addr < (1u << (32 - (u32)TTBCR))) + return svcWriteProcessMemory(ctx->debug, in, addr, len); // not sure if it checks if it's IO or not. It probably does + + else if(addr >= 0x80000000 && addr < 0xB0000000) + { + memcpy((void *)addr, in, len); + return 0; + } + else + { + u32 PA = svcConvertVAToPA((const void *)addr, true); + + if(PA != 0) + { + svcCustomBackdoor(k_memcpy_no_interrupt, (void *)addr, in, len); + return 0; + } + else + { + // Unreliable, use at your own risk + + svcFlushEntireDataCache(); + svcInvalidateEntireInstructionCache(); + Result ret = GDB_WriteMemoryInPage(ctx, PA_FROM_VA_PTR(in), addr, len); + svcFlushEntireDataCache(); + svcInvalidateEntireInstructionCache(); + return ret; + } + } +} + +int GDB_SendMemory(GDBContext *ctx, const char *prefix, u32 prefixLen, u32 addr, u32 len) +{ + char buf[GDB_BUF_LEN]; + u8 membuf[GDB_BUF_LEN / 2]; + + if(prefix != NULL) + memcpy(buf, prefix, prefixLen); + else + prefixLen = 0; + + if(prefixLen + 2 * len > GDB_BUF_LEN) // gdb shouldn't send requests which responses don't fit in a packet + return prefix == NULL ? GDB_ReplyErrno(ctx, ENOMEM) : -1; + + Result r = 0; + u32 remaining = len, total = 0; + do + { + u32 nb = (remaining > 0x1000 - (addr & 0xFFF)) ? 0x1000 - (addr & 0xFFF) : remaining; + r = GDB_ReadMemoryInPage(membuf + total, ctx, addr, nb); + if(R_SUCCEEDED(r)) + { + addr += nb; + total += nb; + remaining -= nb; + } + } + while(remaining > 0 && R_SUCCEEDED(r)); + + if(total == 0) + return prefix == NULL ? GDB_ReplyErrno(ctx, EFAULT) : -EFAULT; + else + { + GDB_EncodeHex(buf + prefixLen, membuf, total); + return GDB_SendPacket(ctx, buf, prefixLen + 2 * total); + } +} + +int GDB_WriteMemory(GDBContext *ctx, const void *buf, u32 addr, u32 len) +{ + Result r = 0; + u32 remaining = len, total = 0; + do + { + u32 nb = (remaining > 0x1000 - (addr & 0xFFF)) ? 0x1000 - (addr & 0xFFF) : remaining; + r = GDB_WriteMemoryInPage(ctx, (u8 *)buf + total, addr, nb); + if(R_SUCCEEDED(r)) + { + addr += nb; + total += nb; + remaining -= nb; + } + } + while(remaining > 0 && R_SUCCEEDED(r)); + + if(R_FAILED(r)) + return GDB_ReplyErrno(ctx, EFAULT); + else + return GDB_ReplyOk(ctx); +} + +u32 GDB_SearchMemory(bool *found, GDBContext *ctx, u32 addr, u32 len, const void *pattern, u32 patternLen) +{ + u8 buf[0x1000 + 0x1000 * ((GDB_BUF_LEN + 0xFFF) / 0x1000)]; + u32 maxNbPages = 1 + ((GDB_BUF_LEN + 0xFFF) / 0x1000); + u32 curAddr = addr; + + s64 TTBCR; + svcGetSystemInfo(&TTBCR, 0x10002, 0); + while(curAddr < addr + len) + { + u32 nbPages; + u32 addrBase = curAddr & ~0xFFF, addrDispl = curAddr & 0xFFF; + + for(nbPages = 0; nbPages < maxNbPages; nbPages++) + { + if(addr >= (1u << (32 - (u32)TTBCR))) + { + u32 PA = svcConvertVAToPA((const void *)addr, false); + if(PA == 0 || (PA >= 0x10000000 && PA <= 0x18000000)) + break; + } + + if(R_FAILED(GDB_ReadMemoryInPage(buf + 0x1000 * nbPages, ctx, addrBase + nbPages * 0x1000, 0x1000))) + break; + } + + u8 *pos = NULL; + if(addrDispl + patternLen <= 0x1000 * nbPages) + pos = memsearch(buf + addrDispl, pattern, 0x1000 * nbPages - addrDispl, patternLen); + + if(pos != NULL) + { + *found = true; + return addrBase + (pos - buf); + } + + curAddr = addrBase + 0x1000; + } + + *found = false; + return 0; +} + +GDB_DECLARE_HANDLER(ReadMemory) +{ + u32 lst[2]; + if(GDB_ParseHexIntegerList(lst, ctx->commandData, 2, 0) == NULL) + return GDB_ReplyErrno(ctx, EILSEQ); + + u32 addr = lst[0]; + u32 len = lst[1]; + + return GDB_SendMemory(ctx, NULL, 0, addr, len); +} + +GDB_DECLARE_HANDLER(WriteMemory) +{ + u32 lst[2]; + const char *dataStart = GDB_ParseHexIntegerList(lst, ctx->commandData, 2, ':'); + if(dataStart == NULL || *dataStart != ':') + return GDB_ReplyErrno(ctx, EILSEQ); + + dataStart++; + u32 addr = lst[0]; + u32 len = lst[1]; + + if(dataStart + 2 * len >= ctx->buffer + 4 + GDB_BUF_LEN) + return GDB_ReplyErrno(ctx, ENOMEM); + + u8 data[GDB_BUF_LEN / 2]; + u32 n = GDB_DecodeHex(data, dataStart, len); + + if(n != len) + return GDB_ReplyErrno(ctx, EILSEQ); + + return GDB_WriteMemory(ctx, data, addr, len); +} + +GDB_DECLARE_HANDLER(WriteMemoryRaw) +{ + u32 lst[2]; + const char *dataStart = GDB_ParseHexIntegerList(lst, ctx->commandData, 2, ':'); + if(dataStart == NULL || *dataStart != ':') + return GDB_ReplyErrno(ctx, EILSEQ); + + dataStart++; + u32 addr = lst[0]; + u32 len = lst[1]; + + if(dataStart + len >= ctx->buffer + 4 + GDB_BUF_LEN) + return GDB_ReplyErrno(ctx, ENOMEM); + + u8 data[GDB_BUF_LEN]; + u32 n = GDB_UnescapeBinaryData(data, dataStart, len); + + if(n != len) + return GDB_ReplyErrno(ctx, n); + + return GDB_WriteMemory(ctx, data, addr, len); +} + +GDB_DECLARE_QUERY_HANDLER(SearchMemory) +{ + u32 lst[2]; + u32 addr, len; + u8 pattern[GDB_BUF_LEN]; + const char *patternStart; + u32 patternLen; + bool found; + u32 foundAddr; + + if(strncmp(ctx->commandData, "memory:", 7) != 0) + return GDB_ReplyErrno(ctx, EILSEQ); + + ctx->commandData += 7; + patternStart = GDB_ParseIntegerList(lst, ctx->commandData, 2, ';', ';', 16, false); + if(patternStart == NULL || *patternStart != ';') + return GDB_ReplyErrno(ctx, EILSEQ); + + addr = lst[0]; + len = lst[1]; + + patternStart++; + patternLen = ctx->commandEnd - patternStart; + + patternLen = GDB_UnescapeBinaryData(pattern, patternStart, patternLen); + + foundAddr = GDB_SearchMemory(&found, ctx, addr, len, patternStart, patternLen); + + if(found) + return GDB_SendFormattedPacket(ctx, "1,%x", foundAddr); + else + return GDB_SendPacket(ctx, "0", 1); +} diff --git a/sysmodules/rosalina/source/gdb/monitor.c b/sysmodules/rosalina/source/gdb/monitor.c new file mode 100644 index 000000000..76ca80679 --- /dev/null +++ b/sysmodules/rosalina/source/gdb/monitor.c @@ -0,0 +1,94 @@ +/* +* 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 . +* +* 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. +*/ + +#include "gdb/monitor.h" +#include "gdb/net.h" +#include "gdb/debug.h" + +extern Handle terminationRequestEvent; +extern bool terminationRequest; + +void GDB_RunMonitor(GDBServer *server) +{ + Handle handles[3 + MAX_DEBUG]; + Result r = 0; + + handles[0] = terminationRequestEvent; + handles[1] = server->super.shall_terminate_event; + handles[2] = server->statusUpdated; + + do + { + for(int i = 0; i < MAX_DEBUG; i++) + { + GDBContext *ctx = &server->ctxs[i]; + handles[3 + i] = ctx->eventToWaitFor; + } + + s32 idx = -1; + r = svcWaitSynchronizationN(&idx, handles, 3 + MAX_DEBUG, false, -1LL); + + if(R_FAILED(r) || idx < 2) + break; + else if(idx == 2) + continue; + else + { + GDBContext *ctx = &server->ctxs[idx - 3]; + + RecursiveLock_Lock(&ctx->lock); + if(ctx->state == GDB_STATE_DISCONNECTED || ctx->state == GDB_STATE_CLOSING) + { + svcClearEvent(ctx->clientAcceptedEvent); + ctx->eventToWaitFor = ctx->clientAcceptedEvent; + RecursiveLock_Unlock(&ctx->lock); + continue; + } + + if(ctx->eventToWaitFor == ctx->clientAcceptedEvent) + ctx->eventToWaitFor = ctx->continuedEvent; + else if(ctx->eventToWaitFor == ctx->continuedEvent) + ctx->eventToWaitFor = ctx->debug; + else + { + int res = GDB_HandleDebugEvents(ctx); + if(res >= 0) + ctx->eventToWaitFor = ctx->continuedEvent; + else if(res == -2) + { + while(GDB_HandleDebugEvents(ctx) != -1) // until we've got all the remaining debug events + svcSleepThread(1 * 1000 * 1000LL); // sleep just in case + + svcClearEvent(ctx->clientAcceptedEvent); + ctx->eventToWaitFor = ctx->clientAcceptedEvent; + } + } + + RecursiveLock_Unlock(&ctx->lock); + } + } + while(!terminationRequest && server->super.running); +} diff --git a/sysmodules/rosalina/source/gdb/net.c b/sysmodules/rosalina/source/gdb/net.c new file mode 100644 index 000000000..0bad8e367 --- /dev/null +++ b/sysmodules/rosalina/source/gdb/net.c @@ -0,0 +1,332 @@ +/* +* 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 . +* +* 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. +*/ + +#include "gdb/net.h" +#include +#include +#include "fmt.h" +#include "minisoc.h" + +u8 GDB_ComputeChecksum(const char *packetData, u32 len) +{ + u8 cksum = 0; + for(u32 i = 0; i < len; i++) + cksum += (u8)packetData[i]; + + return cksum; +} + +void GDB_EncodeHex(char *dst, const void *src, u32 len) +{ + static const char *alphabet = "0123456789abcdef"; + const u8 *src8 = (u8 *)src; + + for(u32 i = 0; i < len; i++) + { + dst[2 * i] = alphabet[(src8[i] & 0xf0) >> 4]; + dst[2 * i + 1] = alphabet[src8[i] & 0x0f]; + } +} + +static inline u32 GDB_DecodeHexDigit(char src, bool *ok) +{ + *ok = true; + if(src >= '0' && src <= '9') return src - '0'; + else if(src >= 'a' && src <= 'f') return 0xA + (src - 'a'); + else if(src >= 'A' && src <= 'F') return 0xA + (src - 'A'); + else + { + *ok = false; + return 0; + } +} + +u32 GDB_DecodeHex(void *dst, const char *src, u32 len) +{ + u32 i = 0; + bool ok = true; + u8 *dst8 = (u8 *)dst; + for(i = 0; i < len && ok && src[2 * i] != 0 && src[2 * i + 1] != 0; i++) + dst8[i] = (GDB_DecodeHexDigit(src[2 * i], &ok) << 4) | GDB_DecodeHexDigit(src[2 * i + 1], &ok); + + return (!ok) ? i - 1 : i; +} + +u32 GDB_UnescapeBinaryData(void *dst, const void *src, u32 len) +{ + u8 *dst8 = (u8 *)dst; + const u8 *src8 = (const u8 *)src; + + for(u32 i = 0; i < len; i++) + { + if(*src8 == '}') + { + src8++; + *dst8++ = *src8++ ^ 0x20; + } + else + *dst8++ = *src8++; + } + + return dst8 - (u8 *)dst; +} + +const char *GDB_ParseIntegerList(u32 *dst, const char *src, u32 nb, char sep, char lastSep, u32 base, bool allowPrefix) +{ + const char *pos = src; + const char *endpos; + bool ok; + + for(u32 i = 0; i < nb; i++) + { + u32 n = xstrtoul(pos, (char **)&endpos, (int) base, allowPrefix, &ok); + if(!ok || endpos == pos) + return NULL; + + if(i != nb - 1) + { + if(*endpos != sep) + return NULL; + pos = endpos + 1; + } + else + { + if(*endpos != lastSep && *endpos != 0) + return NULL; + pos = endpos; + } + + dst[i] = n; + } + + return pos; +} + +const char *GDB_ParseHexIntegerList(u32 *dst, const char *src, u32 nb, char lastSep) +{ + return GDB_ParseIntegerList(dst, src, nb, ',', lastSep, 16, false); +} + +int GDB_ReceivePacket(GDBContext *ctx) +{ + char backupbuf[GDB_BUF_LEN + 4]; + memcpy(backupbuf, ctx->buffer, ctx->latestSentPacketSize); + memset(ctx->buffer, 0, sizeof(ctx->buffer)); + + int r = soc_recv(ctx->super.sockfd, ctx->buffer, sizeof(ctx->buffer), MSG_PEEK); + if(r < 1) + return -1; + if(ctx->buffer[0] == '+') // GDB sometimes acknowleges TCP acknowledgment packets (yes...). IDA does it properly + { + if(ctx->state == GDB_STATE_NOACK) + return -1; + + // Consume it + r = soc_recv(ctx->super.sockfd, ctx->buffer, 1, 0); + if(r != 1) + return -1; + + ctx->buffer[0] = 0; + + r = soc_recv(ctx->super.sockfd, ctx->buffer, sizeof(ctx->buffer), MSG_PEEK); + + if(r == -1) + goto packet_error; + } + else if(ctx->buffer[0] == '-') + { + soc_send(ctx->super.sockfd, backupbuf, ctx->latestSentPacketSize, 0); + return 0; + } + int maxlen = r > (int)sizeof(ctx->buffer) ? (int)sizeof(ctx->buffer) : r; + + if(ctx->buffer[0] == '$') // normal packet + { + char *pos; + for(pos = ctx->buffer; pos < ctx->buffer + maxlen && *pos != '#'; pos++); + + if(pos == ctx->buffer + maxlen) // malformed packet + return -1; + + else + { + u8 checksum; + r = soc_recv(ctx->super.sockfd, ctx->buffer, 3 + pos - ctx->buffer, 0); + if(r != 3 + pos - ctx->buffer || GDB_DecodeHex(&checksum, pos + 1, 1) != 1) + goto packet_error; + else if(GDB_ComputeChecksum(ctx->buffer + 1, pos - ctx->buffer - 1) != checksum) + goto packet_error; + + ctx->commandEnd = pos; + *pos = 0; // replace trailing '#' by a NUL character + } + } + else if(ctx->buffer[0] == '\x03') + { + r = soc_recv(ctx->super.sockfd, ctx->buffer, 1, 0); + if(r != 1) + goto packet_error; + + ctx->commandEnd = ctx->buffer; + } + + if(ctx->state >= GDB_STATE_CONNECTED && ctx->state < GDB_STATE_NOACK) + { + int r2 = soc_send(ctx->super.sockfd, "+", 1, 0); + if(r2 != 1) + return -1; + } + + if(ctx->state == GDB_STATE_NOACK_SENT) + ctx->state = GDB_STATE_NOACK; + + return r; + +packet_error: + if(ctx->state >= GDB_STATE_CONNECTED && ctx->state < GDB_STATE_NOACK) + { + r = soc_send(ctx->super.sockfd, "-", 1, 0); + if(r != 1) + return -1; + else + return 0; + } + else + return -1; +} + +static int GDB_DoSendPacket(GDBContext *ctx, u32 len) +{ + int r = soc_send(ctx->super.sockfd, ctx->buffer, len, 0); + + if(r > 0) + ctx->latestSentPacketSize = r; + return r; +} + +int GDB_SendPacket(GDBContext *ctx, const char *packetData, u32 len) +{ + ctx->buffer[0] = '$'; + + memcpy(ctx->buffer + 1, packetData, len); + + char *checksumLoc = ctx->buffer + len + 1; + *checksumLoc++ = '#'; + + hexItoa(GDB_ComputeChecksum(packetData, len), checksumLoc, 2, false); + return GDB_DoSendPacket(ctx, 4 + len); +} + +int GDB_SendFormattedPacket(GDBContext *ctx, const char *packetDataFmt, ...) +{ + // It goes without saying you shouldn't use that with user-controlled data... + char buf[GDB_BUF_LEN + 1]; + va_list args; + va_start(args, packetDataFmt); + int n = vsprintf(buf, packetDataFmt, args); + va_end(args); + + if(n < 0) return -1; + else return GDB_SendPacket(ctx, buf, (u32)n); +} + +int GDB_SendHexPacket(GDBContext *ctx, const void *packetData, u32 len) +{ + if(4 + 2 * len > GDB_BUF_LEN) + return -1; + + ctx->buffer[0] = '$'; + GDB_EncodeHex(ctx->buffer + 1, packetData, len); + + char *checksumLoc = ctx->buffer + 2 * len + 1; + *checksumLoc++ = '#'; + + hexItoa(GDB_ComputeChecksum(ctx->buffer + 1, 2 * len), checksumLoc, 2, false); + return GDB_DoSendPacket(ctx, 4 + 2 * len); +} + +int GDB_SendStreamData(GDBContext *ctx, const char *streamData, u32 offset, u32 length, u32 totalSize, bool forceEmptyLast) +{ + char buf[GDB_BUF_LEN]; + if(length > GDB_BUF_LEN - 1) + length = GDB_BUF_LEN - 1; + + if((forceEmptyLast && offset >= totalSize) || (!forceEmptyLast && offset + length >= totalSize)) + { + length = totalSize - offset; + buf[0] = 'l'; + memcpy(buf + 1, streamData + offset, length); + return GDB_SendPacket(ctx, buf, 1 + length); + } + else + { + buf[0] = 'm'; + memcpy(buf + 1, streamData + offset, length); + return GDB_SendPacket(ctx, buf, 1 + length); + } +} + +int GDB_SendDebugString(GDBContext *ctx, const char *fmt, ...) // unsecure +{ + if(ctx->state == GDB_STATE_CLOSING || !(ctx->flags & GDB_FLAG_PROCESS_CONTINUING)) + return 0; + + char formatted[(GDB_BUF_LEN - 1) / 2 + 1]; + ctx->buffer[0] = '$'; + ctx->buffer[1] = 'O'; + + va_list args; + va_start(args, fmt); + int n = vsprintf(formatted, fmt, args); + va_end(args); + + if(n <= 0) return n; + GDB_EncodeHex(ctx->buffer + 2, formatted, 2 * n); + + char *checksumLoc = ctx->buffer + 2 * n + 2; + *checksumLoc++ = '#'; + + hexItoa(GDB_ComputeChecksum(ctx->buffer + 1, 2 * n + 1), checksumLoc, 2, false); + + return GDB_DoSendPacket(ctx, 5 + 2 * n); +} + +int GDB_ReplyEmpty(GDBContext *ctx) +{ + return GDB_SendPacket(ctx, "", 0); +} + +int GDB_ReplyOk(GDBContext *ctx) +{ + return GDB_SendPacket(ctx, "OK", 2); +} + +int GDB_ReplyErrno(GDBContext *ctx, int no) +{ + char buf[] = "E01"; + hexItoa((u8)no, buf + 1, 2, false); + return GDB_SendPacket(ctx, buf, 3); +} diff --git a/sysmodules/rosalina/source/gdb/query.c b/sysmodules/rosalina/source/gdb/query.c new file mode 100644 index 000000000..f41e66375 --- /dev/null +++ b/sysmodules/rosalina/source/gdb/query.c @@ -0,0 +1,162 @@ +/* +* 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 . +* +* 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. +*/ + +#include "gdb/query.h" +#include "gdb/xfer.h" +#include "gdb/thread.h" +#include "gdb/mem.h" +#include "gdb/net.h" +#include "gdb/remote_command.h" + +typedef enum GDBQueryDirection +{ + GDB_QUERY_DIRECTION_READ, + GDB_QUERY_DIRECTION_WRITE +} GDBQueryDirection; + +// https://gcc.gnu.org/onlinedocs/gcc-5.3.0/cpp/Stringification.html +#define xstr(s) str(s) +#define str(s) #s + +#define GDB_QUERY_HANDLER_LIST_ITEM_3(name, name2, direction) { name, GDB_QUERY_HANDLER(name2), GDB_QUERY_DIRECTION_##direction } +#define GDB_QUERY_HANDLER_LIST_ITEM(name, direction) GDB_QUERY_HANDLER_LIST_ITEM_3(xstr(name), name, direction) + +static const struct +{ + const char *name; + GDBCommandHandler handler; + GDBQueryDirection direction; +} gdbQueryHandlers[] = +{ + GDB_QUERY_HANDLER_LIST_ITEM(Supported, READ), + GDB_QUERY_HANDLER_LIST_ITEM(Xfer, READ), + GDB_QUERY_HANDLER_LIST_ITEM(StartNoAckMode, WRITE), + GDB_QUERY_HANDLER_LIST_ITEM(Attached, READ), + GDB_QUERY_HANDLER_LIST_ITEM(fThreadInfo, READ), + GDB_QUERY_HANDLER_LIST_ITEM(sThreadInfo, READ), + GDB_QUERY_HANDLER_LIST_ITEM(ThreadEvents, WRITE), + GDB_QUERY_HANDLER_LIST_ITEM(ThreadExtraInfo, READ), + GDB_QUERY_HANDLER_LIST_ITEM_3("C", CurrentThreadId, READ), + GDB_QUERY_HANDLER_LIST_ITEM_3("Search", SearchMemory, READ), + GDB_QUERY_HANDLER_LIST_ITEM(CatchSyscalls, WRITE), + GDB_QUERY_HANDLER_LIST_ITEM(Rcmd, READ), +}; + +static int GDB_HandleQuery(GDBContext *ctx, GDBQueryDirection direction) +{ + char *nameBegin = ctx->commandData; // w/o leading 'q'/'Q' + if(*nameBegin == 0) + return GDB_ReplyErrno(ctx, EILSEQ); + + char *nameEnd; + char *queryData = NULL; + + for(nameEnd = nameBegin; *nameEnd != 0 && *nameEnd != ':' && *nameEnd != ','; nameEnd++); + if(*nameEnd != 0) + { + *nameEnd = 0; + queryData = nameEnd + 1; + } + else + queryData = nameEnd; + + for(u32 i = 0; i < sizeof(gdbQueryHandlers) / sizeof(gdbQueryHandlers[0]); i++) + { + if(strcmp(gdbQueryHandlers[i].name, nameBegin) == 0 && gdbQueryHandlers[i].direction == direction) + { + ctx->commandData = queryData; + return gdbQueryHandlers[i].handler(ctx); + } + } + + return GDB_HandleUnsupported(ctx); // No handler found! +} + +int GDB_HandleReadQuery(GDBContext *ctx) +{ + return GDB_HandleQuery(ctx, GDB_QUERY_DIRECTION_READ); +} + +int GDB_HandleWriteQuery(GDBContext *ctx) +{ + return GDB_HandleQuery(ctx, GDB_QUERY_DIRECTION_WRITE); +} + +GDB_DECLARE_QUERY_HANDLER(Supported) +{ + return GDB_SendFormattedPacket(ctx, + "PacketSize=%x;" + "qXfer:features:read+;qXfer:osdata:read+;" + "QStartNoAckMode+;QThreadEvents+;QCatchSyscalls+;" + "vContSupported+;swbreak+", sizeof(ctx->buffer)); +} + +GDB_DECLARE_QUERY_HANDLER(StartNoAckMode) +{ + ctx->isGDB = true; + ctx->state = GDB_STATE_NOACK_SENT; + return GDB_ReplyOk(ctx); +} + +GDB_DECLARE_QUERY_HANDLER(Attached) +{ + return GDB_SendPacket(ctx, "1", 1); +} + +GDB_DECLARE_QUERY_HANDLER(CatchSyscalls) +{ + if(ctx->commandData[0] == '0') + { + memset(ctx->svcMask, 0, 32); + return R_SUCCEEDED(svcKernelSetState(0x10002, ctx->pid, false)) ? GDB_ReplyOk(ctx) : GDB_ReplyErrno(ctx, EPERM); + } + else if(ctx->commandData[0] == '1') + { + if(ctx->commandData[1] == ';') + { + u32 id; + const char *pos = ctx->commandData + 1; + memset(ctx->svcMask, 0, 32); + + do + { + pos = GDB_ParseHexIntegerList(&id, pos + 1, 1, ';'); + if(pos == NULL) + return GDB_ReplyErrno(ctx, EILSEQ); + + if(id < 0xFE) + ctx->svcMask[id / 32] |= 1 << (31 - (id % 32)); + } + while(*pos != 0); + } + else + memset(ctx->svcMask, 0xFF, 32); + + return R_SUCCEEDED(svcKernelSetState(0x10002, ctx->pid, true, ctx->svcMask)) ? GDB_ReplyOk(ctx) : GDB_ReplyErrno(ctx, EPERM); + } + else + return GDB_ReplyErrno(ctx, EILSEQ); +} diff --git a/sysmodules/rosalina/source/gdb/regs.c b/sysmodules/rosalina/source/gdb/regs.c new file mode 100644 index 000000000..1062ce2b1 --- /dev/null +++ b/sysmodules/rosalina/source/gdb/regs.c @@ -0,0 +1,172 @@ +/* +* 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 . +* +* 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. +*/ + +#include "gdb/regs.h" +#include "gdb/net.h" + +GDB_DECLARE_HANDLER(ReadRegisters) +{ + if(ctx->selectedThreadId == 0) + ctx->selectedThreadId = ctx->currentThreadId; + + ThreadContext regs; + Result r = svcGetDebugThreadContext(®s, ctx->debug, ctx->selectedThreadId, THREADCONTEXT_CONTROL_ALL); + + if(R_FAILED(r)) + return GDB_ReplyErrno(ctx, EPERM); + + return GDB_SendHexPacket(ctx, ®s, sizeof(ThreadContext)); +} + +GDB_DECLARE_HANDLER(WriteRegisters) +{ + if(ctx->selectedThreadId == 0) + ctx->selectedThreadId = ctx->currentThreadId; + + ThreadContext regs; + + if(GDB_DecodeHex(®s, ctx->commandData, sizeof(ThreadContext)) != sizeof(ThreadContext)) + return GDB_ReplyErrno(ctx, EPERM); + + Result r = svcSetDebugThreadContext(ctx->debug, ctx->selectedThreadId, ®s, THREADCONTEXT_CONTROL_ALL); + if(R_FAILED(r)) + return GDB_ReplyErrno(ctx, EPERM); + else + return GDB_ReplyOk(ctx); +} + +static u32 GDB_ConvertRegisterNumber(ThreadContextControlFlags *flags, u32 gdbNum) +{ + if(gdbNum <= 15) + { + *flags = (gdbNum >= 13) ? THREADCONTEXT_CONTROL_CPU_SPRS : THREADCONTEXT_CONTROL_CPU_GPRS; + return gdbNum; + } + else if(gdbNum == 25) + { + *flags = THREADCONTEXT_CONTROL_CPU_SPRS; + return 16; + } + else if(gdbNum >= 26 && gdbNum <= 41) + { + *flags = THREADCONTEXT_CONTROL_FPU_GPRS; + return gdbNum - 26; + } + else if(gdbNum == 42 || gdbNum == 43) + { + *flags = THREADCONTEXT_CONTROL_FPU_SPRS; + return gdbNum - 42; + } + else + { + *flags = (ThreadContextControlFlags)0; + return 0; + } +} + +GDB_DECLARE_HANDLER(ReadRegister) +{ + if(ctx->selectedThreadId == 0) + ctx->selectedThreadId = ctx->currentThreadId; + + ThreadContext regs; + ThreadContextControlFlags flags; + u32 gdbRegNum; + + if(GDB_ParseHexIntegerList(&gdbRegNum, ctx->commandData, 1, 0) == NULL) + return GDB_ReplyErrno(ctx, EILSEQ); + + u32 n = GDB_ConvertRegisterNumber(&flags, gdbRegNum); + if(!flags) + return GDB_ReplyErrno(ctx, EINVAL); + + Result r = svcGetDebugThreadContext(®s, ctx->debug, ctx->selectedThreadId, flags); + + if(R_FAILED(r)) + return GDB_ReplyErrno(ctx, EPERM); + + if(flags & THREADCONTEXT_CONTROL_CPU_GPRS) + return GDB_SendHexPacket(ctx, ®s.cpu_registers.r[n], 4); + else if(flags & THREADCONTEXT_CONTROL_CPU_SPRS) + return GDB_SendHexPacket(ctx, ®s.cpu_registers.sp + (n - 13), 4); // hacky + else if(flags & THREADCONTEXT_CONTROL_FPU_GPRS) + return GDB_SendHexPacket(ctx, ®s.fpu_registers.d[n], 8); + else + return GDB_SendHexPacket(ctx, ®s.fpu_registers.fpscr + n, 4); // hacky +} + +GDB_DECLARE_HANDLER(WriteRegister) +{ + if(ctx->selectedThreadId == 0) + ctx->selectedThreadId = ctx->currentThreadId; + + ThreadContext regs; + ThreadContextControlFlags flags; + u32 gdbRegNum; + + const char *valueStart = GDB_ParseHexIntegerList(&gdbRegNum, ctx->commandData, 1, '='); + if(valueStart == NULL || *valueStart != '=') + return GDB_ReplyErrno(ctx, EILSEQ); + + valueStart++; + + u32 n = GDB_ConvertRegisterNumber(&flags, gdbRegNum); + u32 value; + u64 value64; + + if(flags & THREADCONTEXT_CONTROL_FPU_GPRS) + { + if(GDB_DecodeHex(&value64, valueStart, 8) != 8 || valueStart[16] != 0) + return GDB_ReplyErrno(ctx, EINVAL); + } + else if(flags) + { + if(GDB_DecodeHex(&value, valueStart, 4) != 4 || valueStart[8] != 0) + return GDB_ReplyErrno(ctx, EINVAL); + } + else + return GDB_ReplyErrno(ctx, EINVAL); + + Result r = svcGetDebugThreadContext(®s, ctx->debug, ctx->selectedThreadId, flags); + + if(R_FAILED(r)) + return GDB_ReplyErrno(ctx, EPERM); + + if(flags & THREADCONTEXT_CONTROL_CPU_GPRS) + regs.cpu_registers.r[n] = value; + else if(flags & THREADCONTEXT_CONTROL_CPU_SPRS) + *(®s.cpu_registers.sp + (n - 13)) = value; // hacky + else if(flags & THREADCONTEXT_CONTROL_FPU_GPRS) + memcpy(®s.fpu_registers.d[n], &value64, 8); + else + *(®s.fpu_registers.fpscr + n) = value; // hacky + + r = svcSetDebugThreadContext(ctx->debug, ctx->selectedThreadId, ®s, flags); + if(R_FAILED(r)) + return GDB_ReplyErrno(ctx, EPERM); + else + return GDB_ReplyOk(ctx); +} diff --git a/sysmodules/rosalina/source/gdb/remote_command.c b/sysmodules/rosalina/source/gdb/remote_command.c new file mode 100644 index 000000000..9a4a2798e --- /dev/null +++ b/sysmodules/rosalina/source/gdb/remote_command.c @@ -0,0 +1,265 @@ +/* +* 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 . +* +* 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. +*/ + +#include "gdb/remote_command.h" +#include "gdb/net.h" +#include "csvc.h" +#include "fmt.h" +#include "gdb/breakpoints.h" + +struct +{ + const char *name; + GDBCommandHandler handler; +} remoteCommandHandlers[] = +{ + { "syncrequestinfo", GDB_REMOTE_COMMAND_HANDLER(SyncRequestInfo) }, + { "translatehandle", GDB_REMOTE_COMMAND_HANDLER(TranslateHandle) }, + { "getmmuconfig" , GDB_REMOTE_COMMAND_HANDLER(GetMmuConfig) }, + { "flushcaches" , GDB_REMOTE_COMMAND_HANDLER(FlushCaches) }, +}; + +static const char *GDB_SkipSpaces(const char *pos) +{ + const char *nextpos; + for(nextpos = pos; *nextpos != 0 && ((*nextpos >= 9 && *nextpos <= 13) || *nextpos == ' '); nextpos++); + return nextpos; +} + +GDB_DECLARE_REMOTE_COMMAND_HANDLER(SyncRequestInfo) +{ + char outbuf[GDB_BUF_LEN / 2 + 1]; + Result r; + int n; + + if(ctx->commandData[0] != 0) + return GDB_ReplyErrno(ctx, EILSEQ); + + if(ctx->selectedThreadId == 0) + ctx->selectedThreadId = ctx->currentThreadId; + + if(ctx->selectedThreadId == 0) + { + n = sprintf(outbuf, "Cannot run this command without a selected thread.\n"); + goto end; + } + + u32 id; + u32 cmdId; + ThreadContext regs; + u32 instr; + Handle process; + r = svcOpenProcess(&process, ctx->pid); + if(R_FAILED(r)) + { + n = sprintf(outbuf, "Invalid process (wtf?)\n"); + goto end; + } + + for(id = 0; id < MAX_DEBUG_THREAD && ctx->threadInfos[id].id != ctx->selectedThreadId; id++); + + r = svcGetDebugThreadContext(®s, ctx->debug, ctx->selectedThreadId, THREADCONTEXT_CONTROL_CPU_REGS); + + if(R_FAILED(r) || id == MAX_DEBUG_THREAD) + { + n = sprintf(outbuf, "Invalid or running thread.\n"); + goto end; + } + + r = svcReadProcessMemory(&cmdId, ctx->debug, ctx->threadInfos[id].tls + 0x80, 4); + if(R_FAILED(r)) + { + n = sprintf(outbuf, "Invalid or running thread.\n"); + goto end; + } + + r = svcReadProcessMemory(&instr, ctx->debug, regs.cpu_registers.pc, (regs.cpu_registers.cpsr & 0x20) ? 2 : 4); + + if(R_SUCCEEDED(r) && (((regs.cpu_registers.cpsr & 0x20) && instr == BREAKPOINT_INSTRUCTION_THUMB) || instr == BREAKPOINT_INSTRUCTION_ARM)) + { + u32 savedInstruction; + if(GDB_GetBreakpointInstruction(&savedInstruction, ctx, regs.cpu_registers.pc) == 0) + instr = savedInstruction; + } + + if(R_FAILED(r) || ((regs.cpu_registers.cpsr & 0x20) && !(instr == 0xDF32 || (instr == 0xDFFE && regs.cpu_registers.r[12] == 0x32))) + || (!(regs.cpu_registers.cpsr & 0x20) && !(instr == 0xEF000032 || (instr == 0xEF0000FE && regs.cpu_registers.r[12] == 0x32)))) + { + n = sprintf(outbuf, "The selected thread is not currently performing a sync request (svc 0x32).\n"); + goto end; + } + + char name[12]; + Handle handle; + r = svcCopyHandle(&handle, CUR_PROCESS_HANDLE, (Handle)regs.cpu_registers.r[0], process); + if(R_FAILED(r)) + { + n = sprintf(outbuf, "Invalid handle.\n"); + goto end; + } + + r = svcControlService(SERVICEOP_GET_NAME, name, handle); + if(R_FAILED(r)) + name[0] = 0; + + n = sprintf(outbuf, "%s 0x%x, 0x%08x\n", name, cmdId, ctx->threadInfos[id].tls + 0x80); + +end: + svcCloseHandle(handle); + svcCloseHandle(process); + return GDB_SendHexPacket(ctx, outbuf, n); +} + +GDB_DECLARE_REMOTE_COMMAND_HANDLER(TranslateHandle) +{ + bool ok; + u32 val; + char *end; + int n; + Result r; + u32 kernelAddr; + Handle handle, process; + s64 refcountRaw; + u32 refcount; + char classBuf[32], serviceBuf[12] = { 0 }; + char outbuf[GDB_BUF_LEN / 2 + 1]; + + if(ctx->commandData[0] == 0) + return GDB_ReplyErrno(ctx, EILSEQ); + + val = xstrtoul(ctx->commandData, &end, 0, true, &ok); + + if(!ok) + return GDB_ReplyErrno(ctx, EILSEQ); + + end = (char *)GDB_SkipSpaces(end); + + if(*end != 0) + return GDB_ReplyErrno(ctx, EILSEQ); + + r = svcOpenProcess(&process, ctx->pid); + if(R_FAILED(r)) + { + n = sprintf(outbuf, "Invalid process (wtf?)\n"); + goto end; + } + + r = svcCopyHandle(&handle, CUR_PROCESS_HANDLE, (Handle)val, process); + if(R_FAILED(r)) + { + n = sprintf(outbuf, "Invalid handle.\n"); + goto end; + } + + svcTranslateHandle(&kernelAddr, classBuf, handle); + svcGetHandleInfo(&refcountRaw, handle, 1); + svcControlService(SERVICEOP_GET_NAME, serviceBuf, handle); + refcount = (u32)(refcountRaw - 1); + if(serviceBuf[0] != 0) + n = sprintf(outbuf, "(%s *)0x%08x /* %s handle, %u %s */\n", classBuf, kernelAddr, serviceBuf, refcount, refcount == 1 ? "reference" : "references"); + else + n = sprintf(outbuf, "(%s *)0x%08x /* %u %s */\n", classBuf, kernelAddr, refcount, refcount == 1 ? "reference" : "references"); + +end: + svcCloseHandle(handle); + svcCloseHandle(process); + return GDB_SendHexPacket(ctx, outbuf, n); +} + +extern bool isN3DS; +GDB_DECLARE_REMOTE_COMMAND_HANDLER(GetMmuConfig) +{ + int n; + char outbuf[GDB_BUF_LEN / 2 + 1]; + Result r; + Handle process; + + if(ctx->commandData[0] != 0) + return GDB_ReplyErrno(ctx, EILSEQ); + + r = svcOpenProcess(&process, ctx->pid); + if(R_FAILED(r)) + n = sprintf(outbuf, "Invalid process (wtf?)\n"); + else + { + s64 TTBCR, TTBR0; + svcGetSystemInfo(&TTBCR, 0x10002, 0); + svcGetProcessInfo(&TTBR0, process, 0x10008); + n = sprintf(outbuf, "TTBCR = %u\nTTBR0 = 0x%08x\nTTBR1 =", (u32)TTBCR, (u32)TTBR0); + for(u32 i = 0; i < (isN3DS ? 4 : 2); i++) + { + s64 TTBR1; + svcGetSystemInfo(&TTBR1, 0x10002, 1 + i); + + if(i == (isN3DS ? 3 : 1)) + n += sprintf(outbuf + n, " 0x%08x\n", (u32)TTBR1); + else + n += sprintf(outbuf + n, " 0x%08x /", (u32)TTBR1); + } + svcCloseHandle(process); + } + + return GDB_SendHexPacket(ctx, outbuf, n); +} + +GDB_DECLARE_REMOTE_COMMAND_HANDLER(FlushCaches) +{ + if(ctx->commandData[0] != 0) + return GDB_ReplyErrno(ctx, EILSEQ); + + svcFlushEntireDataCache(); + svcInvalidateEntireInstructionCache(); + + return GDB_ReplyOk(ctx); +} + +GDB_DECLARE_QUERY_HANDLER(Rcmd) +{ + char commandData[GDB_BUF_LEN / 2 + 1]; + char *endpos; + const char *errstr = "Unrecognized command.\n"; + u32 len = strlen(ctx->commandData); + + if(len == 0 || (len % 2) == 1 || GDB_DecodeHex(commandData, ctx->commandData, len / 2) != len / 2) + return GDB_ReplyErrno(ctx, EILSEQ); + commandData[len / 2] = 0; + + for(endpos = commandData; !(*endpos >= 9 && *endpos <= 13) && *endpos != ' ' && *endpos != 0; endpos++); + + char *nextpos = (char *)GDB_SkipSpaces(endpos); + *endpos = 0; + + for(u32 i = 0; i < sizeof(remoteCommandHandlers) / sizeof(remoteCommandHandlers[0]); i++) + { + if(strcmp(commandData, remoteCommandHandlers[i].name) == 0) + { + ctx->commandData = nextpos; + return remoteCommandHandlers[i].handler(ctx); + } + } + + return GDB_SendHexPacket(ctx, errstr, strlen(errstr)); +} diff --git a/sysmodules/rosalina/source/gdb/server.c b/sysmodules/rosalina/source/gdb/server.c new file mode 100644 index 000000000..2199e25a4 --- /dev/null +++ b/sysmodules/rosalina/source/gdb/server.c @@ -0,0 +1,297 @@ +/* +* 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 . +* +* 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. +*/ + +#include "gdb/server.h" +#include "gdb/net.h" +#include "gdb/query.h" +#include "gdb/verbose.h" +#include "gdb/thread.h" +#include "gdb/debug.h" +#include "gdb/regs.h" +#include "gdb/mem.h" +#include "gdb/watchpoints.h" +#include "gdb/breakpoints.h" +#include "gdb/stop_point.h" + +Result GDB_InitializeServer(GDBServer *server) +{ + Result ret = server_init(&server->super); + if(ret != 0) + return ret; + + server->super.host = 0; + + server->super.accept_cb = (sock_accept_cb)GDB_AcceptClient; + server->super.data_cb = (sock_data_cb) GDB_DoPacket; + server->super.close_cb = (sock_close_cb) GDB_CloseClient; + + server->super.alloc = (sock_alloc_func) GDB_GetClient; + server->super.free = (sock_free_func) GDB_ReleaseClient; + + server->super.clients_per_server = 1; + + server->referenceCount = 0; + svcCreateEvent(&server->statusUpdated, RESET_ONESHOT); + + for(u32 i = 0; i < sizeof(server->ctxs) / sizeof(GDBContext); i++) + GDB_InitializeContext(server->ctxs + i); + + GDB_ResetWatchpoints(); + + return 0; +} + +void GDB_FinalizeServer(GDBServer *server) +{ + server_finalize(&server->super); + + svcCloseHandle(server->statusUpdated); +} + +void GDB_IncrementServerReferenceCount(GDBServer *server) +{ + AtomicPostIncrement(&server->referenceCount); +} + +void GDB_DecrementServerReferenceCount(GDBServer *server) +{ + if(AtomicDecrement(&server->referenceCount) == 0) + GDB_FinalizeServer(server); +} + +void GDB_RunServer(GDBServer *server) +{ + server_bind(&server->super, GDB_PORT_BASE); + server_bind(&server->super, GDB_PORT_BASE + 1); + server_bind(&server->super, GDB_PORT_BASE + 2); + server_run(&server->super); +} + +int GDB_AcceptClient(GDBContext *ctx) +{ + RecursiveLock_Lock(&ctx->lock); + Result r = svcDebugActiveProcess(&ctx->debug, ctx->pid); + if(R_SUCCEEDED(r)) + { + DebugEventInfo *info = &ctx->latestDebugEvent; + ctx->state = GDB_STATE_CONNECTED; + ctx->processExited = ctx->processEnded = false; + ctx->latestSentPacketSize = 0; + while(R_SUCCEEDED(svcGetProcessDebugEvent(info, ctx->debug)) && info->type != DBGEVENT_EXCEPTION && + info->exception.type != EXCEVENT_ATTACH_BREAK) + { + GDB_PreprocessDebugEvent(ctx, info); + svcContinueDebugEvent(ctx->debug, ctx->continueFlags); + } + } + else + { + RecursiveLock_Unlock(&ctx->lock); + return -1; + } + + svcSignalEvent(ctx->clientAcceptedEvent); + RecursiveLock_Unlock(&ctx->lock); + + return 0; +} + +int GDB_CloseClient(GDBContext *ctx) +{ + RecursiveLock_Lock(&ctx->lock); + + for(u32 i = 0; i < ctx->nbBreakpoints; i++) + { + if(!ctx->breakpoints[i].persistent) + GDB_DisableBreakpointById(ctx, i); + } + memset(&ctx->breakpoints, 0, sizeof(ctx->breakpoints)); + ctx->nbBreakpoints = 0; + + for(u32 i = 0; i < ctx->nbWatchpoints; i++) + { + GDB_RemoveWatchpoint(ctx, ctx->watchpoints[i], WATCHPOINT_DISABLED); + ctx->watchpoints[i] = 0; + } + ctx->nbWatchpoints = 0; + + svcKernelSetState(0x10002, ctx->pid, false); + memset(ctx->svcMask, 0, 32); + + memset(ctx->memoryOsInfoXmlData, 0, sizeof(ctx->memoryOsInfoXmlData)); + memset(ctx->processesOsInfoXmlData, 0, sizeof(ctx->processesOsInfoXmlData)); + memset(ctx->threadListData, 0, sizeof(ctx->threadListData)); + ctx->threadListDataPos = 0; + + svcClearEvent(ctx->clientAcceptedEvent); + ctx->eventToWaitFor = ctx->clientAcceptedEvent; + RecursiveLock_Unlock(&ctx->lock); + return 0; +} + +GDBContext *GDB_GetClient(GDBServer *server, u16 port) +{ + if(port < GDB_PORT_BASE || port >= GDB_PORT_BASE + sizeof(server->ctxs) / sizeof(GDBContext)) + return NULL; + + GDBContext *ctx = &server->ctxs[port - GDB_PORT_BASE]; + if(!(ctx->flags & GDB_FLAG_USED) && (ctx->flags & GDB_FLAG_SELECTED)) + { + RecursiveLock_Lock(&ctx->lock); + ctx->flags |= GDB_FLAG_USED; + ctx->state = GDB_STATE_CONNECTED; + RecursiveLock_Unlock(&ctx->lock); + + return ctx; + } + + return NULL; +} + +void GDB_ReleaseClient(GDBServer *server, GDBContext *ctx) +{ + DebugEventInfo dummy; + + svcSignalEvent(server->statusUpdated); + + RecursiveLock_Lock(&ctx->lock); + + /* + There's a possibility of a race condition with a possible user exception handler, but you shouldn't + use 'kill' on APPLICATION titles in the first place (reboot hanging because the debugger is still running, etc). + */ + + ctx->continueFlags = (DebugFlags)0; + + while(R_SUCCEEDED(svcGetProcessDebugEvent(&dummy, ctx->debug))); + while(R_SUCCEEDED(svcContinueDebugEvent(ctx->debug, ctx->continueFlags))); + if(ctx->flags & GDB_FLAG_TERMINATE_PROCESS) + { + svcTerminateDebugProcess(ctx->debug); + ctx->processEnded = true; + ctx->processExited = false; + } + + while(R_SUCCEEDED(svcGetProcessDebugEvent(&dummy, ctx->debug))); + while(R_SUCCEEDED(svcContinueDebugEvent(ctx->debug, ctx->continueFlags))); + + svcCloseHandle(ctx->debug); + ctx->debug = 0; + + ctx->flags = (GDBFlags)0; + ctx->state = GDB_STATE_DISCONNECTED; + + ctx->eventToWaitFor = ctx->clientAcceptedEvent; + ctx->continueFlags = (DebugFlags)(DBG_SIGNAL_FAULT_EXCEPTION_EVENTS | DBG_INHIBIT_USER_CPU_EXCEPTION_HANDLERS); + ctx->pid = 0; + ctx->currentThreadId = ctx->selectedThreadId = ctx->selectedThreadIdForContinuing = 0; + ctx->nbThreads = 0; + memset(ctx->threadInfos, 0, sizeof(ctx->threadInfos)); + ctx->catchThreadEvents = false; + ctx->isGDB = false; + RecursiveLock_Unlock(&ctx->lock); +} + +static const struct +{ + char command; + GDBCommandHandler handler; +} gdbCommandHandlers[] = +{ + { '?', GDB_HANDLER(GetStopReason) }, + { 'c', GDB_HANDLER(Continue) }, + { 'C', GDB_HANDLER(Continue) }, + { 'D', GDB_HANDLER(Detach) }, + { 'g', GDB_HANDLER(ReadRegisters) }, + { 'G', GDB_HANDLER(WriteRegisters) }, + { 'H', GDB_HANDLER(SetThreadId) }, + { 'k', GDB_HANDLER(Kill) }, + { 'm', GDB_HANDLER(ReadMemory) }, + { 'M', GDB_HANDLER(WriteMemory) }, + { 'p', GDB_HANDLER(ReadRegister) }, + { 'P', GDB_HANDLER(WriteRegister) }, + { 'q', GDB_HANDLER(ReadQuery) }, + { 'Q', GDB_HANDLER(WriteQuery) }, + { 'T', GDB_HANDLER(IsThreadAlive) }, + { 'v', GDB_HANDLER(VerboseCommand) }, + { 'X', GDB_HANDLER(WriteMemoryRaw) }, + { 'z', GDB_HANDLER(ToggleStopPoint) }, + { 'Z', GDB_HANDLER(ToggleStopPoint) }, +}; + +static inline GDBCommandHandler GDB_GetCommandHandler(char command) +{ + static const u32 nbHandlers = sizeof(gdbCommandHandlers) / sizeof(gdbCommandHandlers[0]); + + u32 i; + for(i = 0; i < nbHandlers && gdbCommandHandlers[i].command != command; i++); + + return i < nbHandlers ? gdbCommandHandlers[i].handler : GDB_HANDLER(Unsupported); +} + +int GDB_DoPacket(GDBContext *ctx) +{ + int ret; + + RecursiveLock_Lock(&ctx->lock); + GDBFlags oldFlags = ctx->flags; + + if(ctx->state == GDB_STATE_DISCONNECTED) + return -1; + + int r = GDB_ReceivePacket(ctx); + if(r == 0) + ret = 0; + else if(r == -1) + ret = -1; + else if(ctx->buffer[0] == '\x03') + { + GDB_HandleBreak(ctx); + ret = 0; + } + else if(ctx->buffer[0] == '$') + { + GDBCommandHandler handler = GDB_GetCommandHandler(ctx->buffer[1]); + ctx->commandData = ctx->buffer + 2; + ret = handler(ctx); + } + else + ret = 0; + + RecursiveLock_Unlock(&ctx->lock); + if(ctx->state == GDB_STATE_CLOSING) + return -1; + + if((oldFlags & GDB_FLAG_PROCESS_CONTINUING) && !(ctx->flags & GDB_FLAG_PROCESS_CONTINUING)) + { + if(R_FAILED(svcBreakDebugProcess(ctx->debug))) + ctx->flags |= GDB_FLAG_PROCESS_CONTINUING; + } + else if(!(oldFlags & GDB_FLAG_PROCESS_CONTINUING) && (ctx->flags & GDB_FLAG_PROCESS_CONTINUING)) + svcSignalEvent(ctx->continuedEvent); + + return ret; +} diff --git a/sysmodules/rosalina/source/gdb/stop_point.c b/sysmodules/rosalina/source/gdb/stop_point.c new file mode 100644 index 000000000..5c8807523 --- /dev/null +++ b/sysmodules/rosalina/source/gdb/stop_point.c @@ -0,0 +1,71 @@ +/* +* 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 . +* +* 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. +*/ + +#include "gdb.h" +#include "gdb/net.h" +#include "gdb/watchpoints.h" +#include "gdb/breakpoints.h" + +GDB_DECLARE_HANDLER(ToggleStopPoint) +{ + bool add = ctx->commandData[-1] == 'Z'; + u32 lst[3]; + + const char *pos = GDB_ParseHexIntegerList(lst, ctx->commandData, 3, ';'); + if(pos == NULL) + return GDB_ReplyErrno(ctx, EILSEQ); + bool persist = *pos != 0 && strncmp(pos, ";cmds:1", 7) == 0; + + u32 kind = lst[0]; + u32 addr = lst[1]; + u32 size = lst[2]; + + int res; + static const WatchpointKind kinds[3] = { WATCHPOINT_WRITE, WATCHPOINT_READ, WATCHPOINT_READWRITE }; + switch(kind) + { + case 0: // software breakpoint + if(size != 2 && size != 4) + return GDB_ReplyEmpty(ctx); + else + { + res = add ? GDB_AddBreakpoint(ctx, addr, size == 2, persist) : + GDB_RemoveBreakpoint(ctx, addr); + return res == 0 ? GDB_ReplyOk(ctx) : GDB_ReplyErrno(ctx, -res); + } + + // Watchpoints + case 2: + case 3: + case 4: + res = add ? GDB_AddWatchpoint(ctx, addr, size, kinds[kind - 2]) : + GDB_RemoveWatchpoint(ctx, addr, kinds[kind - 2]); + return res == 0 ? GDB_ReplyOk(ctx) : GDB_ReplyErrno(ctx, -res); + + default: + return GDB_ReplyEmpty(ctx); + } +} diff --git a/sysmodules/rosalina/source/gdb/thread.c b/sysmodules/rosalina/source/gdb/thread.c new file mode 100644 index 000000000..e10bbffcc --- /dev/null +++ b/sysmodules/rosalina/source/gdb/thread.c @@ -0,0 +1,304 @@ +/* +* 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 . +* +* 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. +*/ + +#include "gdb/thread.h" +#include "gdb/net.h" +#include "fmt.h" +#include + +static s32 GDB_GetDynamicThreadPriority(GDBContext *ctx, u32 threadId) +{ + Handle process, thread; + Result r; + s32 prio = 65; + + r = svcOpenProcess(&process, ctx->pid); + if(R_FAILED(r)) + return 65; + + r = svcOpenThread(&thread, process, threadId); + if(R_FAILED(r)) + goto cleanup; + + r = svcGetThreadPriority(&prio, thread); + +cleanup: + svcCloseHandle(thread); + svcCloseHandle(process); + + return prio; +} + +struct ThreadIdWithCtx +{ + GDBContext *ctx; + u32 id; +}; + +static int thread_compare_func(const void *a_, const void *b_) +{ + const struct ThreadIdWithCtx *a = (const struct ThreadIdWithCtx *)a_; + const struct ThreadIdWithCtx *b = (const struct ThreadIdWithCtx *)b_; + + u32 maskA = 2, maskB = 2; + s32 prioAStatic = 65, prioBStatic = 65; + s32 prioADynamic = GDB_GetDynamicThreadPriority(a->ctx, a->id); + s32 prioBDynamic = GDB_GetDynamicThreadPriority(b->ctx, b->id); + s64 dummy; + + svcGetDebugThreadParam(&dummy, &maskA, a->ctx->debug, a->id, DBGTHREAD_PARAMETER_SCHEDULING_MASK_LOW); + svcGetDebugThreadParam(&dummy, &maskB, b->ctx->debug, b->id, DBGTHREAD_PARAMETER_SCHEDULING_MASK_LOW); + svcGetDebugThreadParam(&dummy, (u32 *)&prioAStatic, a->ctx->debug, a->id, DBGTHREAD_PARAMETER_PRIORITY); + svcGetDebugThreadParam(&dummy, (u32 *)&prioBStatic, b->ctx->debug, b->id, DBGTHREAD_PARAMETER_PRIORITY); + + if(maskA == 1 && maskB != 1) + return -1; + else if(maskA != 1 && maskB == 1) + return 1; + else if(prioADynamic != prioBDynamic) + return prioADynamic - prioBDynamic; + else + return prioAStatic - prioBStatic; +} + +u32 GDB_GetCurrentThreadFromList(GDBContext *ctx, u32 *threadIds, u32 nbThreads) +{ + struct ThreadIdWithCtx lst[MAX_DEBUG_THREAD]; + for(u32 i = 0; i < nbThreads; i++) + { + lst[i].ctx = ctx; + lst[i].id = threadIds[i]; + } + + qsort(lst, nbThreads, sizeof(struct ThreadIdWithCtx), thread_compare_func); + return lst[0].id; +} + +u32 GDB_GetCurrentThread(GDBContext *ctx) +{ + u32 threadIds[MAX_DEBUG_THREAD]; + + if(ctx->nbThreads == 0) + return 0; + + for(u32 i = 0; i < ctx->nbThreads; i++) + threadIds[i] = ctx->threadInfos[i].id; + + return GDB_GetCurrentThreadFromList(ctx, threadIds, ctx->nbThreads); +} + +GDB_DECLARE_HANDLER(SetThreadId) +{ + if(ctx->commandData[0] == 'g') + { + if(strncmp(ctx->commandData + 1, "-1", 2) == 0) + return GDB_ReplyErrno(ctx, EILSEQ); // a thread must be specified + + u32 id; + if(GDB_ParseHexIntegerList(&id, ctx->commandData + 1, 1, 0) == NULL) + return GDB_ReplyErrno(ctx, EILSEQ); + ctx->selectedThreadId = id; + return GDB_ReplyOk(ctx); + } + else if(ctx->commandData[0] == 'c') + { + // We can't stop/continue particular threads (uncompliant behavior) + if(strncmp(ctx->commandData + 1, "-1", 2) == 0) + ctx->selectedThreadIdForContinuing = 0; + else + { + u32 id; + if(GDB_ParseHexIntegerList(&id, ctx->commandData + 1, 1, 0) == NULL) + return GDB_ReplyErrno(ctx, EILSEQ); + ctx->selectedThreadIdForContinuing = id; + } + + return GDB_ReplyOk(ctx); + } + else + return GDB_ReplyErrno(ctx, EPERM); +} + +GDB_DECLARE_HANDLER(IsThreadAlive) +{ + u32 threadId; + s64 dummy; + u32 mask; + + if(GDB_ParseHexIntegerList(&threadId, ctx->commandData, 1, 0) == NULL) + return GDB_ReplyErrno(ctx, EILSEQ); + + Result r = svcGetDebugThreadParam(&dummy, &mask, ctx->debug, threadId, DBGTHREAD_PARAMETER_SCHEDULING_MASK_LOW); + if(R_SUCCEEDED(r) && mask != 2) + return GDB_ReplyOk(ctx); + else + return GDB_ReplyErrno(ctx, EPERM); +} + +GDB_DECLARE_QUERY_HANDLER(CurrentThreadId) +{ + if(ctx->currentThreadId == 0) + ctx->currentThreadId = GDB_GetCurrentThread(ctx); + + return ctx->currentThreadId != 0 ? GDB_SendFormattedPacket(ctx, "QC%x", ctx->currentThreadId) : GDB_ReplyErrno(ctx, EPERM); +} + +static void GDB_GenerateThreadListData(GDBContext *ctx) +{ + u32 aliveThreadIds[MAX_DEBUG_THREAD]; + u32 nbAliveThreads = 0; // just in case. This is probably redundant + + for(u32 i = 0; i < ctx->nbThreads; i++) + { + s64 dummy; + u32 mask; + + Result r = svcGetDebugThreadParam(&dummy, &mask, ctx->debug, ctx->threadInfos[i].id, DBGTHREAD_PARAMETER_SCHEDULING_MASK_LOW); + if(R_SUCCEEDED(r) && mask != 2) + aliveThreadIds[nbAliveThreads++] = ctx->threadInfos[i].id; + } + + if(nbAliveThreads == 0) + ctx->threadListData[0] = 0; + + char *bufptr = ctx->threadListData; + + for(u32 i = 0; i < nbAliveThreads; i++) + bufptr += sprintf(bufptr, i == (nbAliveThreads - 1) ? "%x" : "%x,", aliveThreadIds[i]); +} + +static int GDB_SendThreadData(GDBContext *ctx) +{ + u32 sz = strlen(ctx->threadListData); + u32 len; + if(ctx->threadListDataPos >= sz) + len = 0; + else if(sz - ctx->threadListDataPos <= GDB_BUF_LEN - 1) + len = sz - ctx->threadListDataPos; + else + { + for(len = GDB_BUF_LEN - 1; ctx->threadListData[ctx->threadListDataPos + len] != ',' && len > 0; len--); + if(len > 0) + len--; + } + + int n = GDB_SendStreamData(ctx, ctx->threadListData, ctx->threadListDataPos, len, sz, true); + + if(ctx->threadListDataPos >= sz) + { + ctx->threadListDataPos = 0; + ctx->threadListData[0] = 0; + } + else + ctx->threadListDataPos += len; + + return n; +} + +GDB_DECLARE_QUERY_HANDLER(fThreadInfo) +{ + if(ctx->threadListData[0] == 0) + GDB_GenerateThreadListData(ctx); + + return GDB_SendThreadData(ctx); +} + +GDB_DECLARE_QUERY_HANDLER(sThreadInfo) +{ + return GDB_SendThreadData(ctx); +} + +GDB_DECLARE_QUERY_HANDLER(ThreadEvents) +{ + switch(ctx->commandData[0]) + { + case '0': + ctx->catchThreadEvents = false; + return GDB_ReplyOk(ctx); + case '1': + ctx->catchThreadEvents = true; + return GDB_ReplyOk(ctx); + default: + return GDB_ReplyErrno(ctx, EILSEQ); + } +} + +GDB_DECLARE_QUERY_HANDLER(ThreadExtraInfo) +{ + u32 id; + s64 dummy; + u32 val; + Result r; + int n; + + const char *sStatus; + char sThreadDynamicPriority[64], sThreadStaticPriority[64]; + char sCoreIdeal[64], sCoreCreator[64]; + char buf[512]; + + u32 tls = 0; + + if(GDB_ParseHexIntegerList(&id, ctx->commandData, 1, 0) == NULL) + return GDB_ReplyErrno(ctx, EILSEQ); + + for(u32 i = 0; i < MAX_DEBUG_THREAD; i++) + { + if(ctx->threadInfos[i].id == id) + tls = ctx->threadInfos[i].tls; + } + + r = svcGetDebugThreadParam(&dummy, &val, ctx->debug, id, DBGTHREAD_PARAMETER_SCHEDULING_MASK_LOW); + sStatus = R_SUCCEEDED(r) ? (val == 1 ? ", running, " : ", idle, ") : ""; + + val = (u32)GDB_GetDynamicThreadPriority(ctx, id); + if(val == 65) + sThreadDynamicPriority[0] = 0; + else + sprintf(sThreadDynamicPriority, "dynamic prio.: %d, ", (s32)val); + + r = svcGetDebugThreadParam(&dummy, &val, ctx->debug, id, DBGTHREAD_PARAMETER_PRIORITY); + if(R_FAILED(r)) + sThreadStaticPriority[0] = 0; + else + sprintf(sThreadStaticPriority, "static prio.: %d, ", (s32)val); + + r = svcGetDebugThreadParam(&dummy, &val, ctx->debug, id, DBGTHREAD_PARAMETER_CPU_IDEAL); + if(R_FAILED(r)) + sCoreIdeal[0] = 0; + else + sprintf(sCoreIdeal, "ideal core: %u, ", val); + + r = svcGetDebugThreadParam(&dummy, &val, ctx->debug, id, DBGTHREAD_PARAMETER_CPU_CREATOR); // Creator = "first ran, and running the thread" + if(R_FAILED(r)) + sCoreCreator[0] = 0; + else + sprintf(sCoreCreator, "running on core %u", val); + + n = sprintf(buf, "TLS: 0x%08x%s%s%s%s%s", tls, sStatus, sThreadDynamicPriority, sThreadStaticPriority, + sCoreIdeal, sCoreCreator); + + return GDB_SendHexPacket(ctx, buf, (u32)n); +} diff --git a/sysmodules/rosalina/source/gdb/verbose.c b/sysmodules/rosalina/source/gdb/verbose.c new file mode 100644 index 000000000..fea7d423c --- /dev/null +++ b/sysmodules/rosalina/source/gdb/verbose.c @@ -0,0 +1,73 @@ +/* +* 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 . +* +* 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. +*/ + +#include "gdb/verbose.h" +#include "gdb/net.h" +#include "gdb/debug.h" + +static const struct +{ + const char *name; + GDBCommandHandler handler; +} gdbVerboseCommandHandlers[] = +{ + { "Cont?", GDB_VERBOSE_HANDLER(ContinueSupported) }, + { "Cont", GDB_VERBOSE_HANDLER(Continue) }, + { "MustReplyEmpty", GDB_HANDLER(Unsupported) }, +}; + +GDB_DECLARE_HANDLER(VerboseCommand) +{ + char *nameBegin = ctx->commandData; // w/o leading 'v' + if(*nameBegin == 0) + return GDB_ReplyErrno(ctx, EILSEQ); + + char *nameEnd; + char *vData = NULL; + + for(nameEnd = nameBegin; *nameEnd != 0 && *nameEnd != ';' && *nameEnd != ':'; nameEnd++); + if(*nameEnd != 0) + { + *nameEnd = 0; + vData = nameEnd + 1; + } + + for(u32 i = 0; i < sizeof(gdbVerboseCommandHandlers) / sizeof(gdbVerboseCommandHandlers[0]); i++) + { + if(strcmp(gdbVerboseCommandHandlers[i].name, nameBegin) == 0) + { + ctx->commandData = vData; + return gdbVerboseCommandHandlers[i].handler(ctx); + } + } + + return GDB_HandleUnsupported(ctx); // No handler found! +} + +GDB_DECLARE_VERBOSE_HANDLER(ContinueSupported) +{ + return GDB_SendPacket(ctx, "vCont;c;C", 9); +} diff --git a/sysmodules/rosalina/source/gdb/watchpoints.c b/sysmodules/rosalina/source/gdb/watchpoints.c new file mode 100644 index 000000000..d11dc7ddd --- /dev/null +++ b/sysmodules/rosalina/source/gdb/watchpoints.c @@ -0,0 +1,177 @@ +/* +* 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 . +* +* 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. +*/ + +#include "gdb/watchpoints.h" +#define _REENT_ONLY +#include + +/* + There are only 2 Watchpoint Register Pairs on MPCORE ARM11 CPUs, + and only 2 Breakpoint Register Pairs with context ID capabilities (BRP4-5) as well. + + We'll reserve and use all 4 of them +*/ + +RecursiveLock watchpointManagerLock; + +typedef struct Watchpoint +{ + u32 address; + u32 size; + WatchpointKind kind; + Handle debug; // => context ID +} Watchpoint; + +typedef struct WatchpointManager +{ + u32 total; + Watchpoint watchpoints[2]; +} WatchpointManager; + +static WatchpointManager manager; + +void GDB_ResetWatchpoints(void) +{ + static bool lockInitialized = false; + if(!lockInitialized) + { + RecursiveLock_Init(&watchpointManagerLock); + lockInitialized = true; + } + RecursiveLock_Lock(&watchpointManagerLock); + + svcSetHardwareBreakPoint(4, 0, 0); + svcSetHardwareBreakPoint(0x100, 0, 0); + + svcSetHardwareBreakPoint(5, 0, 0); + svcSetHardwareBreakPoint(0x101, 0, 0); + + memset(&manager, 0, sizeof(WatchpointManager)); + + RecursiveLock_Unlock(&watchpointManagerLock); +} + +int GDB_AddWatchpoint(GDBContext *ctx, u32 address, u32 size, WatchpointKind kind) +{ + RecursiveLock_Lock(&watchpointManagerLock); + + u32 offset = address - (address & ~3); + + if(manager.total == 2) + return -EBUSY; + + if(size == 0 || (offset + size) > 4 || kind == WATCHPOINT_DISABLED) + return -EINVAL; + + if(GDB_GetWatchpointKind(ctx, address) != WATCHPOINT_DISABLED) + // Disallow duplicate watchpoints: the kernel doesn't give us sufficient info to differentiate them by kind (DFSR) + return -EINVAL; + + u32 id = manager.watchpoints[0].kind == WATCHPOINT_DISABLED ? 0 : 1; + u32 selectMask = ((1 << size) - 1) << offset; + + u32 BCR = (1 << 21) | /* compare with context ID */ + (1 << 20) | /* linked (with a WRP in our case) */ + (0xf << 5) | /* byte address select, +0 to +3 as mandated when linking with a WRP */ + (3 << 1) | /* either privileged modes or user mode, as mandated when linking with a WRP */ + (1 << 0) ; /* enabled */ + + u32 WCR = (1 << 20) | /* linked */ + ((4 + id) << 16) | /* ID of the linked BRP */ + (selectMask << 5) | /* byte address select */ + ((u32)kind << 3) | /* kind */ + (2 << 1) | /* user mode only */ + (1 << 0) ; /* enabled */ + + Result r = svcSetHardwareBreakPoint(0x100 | id, WCR, address & ~3); + + if(R_SUCCEEDED(r)) + r = svcSetHardwareBreakPoint(4 + id, BCR, (u32)ctx->debug); + + if(R_SUCCEEDED(r)) + { + Watchpoint *watchpoint = &manager.watchpoints[id]; + manager.total++; + watchpoint->address = address; + watchpoint->size = size; + watchpoint->kind = kind; + watchpoint->debug = ctx->debug; + ctx->watchpoints[ctx->nbWatchpoints++] = address; + RecursiveLock_Unlock(&watchpointManagerLock); + return 0; + } + else + { + RecursiveLock_Unlock(&watchpointManagerLock); + return -EINVAL; + } +} + +int GDB_RemoveWatchpoint(GDBContext *ctx, u32 address, WatchpointKind kind) +{ + RecursiveLock_Lock(&watchpointManagerLock); + + u32 id; + for(id = 0; id < 2 && manager.watchpoints[id].address != address && manager.watchpoints[id].debug != ctx->debug; id++); + + if(id == 2 || (kind != WATCHPOINT_DISABLED && manager.watchpoints[id].kind != kind)) + { + RecursiveLock_Unlock(&watchpointManagerLock); + return -EINVAL; + } + else + { + svcSetHardwareBreakPoint(4 + id, 0, 0); + svcSetHardwareBreakPoint(0x100 | id, 0, 0); + + memset(&manager.watchpoints[id], 0, sizeof(Watchpoint)); + manager.total--; + + if(ctx->watchpoints[0] == address) + { + ctx->watchpoints[0] = ctx->watchpoints[1]; + ctx->watchpoints[1] = 0; + ctx->nbWatchpoints--; + } + else if(ctx->watchpoints[1] == address) + { + ctx->watchpoints[1] = 0; + ctx->nbWatchpoints--; + } + + RecursiveLock_Unlock(&watchpointManagerLock); + + return 0; + } +} + +WatchpointKind GDB_GetWatchpointKind(GDBContext *ctx, u32 address) +{ + u32 id; + for(id = 0; id < 2 && manager.watchpoints[id].address != address && manager.watchpoints[id].debug != ctx->debug; id++); + + return id == 2 ? WATCHPOINT_DISABLED : manager.watchpoints[id].kind; +} diff --git a/sysmodules/rosalina/source/gdb/xfer.c b/sysmodules/rosalina/source/gdb/xfer.c new file mode 100644 index 000000000..fb5caa159 --- /dev/null +++ b/sysmodules/rosalina/source/gdb/xfer.c @@ -0,0 +1,271 @@ +/* +* 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 . +* +* 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. +*/ + +#include "gdb/xfer.h" +#include "gdb/net.h" +#include "../../build/xml_data.h" +#include <3ds/os.h> +#include "fmt.h" + +struct +{ + const char *name; + int (*handler)(GDBContext *ctx, bool write, const char *annex, u32 offset, u32 length); +} xferCommandHandlers[] = +{ + { "features", GDB_XFER_HANDLER(Features) }, + { "osdata", GDB_XFER_HANDLER(OsData) }, +}; + +GDB_DECLARE_XFER_HANDLER(Features) +{ + if(strcmp(annex, "target.xml") != 0 || write) + return GDB_ReplyEmpty(ctx); + else + return GDB_SendStreamData(ctx, target_xml, offset, length, sizeof(target_xml) - 1, false); +} + +struct +{ + const char *name; + int (*handler)(GDBContext *ctx, bool write, u32 offset, u32 length); +} xferOsDataCommandHandlers[] = +{ + { "cfwversion", GDB_XFER_OSDATA_HANDLER(CfwVersion) }, + { "memory", GDB_XFER_OSDATA_HANDLER(Memory) }, + { "processes", GDB_XFER_OSDATA_HANDLER(Processes) }, +}; + +GDB_DECLARE_XFER_OSDATA_HANDLER(CfwVersion) +{ + if(write) + return GDB_HandleUnsupported(ctx); + else + { + char buf[sizeof(osdata_cfw_version_template_xml) + 64]; + char versionString[16]; + s64 out; + u32 version, commitHash; + bool isRelease; + u32 sz; + + svcGetSystemInfo(&out, 0x10000, 0); + version = (u32)out; + + svcGetSystemInfo(&out, 0x10000, 1); + commitHash = (u32)out; + + svcGetSystemInfo(&out, 0x10000, 3); + isRelease = (bool)out; + + if(GET_VERSION_REVISION(version) == 0) + sprintf(versionString, "v%u.%u", GET_VERSION_MAJOR(version), GET_VERSION_MINOR(version)); + else + sprintf(versionString, "v%u.%u.%u", GET_VERSION_MAJOR(version), GET_VERSION_MINOR(version), GET_VERSION_REVISION(version)); + + sz = (u32)sprintf(buf, osdata_cfw_version_template_xml, versionString, commitHash, isRelease ? "Yes" : "No"); + + return GDB_SendStreamData(ctx, buf, offset, length, sz, false); + } +} + +GDB_DECLARE_XFER_OSDATA_HANDLER(Memory) +{ + if(write) + return GDB_HandleUnsupported(ctx); + else + { + if(ctx->memoryOsInfoXmlData[0] == 0) + { + s64 out; + u32 applicationUsed, systemUsed, baseUsed; + u32 applicationTotal = *(vu32 *)0x1FF80040, systemTotal = *(vu32 *)0x1FF80044, baseTotal = *(vu32 *)0x1FF80048; + + svcGetSystemInfo(&out, 0, 1); + applicationUsed = (u32)out; + + svcGetSystemInfo(&out, 0, 2); + systemUsed = (u32)out; + + svcGetSystemInfo(&out, 0, 3); + baseUsed = (u32)out; + + sprintf(ctx->memoryOsInfoXmlData, osdata_memory_template_xml, + applicationUsed, applicationTotal - applicationUsed, applicationTotal, (u32)((5ULL + ((1000ULL * applicationUsed) / applicationTotal)) / 10ULL), + systemUsed, systemTotal - systemUsed, systemTotal, (u32)((5ULL + ((1000ULL * systemUsed) / systemTotal)) / 10ULL), + baseUsed, baseTotal - baseUsed, baseTotal, (u32)((5ULL + ((1000ULL * baseUsed) / baseTotal)) / 10ULL) + ); + } + + u32 size = strlen(ctx->memoryOsInfoXmlData); + int n = GDB_SendStreamData(ctx, ctx->memoryOsInfoXmlData, offset, length, size, false); + + if(offset + length >= size) + ctx->memoryOsInfoXmlData[0] = 0; // we're done, invalidate + + return n; + } +} + +GDB_DECLARE_XFER_OSDATA_HANDLER(Processes) +{ + if(write) + return GDB_HandleUnsupported(ctx); + else + { + if(ctx->processesOsInfoXmlData[0] == 0) + { + static const char header[] = + "\n" + "\n" + "\n"; + + static const char item[] = + " \n" + " %u\n" + " %s\n" + " \n"; + + static const char footer[] = "\n"; + + int n; + u32 pos = 0; + + u32 pidList[0x40]; + s32 processAmount; + + strcpy(ctx->processesOsInfoXmlData, header); + pos = sizeof(header) - 1; + svcGetProcessList(&processAmount, pidList, 0x40); + + for(s32 i = 0; i < processAmount; i++) + { + u32 pid = pidList[i]; + char name[9] = { 0 }; + s64 out; + Handle processHandle; + Result res = svcOpenProcess(&processHandle, pidList[i]); + if(R_FAILED(res)) + continue; + + svcGetProcessInfo(&out, processHandle, 0x10000); + memcpy(name, &out, 8); + svcCloseHandle(processHandle); + + n = sprintf(ctx->processesOsInfoXmlData + pos, item, pid, name); + pos += (u32)n; + } + + strcpy(ctx->processesOsInfoXmlData + pos, footer); + pos = sizeof(footer) - 1; + } + + u32 size = strlen(ctx->processesOsInfoXmlData); + int n = GDB_SendStreamData(ctx, ctx->processesOsInfoXmlData, offset, length, size, false); + + if(offset + length >= size) + ctx->processesOsInfoXmlData[0] = 0; // we're done, invalidate + + return n; + } +} + +GDB_DECLARE_XFER_HANDLER(OsData) +{ + if(strcmp(annex, "") == 0 && !write) + return GDB_SendStreamData(ctx, osdata_xml, offset, length, sizeof(osdata_xml) - 1, false); + else + { + for(u32 i = 0; i < sizeof(xferOsDataCommandHandlers) / sizeof(xferOsDataCommandHandlers[0]); i++) + { + if(strcmp(annex, xferOsDataCommandHandlers[i].name) == 0) + return xferOsDataCommandHandlers[i].handler(ctx, write, offset, length); + } + } + + return GDB_HandleUnsupported(ctx); +} + +GDB_DECLARE_QUERY_HANDLER(Xfer) +{ + const char *objectStart = ctx->commandData; + char *objectEnd = (char*)strchr(objectStart, ':'); + if(objectEnd == NULL) return -1; + *objectEnd = 0; + + char *opStart = objectEnd + 1; + char *opEnd = (char*)strchr(opStart, ':'); + if(opEnd == NULL) return -1; + *opEnd = 0; + + char *annexStart = opEnd + 1; + char *annexEnd = (char*)strchr(annexStart, ':'); + if(annexEnd == NULL) return -1; + *annexEnd = 0; + + const char *offStart = annexEnd + 1; + u32 offset, length; + + bool write; + const char *pos; + if(strcmp(opStart, "read") == 0) + { + u32 lst[2]; + if(GDB_ParseHexIntegerList(lst, offStart, 2, 0) == NULL) + return GDB_ReplyErrno(ctx, EILSEQ); + + offset = lst[0]; + length = lst[1]; + write = false; + } + else if(strcmp(opStart, "write") == 0) + { + pos = GDB_ParseHexIntegerList(&offset, offStart, 1, ':'); + if(pos == NULL || *pos++ != ':') + return GDB_ReplyErrno(ctx, EILSEQ); + + u32 len = strlen(pos); + if(len == 0 || (len % 2) != 0) + return GDB_ReplyErrno(ctx, EILSEQ); + length = len / 2; + write = true; + } + else + return GDB_ReplyErrno(ctx, EILSEQ); + + for(u32 i = 0; i < sizeof(xferCommandHandlers) / sizeof(xferCommandHandlers[0]); i++) + { + if(strcmp(objectStart, xferCommandHandlers[i].name) == 0) + { + if(write) + ctx->commandData = (char *)pos; + + return xferCommandHandlers[i].handler(ctx, write, annexStart, offset, length); + } + } + + return GDB_HandleUnsupported(ctx); +} diff --git a/sysmodules/rosalina/source/gdb/xml/osdata.xml b/sysmodules/rosalina/source/gdb/xml/osdata.xml new file mode 100644 index 000000000..0274721ea --- /dev/null +++ b/sysmodules/rosalina/source/gdb/xml/osdata.xml @@ -0,0 +1,19 @@ + + + + + cfwversion + Listing of the Luma3DS version, commit hash, etc. + CFW + + + memory + Listing of memory usage per region + Memory + + + processes + Listing of all processes + Processes + + diff --git a/sysmodules/rosalina/source/gdb/xml/osdata_cfw_version_template.xml b/sysmodules/rosalina/source/gdb/xml/osdata_cfw_version_template.xml new file mode 100644 index 000000000..7c19a3d86 --- /dev/null +++ b/sysmodules/rosalina/source/gdb/xml/osdata_cfw_version_template.xml @@ -0,0 +1,9 @@ + + + + + %s + %08x + %s + + diff --git a/sysmodules/rosalina/source/gdb/xml/osdata_memory_template.xml b/sysmodules/rosalina/source/gdb/xml/osdata_memory_template.xml new file mode 100644 index 000000000..8b752f86b --- /dev/null +++ b/sysmodules/rosalina/source/gdb/xml/osdata_memory_template.xml @@ -0,0 +1,25 @@ + + + + + APPLICATION + %u + %u + %u + %u%% + + + SYSTEM + %u + %u + %u + %u%% + + + BASE + %u + %u + %u + %u%% + + diff --git a/sysmodules/rosalina/source/gdb/xml/target.xml b/sysmodules/rosalina/source/gdb/xml/target.xml new file mode 100644 index 000000000..70f731c21 --- /dev/null +++ b/sysmodules/rosalina/source/gdb/xml/target.xml @@ -0,0 +1,45 @@ + + + + arm + 3DS + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sysmodules/rosalina/source/hbloader.c b/sysmodules/rosalina/source/hbloader.c new file mode 100644 index 000000000..b10e12d86 --- /dev/null +++ b/sysmodules/rosalina/source/hbloader.c @@ -0,0 +1,396 @@ +/* +* 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 . +* +* 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. +*/ + +/* This file was entirely written by fincs */ + +#include <3ds.h> +#include "hbloader.h" +#include "3dsx.h" +#include "menu.h" +#include "csvc.h" +#include "memory.h" +#include "exheader.h" + +#define MAP_BASE 0x10000000 + +static const char serviceList[32][8] = +{ + "APT:U", + "ac:u", + "am:net", + "boss:P", + "cam:u", + "cfg:nor", + "cfg:u", + "csnd:SND", + "dsp::DSP", + "fs:USER", + "gsp::Lcd", + "gsp::Gpu", + "hid:USER", + "http:C", + "ir:USER", + "ir:rst", + "ir:u", + "ldr:ro", + "mic:u", + "ndm:u", + "news:s", + "nim:s", + "ns:s", + "nwm::UDS", + "nwm::EXT", + "ptm:u", + "ptm:sysm", + "pxi:dev", + "qtm:u", + "soc:U", + "ssl:C", + "y2r:u", +}; + +static const u64 dependencyList[] = +{ + 0x0004013000002402LL, //ac + 0x0004013000001502LL, //am + 0x0004013000003402LL, //boss + 0x0004013000001602LL, //camera + 0x0004013000001702LL, //cfg + 0x0004013000001802LL, //codec + 0x0004013000002702LL, //csnd + 0x0004013000002802LL, //dlp + 0x0004013000001A02LL, //dsp + 0x0004013000001B02LL, //gpio + 0x0004013000001C02LL, //gsp + 0x0004013000001D02LL, //hid + 0x0004013000002902LL, //http + 0x0004013000001E02LL, //i2c + 0x0004013000003302LL, //ir + 0x0004013000001F02LL, //mcu + 0x0004013000002002LL, //mic + 0x0004013000002B02LL, //ndm + 0x0004013000003502LL, //news + 0x0004013000002C02LL, //nim + 0x0004013000002D02LL, //nwm + 0x0004013000002102LL, //pdn + 0x0004013000003102LL, //ps + 0x0004013000002202LL, //ptm + 0x0004013000003702LL, //ro + 0x0004013000002E02LL, //socket + 0x0004013000002302LL, //spi + 0x0004013000002F02LL, //ssl +}; + +static const u32 kernelCaps[] = +{ + 0xFC00022C, // Kernel release version: 8.0 (necessary for using the new linear mapping) + 0xFF81FF50, // RW static mapping: 0x1FF50000 + 0xFF81FF58, // RW static mapping: 0x1FF58000 + 0xFF81FF70, // RW static mapping: 0x1FF70000 + 0xFF81FF78, // RW static mapping: 0x1FF78000 + 0xFF91F000, // RO static mapping: 0x1F000000 + 0xFF91F600, // RO static mapping: 0x1F600000 + 0xFF002101, // Exflags: APPLICATION memtype + "Allow debug" + "Access core2" + 0xFE000200, // Handle table size: 0x200 +}; + +static inline void assertSuccess(Result res) +{ + if(R_FAILED(res)) + svcBreak(USERBREAK_PANIC); +} + +static MyThread hbldrThread; +static u8 ALIGN(8) hbldrThreadStack[THREAD_STACK_SIZE]; +static u16 hbldrTarget[PATH_MAX+1]; + +MyThread *hbldrCreateThread(void) +{ + assertSuccess(MyThread_Create(&hbldrThread, hbldrThreadMain, hbldrThreadStack, THREAD_STACK_SIZE, 0x18, CORE_SYSTEM)); + return &hbldrThread; +} + +static inline void error(u32* cmdbuf, Result rc) +{ + cmdbuf[0] = IPC_MakeHeader(0, 1, 0); + cmdbuf[1] = rc; +} + +static u16 *u16_strncpy(u16 *dest, const u16 *src, u32 size) +{ + u32 i; + for (i = 0; i < size && src[i] != 0; i++) + dest[i] = src[i]; + while (i < size) + dest[i++] = 0; + + return dest; +} + +static void HBLDR_HandleCommands(void) +{ + Result res; + IFile file; + u32 *cmdbuf = getThreadCommandBuffer(); + switch (cmdbuf[0] >> 16) + { + case 1: + { + if (cmdbuf[0] != IPC_MakeHeader(1, 6, 0)) + { + error(cmdbuf, 0xD9001830); + break; + } + + u32 baseAddr = cmdbuf[1]; + u32 flags = cmdbuf[2] & 0xF00; + u64 tid = (u64)cmdbuf[3] | ((u64)cmdbuf[4]<<32); + char name[8]; + memcpy(name, &cmdbuf[5], sizeof(name)); + + if (hbldrTarget[0] == 0) + { + u16_strncpy(hbldrTarget, u"/boot.3dsx", PATH_MAX); + ldrArgvBuf[0] = 1; + strncpy((char*)&ldrArgvBuf[1], "sdmc:/boot.3dsx", sizeof(ldrArgvBuf)-4); + } + + res = IFile_Open(&file, ARCHIVE_SDMC, fsMakePath(PATH_EMPTY, ""), fsMakePath(PATH_UTF16, hbldrTarget), FS_OPEN_READ); + hbldrTarget[0] = 0; + if (R_FAILED(res)) + { + error(cmdbuf, res); + break; + } + + u32 totalSize = 0; + res = Ldr_Get3dsxSize(&totalSize, &file); + if (R_FAILED(res)) + { + IFile_Close(&file); + error(cmdbuf, res); + break; + } + + u32 tmp = 0; + res = svcControlMemoryEx(&tmp, MAP_BASE, 0, totalSize, MEMOP_ALLOC | flags, MEMPERM_READ | MEMPERM_WRITE, true); + if (R_FAILED(res)) + { + IFile_Close(&file); + error(cmdbuf, res); + break; + } + + Handle hCodeset = Ldr_CodesetFrom3dsx(name, (u32*)MAP_BASE, baseAddr, &file, tid); + IFile_Close(&file); + + if (!hCodeset) + { + svcControlMemory(&tmp, MAP_BASE, 0, totalSize, MEMOP_FREE, 0); + error(cmdbuf, MAKERESULT(RL_PERMANENT, RS_INTERNAL, RM_LDR, RD_NOT_FOUND)); + break; + } + + cmdbuf[0] = IPC_MakeHeader(1, 1, 2); + cmdbuf[1] = 0; + cmdbuf[2] = IPC_Desc_MoveHandles(1); + cmdbuf[3] = hCodeset; + break; + } + case 2: + { + if (cmdbuf[0] != IPC_MakeHeader(2, 0, 2) || (cmdbuf[1] & 0x3FFF) != 0x0002) + { + error(cmdbuf, 0xD9001830); + break; + } + ssize_t units = utf8_to_utf16(hbldrTarget, (const uint8_t*)cmdbuf[2], PATH_MAX); + if (units < 0 || units > PATH_MAX) + { + hbldrTarget[0] = 0; + error(cmdbuf, 0xD9001830); + break; + } + + hbldrTarget[units] = 0; + cmdbuf[0] = IPC_MakeHeader(2, 1, 0); + cmdbuf[1] = 0; + break; + } + case 3: + { + if (cmdbuf[0] != IPC_MakeHeader(3, 0, 2) || (cmdbuf[1] & 0x3FFF) != (0x2 | (1<<10))) + { + error(cmdbuf, 0xD9001830); + break; + } + // No need to do anything - the kernel already copied the data to our buffer + cmdbuf[0] = IPC_MakeHeader(3, 1, 0); + cmdbuf[1] = 0; + break; + } + case 4: + { + if (cmdbuf[0] != IPC_MakeHeader(4, 0, 2) || cmdbuf[1] != IPC_Desc_Buffer(sizeof(exheader_header), IPC_BUFFER_RW)) + { + error(cmdbuf, 0xD9001830); + break; + } + + // Perform ExHeader patches + exheader_header* exh = (exheader_header*)cmdbuf[2]; + u32 stacksize = 4096; // 3dsx/libctru don't require anymore than this + memcpy(exh->codesetinfo.name, "3dsx_app", 8); + memcpy(exh->codesetinfo.stacksize, &stacksize, 4); + memset(&exh->deplist, 0, sizeof(exh->deplist)); + memcpy(exh->deplist.programid, dependencyList, sizeof(dependencyList)); + + exheader_arm11systemlocalcaps* localcaps0 = &exh->arm11systemlocalcaps; + exheader_arm11systemlocalcaps* localcaps1 = &exh->accessdesc.arm11systemlocalcaps; + localcaps0->flags[0] = 0x00; + localcaps1->flags[0] = 0x00; + localcaps0->flags[1] = 0x01; + localcaps1->flags[1] = 0x01; + localcaps0->flags[2] = 0x04; + localcaps1->flags[2] = 0x05; + localcaps0->priority = 0x30; + localcaps1->priority = 0; + memset(localcaps0->resourcelimitdescriptor, 0, 0x10); + memset(localcaps1->resourcelimitdescriptor, 0, 0x10); + memset(localcaps0->storageinfo.accessinfo, 0xFF, 7); + memset(localcaps1->storageinfo.accessinfo, 0xFF, 7); + memcpy(localcaps0->serviceaccesscontrol, serviceList, sizeof(serviceList)); + memcpy(localcaps1->serviceaccesscontrol, serviceList, sizeof(serviceList)); + memset(localcaps0->serviceaccesscontrol+0x20, 0, 2); + memset(localcaps1->serviceaccesscontrol+0x20, 0, 2); + localcaps0->resourcelimitcategory = 0; + localcaps1->resourcelimitcategory = 0; + + exheader_arm11kernelcapabilities* kcaps0 = &exh->arm11kernelcaps; + exheader_arm11kernelcapabilities* kcaps1 = &exh->accessdesc.arm11kernelcaps; + memset(kcaps0->descriptors, 0xFF, sizeof(kcaps0->descriptors)); + memset(kcaps1->descriptors, 0xFF, sizeof(kcaps1->descriptors)); + memcpy(kcaps0->descriptors, kernelCaps, sizeof(kernelCaps)); + memcpy(kcaps1->descriptors, kernelCaps, sizeof(kernelCaps)); + + u64 lastdep = sizeof(dependencyList)/8; + if (osGetFirmVersion() >= SYSTEM_VERSION(2,50,0)) // 9.6+ FIRM + { + exh->deplist.programid[lastdep++] = 0x0004013000004002ULL; // nfc + strncpy((char*)&localcaps0->serviceaccesscontrol[0x20], "nfc:u", 8); + strncpy((char*)&localcaps1->serviceaccesscontrol[0x20], "nfc:u", 8); + s64 dummy = 0; + bool isN3DS = svcGetSystemInfo(&dummy, 0x10001, 0) == 0; + if (isN3DS) + { + exh->deplist.programid[lastdep++] = 0x0004013020004102ULL; // mvd + strncpy((char*)&localcaps0->serviceaccesscontrol[0x21], "mvd:STD", 8); + strncpy((char*)&localcaps1->serviceaccesscontrol[0x21], "mvd:STD", 8); + } + } + + cmdbuf[0] = IPC_MakeHeader(4, 1, 2); + cmdbuf[1] = 0; + cmdbuf[2] = IPC_Desc_Buffer(sizeof(exheader_header), IPC_BUFFER_RW); + cmdbuf[3] = (u32)exh; + break; + } + default: + { + error(cmdbuf, 0xD900182F); + break; + } + } +} + +void hbldrThreadMain(void) +{ + Handle handles[2]; + Handle serverHandle, clientHandle, sessionHandle = 0; + + u32 replyTarget = 0; + s32 index; + + char ipcBuf[PATH_MAX+1]; + u32* bufPtrs = getThreadStaticBuffers(); + memset(bufPtrs, 0, 16*2*4); + bufPtrs[0] = IPC_Desc_StaticBuffer(sizeof(ipcBuf), 0); + bufPtrs[1] = (u32)ipcBuf; + bufPtrs[2] = IPC_Desc_StaticBuffer(sizeof(ldrArgvBuf), 1); + bufPtrs[3] = (u32)ldrArgvBuf; + + Result res; + u32 *cmdbuf = getThreadCommandBuffer(); + + assertSuccess(svcCreatePort(&serverHandle, &clientHandle, "hb:ldr", 1)); + + do + { + handles[0] = serverHandle; + handles[1] = sessionHandle; + + if(replyTarget == 0) // k11 + cmdbuf[0] = 0xFFFF0000; + res = svcReplyAndReceive(&index, handles, sessionHandle == 0 ? 1 : 2, replyTarget); + + if(R_FAILED(res)) + { + if((u32)res == 0xC920181A) // session closed by remote + { + svcCloseHandle(sessionHandle); + sessionHandle = 0; + replyTarget = 0; + } + + else + svcBreak(USERBREAK_PANIC); + } + + else + { + if(index == 0) + { + Handle session; + assertSuccess(svcAcceptSession(&session, serverHandle)); + + if(sessionHandle == 0) + sessionHandle = session; + else + svcCloseHandle(session); + } + else + { + HBLDR_HandleCommands(); + replyTarget = sessionHandle; + } + } + } + while(!terminationRequest); + + svcCloseHandle(sessionHandle); + svcCloseHandle(clientHandle); + svcCloseHandle(serverHandle); +} diff --git a/sysmodules/rosalina/source/ifile.c b/sysmodules/rosalina/source/ifile.c new file mode 100644 index 000000000..0f45cc77f --- /dev/null +++ b/sysmodules/rosalina/source/ifile.c @@ -0,0 +1,130 @@ +/* +* 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 . +* +* 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. +*/ + +#include <3ds.h> +#include "ifile.h" + +Result IFile_Open(IFile *file, FS_ArchiveID archiveId, FS_Path archivePath, FS_Path filePath, u32 flags) +{ + Result res; + + res = FSUSER_OpenFileDirectly(&file->handle, archiveId, archivePath, filePath, flags, 0); + file->pos = 0; + file->size = 0; + return res; +} + +Result IFile_Close(IFile *file) +{ + return FSFILE_Close(file->handle); +} + +Result IFile_GetSize(IFile *file, u64 *size) +{ + Result res; + + res = FSFILE_GetSize(file->handle, size); + file->size = *size; + return res; +} + +Result IFile_Read(IFile *file, u64 *total, void *buffer, u32 len) +{ + u32 read; + u32 left; + char *buf; + u64 cur; + Result res; + + if (len == 0) + { + *total = 0; + return 0; + } + + buf = (char *)buffer; + cur = 0; + left = len; + while (1) + { + res = FSFILE_Read(file->handle, &read, file->pos, buf, left); + if (R_FAILED(res)) + { + break; + } + + cur += read; + file->pos += read; + if (read == left) + { + break; + } + buf += read; + left -= read; + } + + *total = cur; + return res; +} + +Result IFile_Write(IFile *file, u64 *total, void *buffer, u32 len, u32 flags) +{ + u32 written; + u32 left; + char *buf; + u64 cur; + Result res; + + if (len == 0) + { + *total = 0; + return 0; + } + + buf = (char *)buffer; + cur = 0; + left = len; + while (1) + { + res = FSFILE_Write(file->handle, &written, file->pos, buf, left, flags); + if (R_FAILED(res)) + { + break; + } + + cur += written; + file->pos += written; + if (written == left) + { + break; + } + buf += written; + left -= written; + } + + *total = cur; + return res; +} diff --git a/sysmodules/rosalina/source/input_redirection.c b/sysmodules/rosalina/source/input_redirection.c new file mode 100644 index 000000000..b8f379803 --- /dev/null +++ b/sysmodules/rosalina/source/input_redirection.c @@ -0,0 +1,306 @@ +/* +* 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 . +* +* 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. +*/ + +#include <3ds.h> +#include +#include "utils.h" // for makeARMBranch +#include "minisoc.h" +#include "input_redirection.h" +#include "menus.h" +#include "memory.h" + +bool inputRedirectionEnabled = false; +Handle inputRedirectionThreadStartedEvent; + +static MyThread inputRedirectionThread; +static u8 ALIGN(8) inputRedirectionThreadStack[0x4000]; + +MyThread *inputRedirectionCreateThread(void) +{ + if(R_FAILED(MyThread_Create(&inputRedirectionThread, inputRedirectionThreadMain, inputRedirectionThreadStack, 0x4000, 0x20, CORE_SYSTEM))) + svcBreak(USERBREAK_PANIC); + return &inputRedirectionThread; +} + +// local hid, local tsrd localcprd, localtswr, localcpwr, remote hid, remote ts, remote circle +static u32 hidData[] = { 0x00000FFF, 0x02000000, 0x007FF7FF, 0x00000000, 0x00000000, 0x00000FFF, 0x02000000, 0x007FF7FF }; +// remote ir +static u32 irData[] = { 0x80800081 }; // Default: C-Stick at the center, no buttons. + +int inputRedirectionStartResult; + +void inputRedirectionThreadMain(void) +{ + Result res = 0; + res = miniSocInit(); + if(R_FAILED(res)) + return; + + int sock = socSocket(AF_INET, SOCK_DGRAM, 0); + while(sock == -1) + { + svcSleepThread(1000 * 0000 * 0000LL); + sock = socSocket(AF_INET, SOCK_DGRAM, 0); + } + + struct sockaddr_in saddr; + saddr.sin_family = AF_INET; + saddr.sin_port = htons(4950); + saddr.sin_addr.s_addr = gethostid(); + res = socBind(sock, (struct sockaddr*)&saddr, sizeof(struct sockaddr_in)); + if(res != 0) + { + socClose(sock); + miniSocExit(); + inputRedirectionStartResult = res; + return; + } + + inputRedirectionEnabled = true; + svcSignalEvent(inputRedirectionThreadStartedEvent); + + u32 *hidDataPhys = PA_FROM_VA_PTR(hidData); + hidDataPhys += 5; // skip to +20 + + u32 *irDataPhys = PA_FROM_VA_PTR(irData); + + char buf[20]; + u32 oldSpecialButtons = 0, specialButtons = 0; + while(inputRedirectionEnabled && !terminationRequest) + { + struct pollfd pfd; + pfd.fd = sock; + pfd.events = POLLIN; + pfd.revents = 0; + + int pollres = socPoll(&pfd, 1, 10); + if(pollres > 0 && (pfd.revents & POLLIN)) + { + int n = soc_recvfrom(sock, buf, 20, 0, NULL, 0); + if(n < 0) + break; + else if(n < 12) + continue; + + memcpy(hidDataPhys, buf, 12); + if(n >= 20) + { + memcpy(irDataPhys, buf + 12, 4); + + oldSpecialButtons = specialButtons; + memcpy(&specialButtons, buf + 16, 4); + + if(!(oldSpecialButtons & 1) && (specialButtons & 1)) // HOME button pressed + srvPublishToSubscriber(0x204, 0); + else if((oldSpecialButtons & 1) && !(specialButtons & 1)) // HOME button released + srvPublishToSubscriber(0x205, 0); + + if(!(oldSpecialButtons & 2) && (specialButtons & 2)) // POWER button pressed + srvPublishToSubscriber(0x202, 0); + + if(!(oldSpecialButtons & 4) && (specialButtons & 4)) // POWER button held long + srvPublishToSubscriber(0x203, 0); + } + } + } + + struct linger linger; + linger.l_onoff = 1; + linger.l_linger = 0; + + socSetsockopt(sock, SOL_SOCKET, SO_LINGER, &linger, sizeof(struct linger)); + + socClose(sock); + miniSocExit(); +} + +void hidCodePatchFunc(void); +void irCodePatchFunc(void); + +Result InputRedirection_DoOrUndoPatches(void) +{ + s64 startAddress, textTotalRoundedSize, rodataTotalRoundedSize, dataTotalRoundedSize; + u32 totalSize; + Handle processHandle; + + Result res = OpenProcessByName("hid", &processHandle); + + if(R_SUCCEEDED(res)) + { + svcGetProcessInfo(&textTotalRoundedSize, processHandle, 0x10002); // only patch .text + .data + svcGetProcessInfo(&rodataTotalRoundedSize, processHandle, 0x10003); + svcGetProcessInfo(&dataTotalRoundedSize, processHandle, 0x10004); + + totalSize = (u32)(textTotalRoundedSize + rodataTotalRoundedSize + dataTotalRoundedSize); + + svcGetProcessInfo(&startAddress, processHandle, 0x10005); + res = svcMapProcessMemoryEx(processHandle, 0x00100000, (u32) startAddress, totalSize); + + if(R_SUCCEEDED(res)) + { + static const u32 hidOrigRegisterAndValue[] = { 0x1EC46000, 0x4001 }; + static const u32 hidOrigCode[] = { + 0xE92D4070, // push {r4-r6, lr} + 0xE1A05001, // mov r5, r1 + 0xEE1D4F70, // mrc p15, 0, r4, c13, c0, 3 + 0xE3A01801, // mov r1, #0x10000 + 0xE5A41080, // str r1, [r4,#0x80]! + }; + + static u32 *hidRegPatchOffsets[2]; + static u32 *hidPatchJumpLoc; + + if(inputRedirectionEnabled) + { + memcpy(hidRegPatchOffsets[0], &hidOrigRegisterAndValue, sizeof(hidOrigRegisterAndValue)); + memcpy(hidRegPatchOffsets[1], &hidOrigRegisterAndValue, sizeof(hidOrigRegisterAndValue)); + memcpy(hidPatchJumpLoc, &hidOrigCode, sizeof(hidOrigCode)); + } + else + { + u32 hidDataPhys = (u32)PA_FROM_VA_PTR(hidData); + u32 hidCodePhys = (u32)PA_FROM_VA_PTR(&hidCodePatchFunc); + u32 hidHook[] = { + 0xE59F3004, // ldr r3, [pc, #4] + 0xE59FC004, // ldr r12, [pc, #4] + 0xE12FFF1C, // bx r12 + hidDataPhys, + hidCodePhys, + }; + + u32 *off = (u32 *)memsearch((u8 *)0x00100000, &hidOrigRegisterAndValue, totalSize, sizeof(hidOrigRegisterAndValue)); + if(off == NULL) + { + svcUnmapProcessMemoryEx(processHandle, 0x00100000, totalSize); + return -1; + } + + u32 *off2 = (u32 *)memsearch((u8 *)off + sizeof(hidOrigRegisterAndValue), &hidOrigRegisterAndValue, totalSize - ((u32)off - 0x00100000), sizeof(hidOrigRegisterAndValue)); + if(off2 == NULL) + { + svcUnmapProcessMemoryEx(processHandle, 0x00100000, totalSize); + return -2; + } + + u32 *off3 = (u32 *)memsearch((u8 *)0x00100000, &hidOrigCode, totalSize, sizeof(hidOrigCode)); + if(off3 == NULL) + { + svcUnmapProcessMemoryEx(processHandle, 0x00100000, totalSize); + return -3; + } + + hidRegPatchOffsets[0] = off; + hidRegPatchOffsets[1] = off2; + hidPatchJumpLoc = off3; + + *off = *off2 = hidDataPhys; + memcpy(off3, &hidHook, sizeof(hidHook)); + } + } + + res = svcUnmapProcessMemoryEx(processHandle, 0x00100000, totalSize); + } + + res = OpenProcessByName("ir", &processHandle); + if(R_SUCCEEDED(res)) + { + svcGetProcessInfo(&textTotalRoundedSize, processHandle, 0x10002); // only patch .text + .data + svcGetProcessInfo(&rodataTotalRoundedSize, processHandle, 0x10003); + svcGetProcessInfo(&dataTotalRoundedSize, processHandle, 0x10004); + + totalSize = (u32)(textTotalRoundedSize + rodataTotalRoundedSize + dataTotalRoundedSize); + + svcGetProcessInfo(&startAddress, processHandle, 0x10005); + res = svcMapProcessMemoryEx(processHandle, 0x00100000, (u32) startAddress, totalSize); + + if(R_SUCCEEDED(res)) + { + static u32 irOrigReadingCode[5] = { + 0xE5940000, // ldr r0, [r4] + 0xE1A01005, // mov r1, r5 + 0xE3A03005, // mov r3, #5 + 0xE3A02011, // mov r2, #17 + }; + + static const u32 irOrigWaitSyncCode[] = { + 0xEF000024, // svc 0x24 (WaitSynchronization) + 0xE1B01FA0, // movs r1, r0,lsr#31 + 0xE1A0A000, // mov r10, r0 + }; + + static u32 *irHookLoc, *irWaitSyncLoc; + + if(inputRedirectionEnabled) + { + memcpy(irHookLoc, &irOrigReadingCode, sizeof(irOrigReadingCode)); + memcpy(irWaitSyncLoc, &irOrigWaitSyncCode, sizeof(irOrigWaitSyncCode)); + } + else + { + u32 irDataPhys = (u32)PA_FROM_VA_PTR(irData); + u32 irCodePhys = (u32)PA_FROM_VA_PTR(&irCodePatchFunc); + + u32 irHook[] = { + 0xE59F0004, // ldr r0, [pc, #4] + 0xE59FC004, // ldr r12, [pc, #4] + 0xE12FFF1C, // bx r12 + irDataPhys, + irCodePhys, + }; + + u32 *off = (u32 *)memsearch((u8 *)0x00100000, &irOrigReadingCode, totalSize, sizeof(irOrigReadingCode) - 4); + if(off == NULL) + { + svcUnmapProcessMemoryEx(processHandle, 0x00100000, totalSize); + return -4; + } + + u32 *off2 = (u32 *)memsearch((u8 *)0x00100000, &irOrigWaitSyncCode, totalSize, sizeof(irOrigWaitSyncCode)); + if(off2 == NULL) + { + svcUnmapProcessMemoryEx(processHandle, 0x00100000, totalSize); + return -5; + } + + *(void **)(irCodePhys + 4) = decodeARMBranch(off + 4); + + irHookLoc = off; + irWaitSyncLoc = off2; + + irOrigReadingCode[4] = off[4]; + memcpy(irHookLoc, &irHook, sizeof(irHook)); + + // This "NOP"s out a WaitSynchronisation1 (on the event bound to the 'IR' interrupt) + *irWaitSyncLoc = 0xE3A00000; // mov r0, #0 + memcpy((u32*)irHookLoc, irHook, sizeof(irHook)); + } + } + + res = svcUnmapProcessMemoryEx(processHandle, 0x00100000, totalSize); + } + + return res; +} diff --git a/sysmodules/rosalina/source/input_redirection_hooks.s b/sysmodules/rosalina/source/input_redirection_hooks.s new file mode 100644 index 000000000..0d5da7807 --- /dev/null +++ b/sysmodules/rosalina/source/input_redirection_hooks.s @@ -0,0 +1,140 @@ +@ 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 . +@ +@ 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. + +@ Hooks mainly written by Stary (PoC originally by Shiny Quagsire) + +.section .rodata +.balign 4 +.arm + +@@@@@ HID hook @@@@@ +.global hidCodePatchFunc +.type hidCodePatchFunc, %function +hidCodePatchFunc: +push {r4-r6, lr} + +push {r3} +mov r5, r1 +mrc p15, 0, r4, c13, c0, 3 +mov r1, #0x10000 +str r1, [r4,#0x80]! +ldr r0, [r0] +svc 0x32 +mov r12, r0 +pop {r3} + +cmp r12, #0 +bne skip_touch_cp_cpy + +ldrd r0, [r4,#8] @ load the touch/cp regs into into r0/1 +strd r0, [r3, #12] @ write to r3+12 +ldrd r0, [r3, #4] @ read from r3+4 +strd r0, [r5] + +skip_touch_cp_cpy: + +@ +0 +4 +8 +12 +16 +20 +24 +28 +@ local hid, local tsrd localcprd, localtswr, localcpwr, remote hid, remote ts, remote circle +@u32 hidData[] = {0x00000FFF, 0x02000000, 0x007FF7FF, 0x00000000, 0x00000000, 0x00000FFF, 0x02000000, 0x007FF7FF}; + +mov r0, r3 @ Base address. +ldr r1, =0x1ec46000 @ HID reg address. +mov r3, #0xf00 +orr r3, #0xff + +@ HID reg. Copy +20 => +0 if remote is not exactly 0xfff. Else, pass local through. +ldr r1, [r1] @ Read HID reg. +ldr r2, [r0, #20] @ Load remote HID reg. +cmp r2, r3 @ Is remote 0xfff? +movne r1, r2 @ If not, load remote. +str r1, [r0] + +@ Touch screen. Copy +24 => +4 if remote is not exactly 0x2000000. Else, pass local through (+12 => +4) +cmp r12, #0 @ full success check + +mov r3, #0x2000000 +ldreq r1, [r0, #12] @ Load the original (written) touch value. +movne r1, r3 +ldr r2, [r0, #24] @ Load the remote touch value. +cmp r2, r3 @ Is remote 0x2000000? +movne r1, r2 @ If not, load remote. +str r1, [r0, #4] @ Store. + +@ Circle pad. Copy +28 => +8 if remote is not exactly 0x7FF7FF. Else, pass local through. (+16 => +8) +cmp r12, #0 @ full success check + +ldr r3, =0x7ff7ff +ldreq r1, [r0, #16] @ Load the original (written) circle value. +movne r1, r3 +ldr r2, [r0, #28] @ Load the remote circle value. +cmp r2, r3 @ Is remote 0x7FF7FF? +movne r1, r2 @ If not, load remote. +str r1, [r0, #8] @ Store. + +ldr r0, [r4,#4] + +pop {r4-r6, pc} + +.pool + +@@@@@ IR hook @@@@@ +.global irCodePatchFunc +.type irCodePatchFunc, %function +irCodePatchFunc: +b skip_vars + +i2c_readdeviceraw_addr: + .word 0 + +skip_vars: + +@ Address to read from is passed by the hook, save it. +mov r6, r0 + +ir_check_i2c: +@ Original code. Does an i2c read at device 17 func 5. +ldr r0, [r4] +mov r1, r5 +mov r2, #17 +mov r3, #5 + +adr r12, i2c_readdeviceraw_addr +ldr r12, [r12] +blx r12 + +ldr r1, =0x80800081 @ no c-stick activity / zlzr not pressed +cmp r0, #0 @ check if the i2c read succeeded completely + +ldreq r2, [r5] +tsteq r2, #0x100 @ apparently this is set only if the c-stick hasn't been moved yet +movne r2, r1 + +cmp r1, r2 +ldreq r0, [r6] @ Pull the remote input in. +streq r0, [r5] @ store it instead of the value read from i2c + +@ Return! +ldmfd sp!, {r4-r6,pc} + +.pool diff --git a/sysmodules/rosalina/source/kernel_extension.s b/sysmodules/rosalina/source/kernel_extension.s new file mode 100644 index 000000000..dc37eb420 --- /dev/null +++ b/sysmodules/rosalina/source/kernel_extension.s @@ -0,0 +1,61 @@ +@ 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 . +@ +@ 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. + +.text +.arm +.balign 4 + +.global svc0x2F +.type svc0x2F, %function +svc0x2F: + @ custom backdoor before kernel ext. is installed + svc 0x2F + bx lr + +.global convertVAToPA +.type convertVAToPA, %function +convertVAToPA: + @ needs to be executed in supervisor mode + mov r1, #0x1000 + sub r1, #1 + and r2, r0, r1 + bic r0, r1 + mcr p15, 0, r0, c7, c8, 0 @ VA to PA translation with privileged read permission check + mrc p15, 0, r0, c7, c4, 0 @ read PA register + tst r0, #1 @ failure bit + bic r0, r1 + addeq r0, r2 + movne r0, #0 + bx lr + +.section .data + +.p2align 12 +.global kernel_extension +kernel_extension: .incbin "build/kernel_extension.bin" +.p2align 12 +kernel_extension_end: + +.global kernel_extension_size +kernel_extension_size: .word kernel_extension_end - kernel_extension diff --git a/sysmodules/rosalina/source/kernel_extension_setup.c b/sysmodules/rosalina/source/kernel_extension_setup.c new file mode 100644 index 000000000..24bc07fa0 --- /dev/null +++ b/sysmodules/rosalina/source/kernel_extension_setup.c @@ -0,0 +1,146 @@ +/* +* 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 . +* +* 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. +*/ + +#include "kernel_extension.h" +#include "kernel_extension_setup.h" + +#define MPCORE_REGS_BASE ((u32)PA_PTR(0x17E00000)) +#define MPCORE_GID_REGS_BASE (MPCORE_REGS_BASE + 0x1000) +#define MPCORE_GID_SGI (*(vu32 *)(MPCORE_GID_REGS_BASE + 0xF00)) + +struct Parameters +{ + void (*SGI0HandlerCallback)(struct Parameters *, u32 *); + void *interruptManager; + u32 *L2MMUTable; // bit31 mapping + + void (*initFPU)(void); + void (*mcuReboot)(void); + void (*coreBarrier)(void); + + u32 TTBCR; + u32 L1MMUTableAddrs[4]; + + u32 kernelVersion; + + struct CfwInfo + { + char magic[4]; + + u8 versionMajor; + u8 versionMinor; + u8 versionBuild; + u8 flags; + + u32 commitHash; + + u32 config; + } __attribute__((packed)) info; +}; + + +static void K_SGI0HandlerCallback(volatile struct Parameters *p) +{ + u32 L1MMUTableAddr; + vu32 *L1MMUTable; + u32 coreId; + + __asm__ volatile("cpsid aif"); // disable interrupts + + p->coreBarrier(); + + __asm__ volatile("mrc p15, 0, %0, c0, c0, 5" : "=r"(coreId)); + coreId &= 3; + + __asm__ volatile("mrc p15, 0, %0, c2, c0, 1" : "=r"(L1MMUTableAddr)); + L1MMUTableAddr &= ~0x3FFF; + p->L1MMUTableAddrs[coreId] = L1MMUTableAddr; + L1MMUTable = (vu32 *)(L1MMUTableAddr | (1 << 31)); + + // Actually map the kernel ext + u32 L2MMUTableAddr = (u32)(p->L2MMUTable) & ~(1 << 31); + L1MMUTable[0x40000000 >> 20] = L2MMUTableAddr | 1; + + __asm__ __volatile__("mcr p15, 0, %[val], c7, c10, 4" :: [val] "r" (0) : "memory"); + ((void (*)(volatile struct Parameters *))0x40000000)(p); + + p->coreBarrier(); +} + +static u32 ALIGN(0x400) L2MMUTableFor0x40000000[256] = { 0 }; +u32 TTBCR; +static void K_ConfigureSGI0(void) +{ + // see /patches/k11MainHook.s + u32 *off; + u32 *initFPU, *mcuReboot, *coreBarrier; + + // Search for stuff in the 0xFFFF0000 page + for(initFPU = (u32 *)0xFFFF0000; initFPU < (u32 *)0xFFFF1000 && *initFPU != 0xE1A0D002; initFPU++); + initFPU += 3; + + for(mcuReboot = initFPU; mcuReboot < (u32 *)0xFFFF1000 && *mcuReboot != 0xE3A0A0C2; mcuReboot++); + mcuReboot--; + coreBarrier = (u32 *)decodeARMBranch(mcuReboot - 4); + + for(off = mcuReboot; off < (u32 *)0xFFFF1000 && *off != 0x726C6468; off++); // "hdlr" + + volatile struct Parameters *p = (struct Parameters *)PA_FROM_VA_PTR(off); // Caches? What are caches? + p->SGI0HandlerCallback = (void (*)(struct Parameters *, u32 *))PA_FROM_VA_PTR(K_SGI0HandlerCallback); + p->L2MMUTable = (u32 *)PA_FROM_VA_PTR(L2MMUTableFor0x40000000); + p->initFPU = (void (*) (void))initFPU; + p->mcuReboot = (void (*) (void))mcuReboot; + p->coreBarrier = (void (*) (void))coreBarrier; + + __asm__ volatile("mrc p15, 0, %0, c2, c0, 2" : "=r"(TTBCR)); + p->TTBCR = TTBCR; + + p->kernelVersion = *(vu32 *)0x1FF80000; + + // Now let's configure the L2 table + + //4KB extended small pages: [SYS:RW USR:-- X TYP:NORMAL SHARED OUTER NOCACHE, INNER CACHED WB WA] + for(u32 offset = 0; offset < kernel_extension_size; offset += 0x1000) + L2MMUTableFor0x40000000[offset >> 12] = (u32)convertVAToPA(kernel_extension + offset) | 0x516; +} + +static void K_SendSGI0ToAllCores(void) +{ + MPCORE_GID_SGI = 0xF0000; // http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0360f/CACGDJJC.html +} + +static inline void flushAllCaches(void) +{ + svcUnmapProcessMemory(CUR_PROCESS_HANDLE, 0, 0); // this SVC flush both caches entirely (and properly) even when returing an error +} + +void installKernelExtension(void) +{ + svc0x2F(K_ConfigureSGI0); + flushAllCaches(); + svc0x2F(K_SendSGI0ToAllCores); + flushAllCaches(); +} diff --git a/sysmodules/rosalina/source/main.c b/sysmodules/rosalina/source/main.c new file mode 100644 index 000000000..7458cd65c --- /dev/null +++ b/sysmodules/rosalina/source/main.c @@ -0,0 +1,129 @@ +/* +* 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 . +* +* 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. +*/ + +#include <3ds.h> +#include "memory.h" +#include "services.h" +#include "fsreg.h" +#include "menu.h" +#include "errdisp.h" +#include "hbloader.h" +#include "utils.h" +#include "MyThread.h" +#include "kernel_extension_setup.h" +#include "menus/process_patches.h" + +// this is called before main +bool isN3DS; +void __appInit() +{ + srvSysInit(); + fsregInit(); + fsSysInit(); + + s64 dummy; + isN3DS = svcGetSystemInfo(&dummy, 0x10001, 0) == 0; +} + +// this is called after main exits +void __appExit() +{ + fsExit(); + fsregExit(); + srvSysExit(); +} + + +Result __sync_init(void); +Result __sync_fini(void); +void __libc_init_array(void); +void __libc_fini_array(void); + +void __ctru_exit() +{ + __appExit(); + __sync_fini(); + __libc_fini_array(); + svcSleepThread(-1LL); // kernel-loaded sysmodules except PXI are not supposed to terminate anyways + svcExitProcess(); +} + + +void initSystem() +{ + __libc_init_array(); + + HBLDR_3DSX_TID = HBLDR_DEFAULT_3DSX_TID; + installKernelExtension(); + + __sync_init(); + __appInit(); +} + +bool terminationRequest = false; +Handle terminationRequestEvent; + +int main(void) +{ + Result res = 0; + Handle notificationHandle; + + MyThread *menuThread = menuCreateThread(), *errDispThread = errDispCreateThread(), *hbldrThread = hbldrCreateThread(); + + if(R_FAILED(srvEnableNotification(¬ificationHandle))) + svcBreak(USERBREAK_ASSERT); + + if(R_FAILED(svcCreateEvent(&terminationRequestEvent, RESET_STICKY))) + svcBreak(USERBREAK_ASSERT); + + do + { + res = svcWaitSynchronization(notificationHandle, -1LL); + + if(R_FAILED(res)) + continue; + + u32 notifId = 0; + + if(R_FAILED(srvReceiveNotification(¬ifId))) + svcBreak(USERBREAK_ASSERT); + + if(notifId == 0x100) + { + // Termination request + terminationRequest = true; + svcSignalEvent(terminationRequestEvent); + } + } + while(!terminationRequest); + + MyThread_Join(menuThread, -1LL); + MyThread_Join(errDispThread, -1LL); + MyThread_Join(hbldrThread, -1LL); + + svcCloseHandle(notificationHandle); + return 0; +} diff --git a/sysmodules/rosalina/source/memory.c b/sysmodules/rosalina/source/memory.c new file mode 100644 index 000000000..de08c3d36 --- /dev/null +++ b/sysmodules/rosalina/source/memory.c @@ -0,0 +1,274 @@ +/* +* 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 . +* +* 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. +*/ + +#include "memory.h" + +void *memcpy(void *dest, const void *src, u32 size) +{ + u8 *destc = (u8 *)dest; + const u8 *srcc = (const u8 *)src; + + for(u32 i = 0; i < size; i++) + destc[i] = srcc[i]; + + return dest; +} + +int memcmp(const void *buf1, const void *buf2, u32 size) +{ + const u8 *buf1c = (const u8 *)buf1; + const u8 *buf2c = (const u8 *)buf2; + + for(u32 i = 0; i < size; i++) + { + int cmp = buf1c[i] - buf2c[i]; + if(cmp) + return cmp; + } + + return 0; +} + +void *memset(void *dest, u32 value, u32 size) +{ + u8 *destc = (u8 *)dest; + + for(u32 i = 0; i < size; i++) destc[i] = (u8)value; + + return dest; +} + +void *memset32(void *dest, u32 value, u32 size) +{ + u32 *dest32 = (u32 *)dest; + + for(u32 i = 0; i < size/4; i++) dest32[i] = value; + + return dest; +} + +//Boyer-Moore Horspool algorithm, adapted from http://www-igm.univ-mlv.fr/~lecroq/string/node18.html#SECTION00180 +u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSize) +{ + const u8 *patternc = (const u8 *)pattern; + u32 table[256]; + + //Preprocessing + for(u32 i = 0; i < 256; i++) + table[i] = patternSize; + for(u32 i = 0; i < patternSize - 1; i++) + table[patternc[i]] = patternSize - i - 1; + + //Searching + u32 j = 0; + while(j <= size - patternSize) + { + u8 c = startPos[j + patternSize - 1]; + if(patternc[patternSize - 1] == c && memcmp(pattern, startPos + j, patternSize - 1) == 0) + return startPos + j; + j += table[c]; + } + + return NULL; +} + +char *strcpy(char *dest, const char *src) +{ + u32 i; + for(i = 0; src[i] != 0; i++) + dest[i] = src[i]; + + dest[i] = 0; + + return dest; +} + +char *strncpy(char *dest, const char *src, u32 size) +{ + u32 i; + for(i = 0; i < size && src[i] != 0; i++) + dest[i] = src[i]; + + for(; i < size; i++) + dest[i] = 0; + + return dest; +} + +s32 strnlen(const char *string, s32 maxlen) +{ + s32 size; + for(size = 0; size < maxlen && *string; string++, size++); + + return size; +} + +s32 strlen(const char *string) +{ + char *stringEnd = (char *)string; + while(*stringEnd) stringEnd++; + + return stringEnd - string; +} + +s32 strcmp(const char *str1, const char *str2) +{ + while(*str1 && (*str1 == *str2)) + { + str1++; + str2++; + } + + return *str1 - *str2; +} + +s32 strncmp(const char *str1, const char *str2, u32 size) +{ + while(size && *str1 && (*str1 == *str2)) + { + str1++; + str2++; + size--; + } + if (!size) + return 0; + else + return *(u8*)str1 - *(u8*)str2; +} + +const char *strchr(const char *string, int c) +{ + char *stringEnd = (char *)string; + while(*stringEnd != 0) + { + if(*stringEnd == c) return stringEnd; + stringEnd++; + } + + return NULL; +} + +void hexItoa(u64 number, char *out, u32 digits, bool uppercase) +{ + const char hexDigits[] = "0123456789ABCDEF"; + const char hexDigitsLowercase[] = "0123456789abcdef"; + u32 i = 0; + + while(number > 0) + { + out[digits - 1 - i++] = uppercase ? hexDigits[number & 0xF] : hexDigitsLowercase[number & 0xF]; + number >>= 4; + } + + while(i < digits) out[digits - 1 - i++] = '0'; +} + + +// Copied from newlib, without the reent stuff + some other stuff +unsigned long int xstrtoul(const char *nptr, char **endptr, int base, bool allowPrefix, bool *ok) +{ + register const unsigned char *s = (const unsigned char *)nptr; + register unsigned long acc; + register int c; + register unsigned long cutoff; + register int neg = 0, any, cutlim; + + if(ok != NULL) + *ok = true; + /* + * See strtol for comments as to the logic used. + */ + do { + c = *s++; + } while ((c >= 9 && c <= 13) || c == ' '); + if (c == '-') { + if(!allowPrefix) { + if(ok != NULL) + *ok = false; + return 0; + } + neg = 1; + c = *s++; + } else if (c == '+'){ + if(!allowPrefix) { + if(ok != NULL) + *ok = false; + return 0; + } + + c = *s++; + } + if ((base == 0 || base == 16) && + c == '0' && (*s == 'x' || *s == 'X')) { + + if(!allowPrefix) { + if(ok != NULL) + *ok = false; + return 0; + } + c = s[1]; + s += 2; + base = 16; + } + if (base == 0) { + if(!allowPrefix) { + if(ok != NULL) + *ok = false; + return 0; + } + + base = c == '0' ? 8 : 10; + } + cutoff = (unsigned long)(-1) / (unsigned long)base; + cutlim = (unsigned long)(-1) % (unsigned long)base; + for (acc = 0, any = 0;; c = *s++) { + if (c >= '0' && c <= '9') + c -= '0'; + else if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) + c -= c >= 'A' && c <= 'Z' ? 'A' - 10 : 'a' - 10; + else + break; + if (c >= base) + break; + if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) + any = -1; + else { + any = 1; + acc *= base; + acc += c; + } + } + if (any < 0) { + acc = (unsigned long)-1; + if(ok != NULL) + *ok = false; +// rptr->_errno = ERANGE; + } else if (neg) + acc = -acc; + if (endptr != 0) + *endptr = (char *) (any ? (char *)s - 1 : nptr); + return (acc); +} diff --git a/sysmodules/rosalina/source/menu.c b/sysmodules/rosalina/source/menu.c new file mode 100644 index 000000000..087a56c89 --- /dev/null +++ b/sysmodules/rosalina/source/menu.c @@ -0,0 +1,285 @@ +/* +* 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 . +* +* 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. +*/ + +#include <3ds.h> +#include "menu.h" +#include "draw.h" +#include "fmt.h" +#include "memory.h" +#include "ifile.h" +#include "menus.h" +#include "utils.h" +#include "menus/n3ds.h" + +u32 waitInputWithTimeout(u32 msec) +{ + bool pressedKey = false; + u32 key = 0; + u32 n = 0; + + //Wait for no keys to be pressed + while(HID_PAD && !terminationRequest && (msec == 0 || n < msec)) + { + svcSleepThread(1 * 1000 * 1000LL); + n++; + } + + if(terminationRequest || (msec != 0 && n >= msec)) + return 0; + + do + { + //Wait for a key to be pressed + while(!HID_PAD && !terminationRequest && (msec == 0 || n < msec)) + { + svcSleepThread(1 * 1000 * 1000LL); + n++; + } + + if(terminationRequest || (msec != 0 && n >= msec)) + return 0; + + key = HID_PAD; + + //Make sure it's pressed + for(u32 i = 0x26000; i > 0; i --) + { + if(key != HID_PAD) break; + if(i == 1) pressedKey = true; + } + } + while(!pressedKey); + + return key; +} + +u32 waitInput(void) +{ + return waitInputWithTimeout(0); +} + +static Result _MCUHWC_GetBatteryLevel(u8 *out) +{ + #define TRY(expr) if(R_FAILED(res = (expr))) { svcCloseHandle(mcuhwcHandle); return res; } + Result res; + Handle mcuhwcHandle; + + TRY(srvGetServiceHandle(&mcuhwcHandle, "mcu::HWC")); + + u32 *cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x50000; + + TRY(svcSendSyncRequest(mcuhwcHandle)); + + *out = (u8) cmdbuf[2]; + + svcCloseHandle(mcuhwcHandle); + return cmdbuf[1]; + + #undef TRY +} + +static MyThread menuThread; +static u8 ALIGN(8) menuThreadStack[THREAD_STACK_SIZE]; +static u8 batteryLevel = 255; + +MyThread *menuCreateThread(void) +{ + if(R_FAILED(MyThread_Create(&menuThread, menuThreadMain, menuThreadStack, THREAD_STACK_SIZE, 0x18, CORE_SYSTEM))) + svcBreak(USERBREAK_PANIC); + return &menuThread; +} + +extern bool isN3DS; +u32 menuCombo = DEFAULT_MENU_COMBO; + +void menuThreadMain(void) +{ + if(!isN3DS) + { + rosalinaMenu.nbItems--; + for(u32 i = 3; i <= rosalinaMenu.nbItems; i++) + rosalinaMenu.items[i] = rosalinaMenu.items[i+1]; + } + else + N3DSMenu_UpdateStatus(); + + while(!terminationRequest) + { + if((HID_PAD & menuCombo) == menuCombo) + { + menuEnter(); + menuShow(&rosalinaMenu); + menuLeave(); + } + svcSleepThread(50 * 1000 * 1000LL); + } +} + +static s32 menuRefCount = 0; +void menuEnter(void) +{ + if(AtomicPostIncrement(&menuRefCount) == 0) + { + svcKernelSetState(0x10000, 1); + svcSleepThread(5 * 1000 * 100LL); + Draw_SetupFramebuffer(); + Draw_ClearFramebuffer(); + } +} + +void menuLeave(void) +{ + svcSleepThread(50 * 1000 * 1000); + + if(AtomicDecrement(&menuRefCount) == 0) + { + Draw_Lock(); + Draw_FlushFramebuffer(); + Draw_RestoreFramebuffer(); + Draw_Unlock(); + svcKernelSetState(0x10000, 1); + } +} + +static void menuDraw(Menu *menu, u32 selected) +{ + char versionString[16]; + s64 out; + u32 version, commitHash; + bool isRelease; + + if(R_FAILED(_MCUHWC_GetBatteryLevel(&batteryLevel))) + batteryLevel = 255; + + svcGetSystemInfo(&out, 0x10000, 0); + version = (u32)out; + + svcGetSystemInfo(&out, 0x10000, 1); + commitHash = (u32)out; + + svcGetSystemInfo(&out, 0x10000, 3); + isRelease = (bool)out; + + if(GET_VERSION_REVISION(version) == 0) + sprintf(versionString, "v%u.%u", GET_VERSION_MAJOR(version), GET_VERSION_MINOR(version)); + else + sprintf(versionString, "v%u.%u.%u", GET_VERSION_MAJOR(version), GET_VERSION_MINOR(version), GET_VERSION_REVISION(version)); + + Draw_DrawString(10, 10, COLOR_TITLE, menu->title); + + for(u32 i = 0; i < 15; i++) + { + if(i >= menu->nbItems) + break; + Draw_DrawString(30, 30 + i * SPACING_Y, COLOR_WHITE, menu->items[i].title); + Draw_DrawCharacter(10, 30 + i * SPACING_Y, COLOR_TITLE, i == selected ? '>' : ' '); + } + + if(batteryLevel != 255) + Draw_DrawFormattedString(SCREEN_BOT_WIDTH - 10 - 4 * SPACING_X, SCREEN_BOT_HEIGHT - 20, COLOR_WHITE, "%02hhu%%", batteryLevel); + else + Draw_DrawString(SCREEN_BOT_WIDTH - 10 - 4 * SPACING_X, SCREEN_BOT_HEIGHT - 20, COLOR_WHITE, " "); + + if(isRelease) + Draw_DrawFormattedString(10, SCREEN_BOT_HEIGHT - 20, COLOR_TITLE, "Luma3DS %s", versionString); + else + Draw_DrawFormattedString(10, SCREEN_BOT_HEIGHT - 20, COLOR_TITLE, "Luma3DS %s-%08x", versionString, commitHash); + + Draw_FlushFramebuffer(); +} + +void menuShow(Menu *root) +{ + u32 selectedItem = 0; + Menu *currentMenu = root; + u32 nbPreviousMenus = 0; + Menu *previousMenus[0x80]; + + Draw_Lock(); + Draw_ClearFramebuffer(); + Draw_FlushFramebuffer(); + menuDraw(currentMenu, selectedItem); + Draw_Unlock(); + + do + { + u32 pressed = waitInputWithTimeout(1000); + + if(pressed & BUTTON_A) + { + Draw_Lock(); + Draw_ClearFramebuffer(); + Draw_FlushFramebuffer(); + Draw_Unlock(); + + switch(currentMenu->items[selectedItem].action_type) + { + case METHOD: + if(currentMenu->items[selectedItem].method != NULL) + currentMenu->items[selectedItem].method(); + break; + case MENU: + previousMenus[nbPreviousMenus++] = currentMenu; + currentMenu = currentMenu->items[selectedItem].menu; + selectedItem = 0; + break; + } + + Draw_Lock(); + Draw_ClearFramebuffer(); + Draw_FlushFramebuffer(); + Draw_Unlock(); + } + else if(pressed & BUTTON_B) + { + Draw_Lock(); + Draw_ClearFramebuffer(); + Draw_FlushFramebuffer(); + Draw_Unlock(); + + if(nbPreviousMenus > 0) + currentMenu = previousMenus[--nbPreviousMenus]; + else + break; + } + else if(pressed & BUTTON_DOWN) + { + if(++selectedItem >= currentMenu->nbItems) + selectedItem = 0; + } + else if(pressed & BUTTON_UP) + { + if(selectedItem-- <= 0) + selectedItem = currentMenu->nbItems - 1; + } + + Draw_Lock(); + menuDraw(currentMenu, selectedItem); + Draw_Unlock(); + } + while(!terminationRequest); +} diff --git a/sysmodules/rosalina/source/menus.c b/sysmodules/rosalina/source/menus.c new file mode 100644 index 000000000..fe0f613b7 --- /dev/null +++ b/sysmodules/rosalina/source/menus.c @@ -0,0 +1,202 @@ +/* +* 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 . +* +* 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. +*/ + +#include <3ds.h> +#include "menus.h" +#include "menu.h" +#include "draw.h" +#include "menus/process_list.h" +#include "menus/process_patches.h" +#include "menus/n3ds.h" +#include "menus/debugger.h" +#include "menus/miscellaneous.h" +#include "ifile.h" +#include "memory.h" +#include "fmt.h" + +Menu rosalinaMenu = { + "Rosalina menu", + .nbItems = 7, + { + { "Process list", METHOD, .method = &RosalinaMenu_ProcessList }, + { "Process patches menu...", MENU, .menu = &processPatchesMenu }, + { "Take screenshot (slow!)", METHOD, .method = &RosalinaMenu_TakeScreenshot }, + { "New 3DS menu...", MENU, .menu = &N3DSMenu }, + { "Debugger options...", MENU, .menu = &debuggerMenu }, + { "Miscellaneous options...", MENU, .menu = &miscellaneousMenu }, + { "Credits", METHOD, .method = &RosalinaMenu_ShowCredits } + } +}; + +void RosalinaMenu_ShowCredits(void) +{ + Draw_Lock(); + Draw_ClearFramebuffer(); + Draw_FlushFramebuffer(); + Draw_Unlock(); + + do + { + Draw_Lock(); + Draw_DrawString(10, 10, COLOR_TITLE, "Rosalina -- Luma3DS credits"); + + u32 posY = Draw_DrawString(10, 30, COLOR_WHITE, "Luma3DS (c) 2016-2017 AuroraWright, TuxSH") + SPACING_Y; + + posY = Draw_DrawString(10, posY + SPACING_Y, COLOR_WHITE, "3DSX loading code by fincs"); + posY = Draw_DrawString(10, posY + SPACING_Y, COLOR_WHITE, "Networking code & basic GDB functionality by Stary"); + posY = Draw_DrawString(10, posY + SPACING_Y, COLOR_WHITE, "InputRedirection by Stary (PoC by ShinyQuagsire)"); + + posY += 2 * SPACING_Y; + + Draw_DrawString(10, posY, COLOR_WHITE, + ( + "Special thanks to:\n" + " Bond697, WinterMute, yifanlu,\n" + " Luma3DS contributors, ctrulib contributors,\n" + " other people" + )); + + Draw_FlushFramebuffer(); + Draw_Unlock(); + } + while(!(waitInput() & BUTTON_B) && !terminationRequest); +} + +void RosalinaMenu_TakeScreenshot(void) +{ +#define TRY(expr) if(R_FAILED(res = (expr))) goto end; + + u64 total; + IFile file; + u8 buf[54]; + Result res; + + u32 filenum; + char filename[64]; + + FS_Archive archive; + FS_ArchiveID archiveId; + s64 out; + bool isSdMode; + + if(R_FAILED(svcGetSystemInfo(&out, 0x10000, 6))) svcBreak(USERBREAK_ASSERT); + isSdMode = (bool)out; + + archiveId = isSdMode ? ARCHIVE_SDMC : ARCHIVE_NAND_RW; + Draw_Lock(); + Draw_RestoreFramebuffer(); + + res = FSUSER_OpenArchive(&archive, archiveId, fsMakePath(PATH_EMPTY, "")); + if(R_SUCCEEDED(res)) + { + res = FSUSER_CreateDirectory(archive, fsMakePath(PATH_ASCII, "/luma/screenshots"), 0); + if((u32)res == 0xC82044BE) // directory already exists + res = 0; + FSUSER_CloseArchive(archive); + } + + for(filenum = 0; filenum <= 9999999; filenum++) // find an unused file name + { + Result res1, res2, res3; + IFile fileR; + + sprintf(filename, "/luma/screenshots/top_%04u.bmp", filenum); + res1 = IFile_Open(&fileR, archiveId, fsMakePath(PATH_EMPTY, ""), fsMakePath(PATH_ASCII, filename), FS_OPEN_READ); + IFile_Close(&fileR); + + sprintf(filename, "/luma/screenshots/bot_%04u.bmp", filenum); + res2 = IFile_Open(&fileR, archiveId, fsMakePath(PATH_EMPTY, ""), fsMakePath(PATH_ASCII, filename), FS_OPEN_READ); + IFile_Close(&fileR); + + sprintf(filename, "/luma/screenshots/top_right_%04u.bmp", filenum); + res3 = IFile_Open(&fileR, archiveId, fsMakePath(PATH_EMPTY, ""), fsMakePath(PATH_ASCII, filename), FS_OPEN_READ); + IFile_Close(&fileR); + + if(R_FAILED(res1) && R_FAILED(res2) && R_FAILED(res3)) + break; + } + + sprintf(filename, "/luma/screenshots/top_%04u.bmp", filenum); + TRY(IFile_Open(&file, archiveId, fsMakePath(PATH_EMPTY, ""), fsMakePath(PATH_ASCII, filename), FS_OPEN_CREATE | FS_OPEN_WRITE)); + Draw_CreateBitmapHeader(buf, 400, 240); + TRY(IFile_Write(&file, &total, buf, 54, 0)); + + for(u32 y = 0; y < 240; y++) + { + u8 *line = Draw_ConvertFrameBufferLine(true, true, y); + TRY(IFile_Write(&file, &total, line, 3 * 400, 0)); + } + + TRY(IFile_Close(&file)); + + sprintf(filename, "/luma/screenshots/bot_%04u.bmp", filenum); + TRY(IFile_Open(&file, archiveId, fsMakePath(PATH_EMPTY, ""), fsMakePath(PATH_ASCII, filename), FS_OPEN_CREATE | FS_OPEN_WRITE)); + Draw_CreateBitmapHeader(buf, 320, 240); + TRY(IFile_Write(&file, &total, buf, 54, 0)); + + for(u32 y = 0; y < 240; y++) + { + u8 *line = Draw_ConvertFrameBufferLine(false, true, y); + TRY(IFile_Write(&file, &total, line, 3 * 320, 0)); + } + + if((GPU_FB_TOP_FMT & 0x20) && (Draw_GetCurrentFramebufferAddress(true, true) != Draw_GetCurrentFramebufferAddress(true, false))) + { + sprintf(filename, "/luma/screenshots/top_right_%04u.bmp", filenum); + TRY(IFile_Open(&file, archiveId, fsMakePath(PATH_EMPTY, ""), fsMakePath(PATH_ASCII, filename), FS_OPEN_CREATE | FS_OPEN_WRITE)); + Draw_CreateBitmapHeader(buf, 400, 240); + TRY(IFile_Write(&file, &total, buf, 54, 0)); + + for(u32 y = 0; y < 240; y++) + { + u8 *line = Draw_ConvertFrameBufferLine(true, false, y); + TRY(IFile_Write(&file, &total, line, 3 * 400, 0)); + } + } + +end: + IFile_Close(&file); + Draw_SetupFramebuffer(); + Draw_ClearFramebuffer(); + Draw_FlushFramebuffer(); + Draw_Unlock(); + + do + { + Draw_Lock(); + Draw_DrawString(10, 10, COLOR_TITLE, "Screenshot"); + if(R_FAILED(res)) + Draw_DrawFormattedString(10, 30, COLOR_WHITE, "Operation failed (0x%08x).", (u32)res); + else + Draw_DrawString(10, 30, COLOR_WHITE, "Operation succeeded."); + + Draw_FlushFramebuffer(); + Draw_Unlock(); + } + while(!(waitInput() & BUTTON_B) && !terminationRequest); + +#undef TRY +} diff --git a/sysmodules/rosalina/source/menus/debugger.c b/sysmodules/rosalina/source/menus/debugger.c new file mode 100644 index 000000000..3b8632cf0 --- /dev/null +++ b/sysmodules/rosalina/source/menus/debugger.c @@ -0,0 +1,165 @@ +/* +* 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 . +* +* 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. +*/ + +#include "menus/debugger.h" +#include "memory.h" +#include "draw.h" +#include "minisoc.h" +#include "fmt.h" +#include "gdb/server.h" +#include "gdb/debug.h" +#include "gdb/monitor.h" +#include "gdb/net.h" + +Menu debuggerMenu = { + "Debugger options menu", + .nbItems = 2, + { + { "Enable debugger", METHOD, .method = &DebuggerMenu_EnableDebugger }, + { "Disable debugger", METHOD, .method = &DebuggerMenu_DisableDebugger } + } +}; + +static MyThread debuggerSocketThread; +static MyThread debuggerDebugThread; +static u8 ALIGN(8) debuggerSocketThreadStack[0x4000]; +static u8 ALIGN(8) debuggerDebugThreadStack[0x2000]; + +GDBServer gdbServer = { 0 }; + +void debuggerSocketThreadMain(void); +MyThread *debuggerCreateSocketThread(void) +{ + MyThread_Create(&debuggerSocketThread, debuggerSocketThreadMain, debuggerSocketThreadStack, 0x4000, 0x20, CORE_SYSTEM); + return &debuggerSocketThread; +} + +void debuggerDebugThreadMain(void); +MyThread *debuggerCreateDebugThread(void) +{ + MyThread_Create(&debuggerDebugThread, debuggerDebugThreadMain, debuggerDebugThreadStack, 0x2000, 0x20, CORE_SYSTEM); + return &debuggerDebugThread; +} + +void DebuggerMenu_EnableDebugger(void) +{ + bool done = false, alreadyEnabled = gdbServer.super.running; + Result res = 0; + char buf[65]; + bool cantStart; + Handle dummy; + + res = OpenProcessByName("socket", &dummy); + cantStart = R_FAILED(res); + svcCloseHandle(dummy); + + Draw_Lock(); + Draw_ClearFramebuffer(); + Draw_FlushFramebuffer(); + Draw_Unlock(); + + do + { + Draw_Lock(); + Draw_DrawString(10, 10, COLOR_TITLE, "Debugger options menu"); + + if(alreadyEnabled) + Draw_DrawString(10, 30, COLOR_WHITE, "Already enabled!"); + else if(cantStart) + Draw_DrawString(10, 30, COLOR_WHITE, "Can't start the debugger before the system has fi-\nnished loading."); + else + { + Draw_DrawString(10, 30, COLOR_WHITE, "Starting debugger..."); + + if(!done) + { + res = GDB_InitializeServer(&gdbServer); + if(R_SUCCEEDED(res)) + { + debuggerCreateSocketThread(); + debuggerCreateDebugThread(); + res = svcWaitSynchronization(gdbServer.super.started_event, 10 * 1000 * 1000 * 1000LL); + } + + if(res != 0) + sprintf(buf, "Starting debugger... failed (0x%08x).", (u32)res); + + done = true; + } + if(res == 0) + Draw_DrawString(10, 30, COLOR_WHITE, "Starting debugger... OK."); + else + Draw_DrawString(10, 30, COLOR_WHITE, buf); + } + + Draw_FlushFramebuffer(); + Draw_Unlock(); + } + while(!(waitInput() & BUTTON_B) && !terminationRequest); +} + +void DebuggerMenu_DisableDebugger(void) +{ + bool initialized = gdbServer.referenceCount != 0; + Result res = 0; + char buf[65]; + + if(initialized) + { + svcSignalEvent(gdbServer.super.shall_terminate_event); + res = MyThread_Join(&debuggerDebugThread, 5 * 1000 * 1000 * 1000LL); + if(res == 0) + res = MyThread_Join(&debuggerSocketThread, 5 * 1000 * 1000 * 1000LL); + svcKernelSetState(0x10000, 2); + } + + if(res != 0) + sprintf(buf, "Failed to disable debugger (0x%08x).", (u32)res); + + do + { + Draw_Lock(); + Draw_DrawString(10, 10, COLOR_TITLE, "Debugger options menu"); + Draw_DrawString(10, 30, COLOR_WHITE, initialized ? (res == 0 ? "Debugger disabled successfully." : buf) : "Debugger not enabled."); + Draw_FlushFramebuffer(); + Draw_Unlock(); + } + while(!(waitInput() & BUTTON_B) && !terminationRequest); +} + +void debuggerSocketThreadMain(void) +{ + GDB_IncrementServerReferenceCount(&gdbServer); + GDB_RunServer(&gdbServer); + GDB_DecrementServerReferenceCount(&gdbServer); +} + +void debuggerDebugThreadMain(void) +{ + GDB_IncrementServerReferenceCount(&gdbServer); + GDB_RunMonitor(&gdbServer); + GDB_DecrementServerReferenceCount(&gdbServer); +} diff --git a/sysmodules/rosalina/source/menus/miscellaneous.c b/sysmodules/rosalina/source/menus/miscellaneous.c new file mode 100644 index 000000000..06f3c5e01 --- /dev/null +++ b/sysmodules/rosalina/source/menus/miscellaneous.c @@ -0,0 +1,261 @@ +/* +* 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 . +* +* 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. +*/ + +#include <3ds.h> +#include "menus/miscellaneous.h" +#include "input_redirection.h" +#include "memory.h" +#include "draw.h" +#include "hbloader.h" +#include "fmt.h" +#include "utils.h" // for makeARMBranch +#include "minisoc.h" + +Menu miscellaneousMenu = { + "Miscellaneous options menu", + .nbItems = 3, + { + { "Switch the hb. title to the current app.", METHOD, .method = &MiscellaneousMenu_SwitchBoot3dsxTargetTitle }, + { "Change the menu combo", METHOD, .method = MiscellaneousMenu_ChangeMenuCombo }, + { "Start InputRedirection", METHOD, .method = &MiscellaneousMenu_InputRedirection }, + } +}; + +void MiscellaneousMenu_SwitchBoot3dsxTargetTitle(void) +{ + Result res; + u64 titleId = 0; + char failureReason[64]; + + if(HBLDR_3DSX_TID == HBLDR_DEFAULT_3DSX_TID) + { + u32 pidList[0x40]; + s32 processAmount; + + res = svcGetProcessList(&processAmount, pidList, 0x40); + if(R_SUCCEEDED(res)) + { + for(s32 i = 0; i < processAmount && (u32)(titleId >> 32) != 0x00040010 && (u32)(titleId >> 32) != 0x00040000; i++) + { + Handle processHandle; + Result res = svcOpenProcess(&processHandle, pidList[i]); + if(R_FAILED(res)) + continue; + + svcGetProcessInfo((s64 *)&titleId, processHandle, 0x10001); + svcCloseHandle(processHandle); + } + } + + if(R_SUCCEEDED(res) && ((u32)(titleId >> 32) == 0x00040010 || (u32)(titleId >> 32) == 0x00040000)) + { + HBLDR_3DSX_TID = titleId; + miscellaneousMenu.items[0].title = "Switch the hb. title to hblauncher_loader"; + } + else if(R_FAILED(res)) + sprintf(failureReason, "%08x", (u32)res); + else + { + res = -1; + strcpy(failureReason, "no suitable process found"); + } + } + else + { + res = 0; + HBLDR_3DSX_TID = HBLDR_DEFAULT_3DSX_TID; + miscellaneousMenu.items[0].title = "Switch the hb. title to the current app."; + } + + Draw_Lock(); + Draw_ClearFramebuffer(); + Draw_FlushFramebuffer(); + Draw_Unlock(); + do + { + Draw_Lock(); + Draw_DrawString(10, 10, COLOR_TITLE, "Miscellaneous options menu"); + + if(R_SUCCEEDED(res)) + Draw_DrawString(10, 30, COLOR_WHITE, "Operation succeeded."); + else + Draw_DrawFormattedString(10, 30, COLOR_WHITE, "Operation failed (%s).", failureReason); + + Draw_FlushFramebuffer(); + Draw_Unlock(); + } + while(!(waitInput() & BUTTON_B) && !terminationRequest); +} + +static void MiscellaneousMenu_ConvertComboToString(char *out, u32 combo) +{ + static const char *keys[] = { "A", "B", "Select", "Start", "Right", "Left", "Up", "Down", "R", "L", "X", "Y" }; + for(s32 i = 11; i >= 0; i--) + { + if(combo & (1 << i)) + { + strcpy(out, keys[i]); + out += strlen(keys[i]); + *out++ = '+'; + } + } + + out[-1] = 0; +} +void MiscellaneousMenu_ChangeMenuCombo(void) +{ + char comboStrOrig[64], comboStr[64]; + u32 posY; + + Draw_Lock(); + Draw_ClearFramebuffer(); + Draw_FlushFramebuffer(); + Draw_Unlock(); + + MiscellaneousMenu_ConvertComboToString(comboStrOrig, menuCombo); + + Draw_Lock(); + Draw_DrawString(10, 10, COLOR_TITLE, "Miscellaneous options menu"); + + posY = Draw_DrawFormattedString(10, 30, COLOR_WHITE, "The current menu combo is: %s", comboStrOrig); + posY = Draw_DrawString(10, posY + SPACING_Y, COLOR_WHITE, "Please enter the new combo:"); + + Draw_FlushFramebuffer(); + Draw_Unlock(); + + menuCombo = waitInput(); + MiscellaneousMenu_ConvertComboToString(comboStr, menuCombo); + + do + { + Draw_Lock(); + Draw_DrawString(10, 10, COLOR_TITLE, "Miscellaneous options menu"); + + posY = Draw_DrawFormattedString(10, 30, COLOR_WHITE, "The current menu combo is: %s", comboStrOrig); + posY = Draw_DrawFormattedString(10, posY + SPACING_Y, COLOR_WHITE, "Please enter the new combo: %s", comboStr) + SPACING_Y; + + posY = Draw_DrawString(10, posY + SPACING_Y, COLOR_WHITE, "Successfully changed the menu combo."); + + Draw_FlushFramebuffer(); + Draw_Unlock(); + } + while(!(waitInput() & BUTTON_B) && !terminationRequest); +} + +void MiscellaneousMenu_InputRedirection(void) +{ + static MyThread *inputRedirectionThread = NULL; + bool done = false; + + Result res; + char buf[65]; + bool wasEnabled = inputRedirectionEnabled; + bool cantStart; + + if(wasEnabled) + { + res = InputRedirection_DoOrUndoPatches(); + inputRedirectionEnabled = false; + res = MyThread_Join(inputRedirectionThread, 5 * 1000 * 1000 * 1000LL); + svcCloseHandle(inputRedirectionThreadStartedEvent); + + if(res != 0) + sprintf(buf, "Failed to stop InputRedirection (0x%08x).", (u32)res); + else + miscellaneousMenu.items[2].title = "Start InputRedirection"; + } + else + { + Handle dummy; + s64 dummyInfo; + bool isN3DS = svcGetSystemInfo(&dummyInfo, 0x10001, 0) == 0; + + res = OpenProcessByName("socket", &dummy); + cantStart = R_FAILED(res); + svcCloseHandle(dummy); + + if(!cantStart && isN3DS) + { + res = OpenProcessByName("ir", &dummy); + cantStart = R_FAILED(res); + svcCloseHandle(dummy); + } + } + + do + { + Draw_Lock(); + Draw_DrawString(10, 10, COLOR_TITLE, "Miscellaneous options menu"); + + if(!wasEnabled && cantStart) + Draw_DrawString(10, 30, COLOR_WHITE, "Can't start the debugger before the system has fi-\nnished loading."); + else if(!wasEnabled) + { + Draw_DrawString(10, 30, COLOR_WHITE, "Starting InputRedirection..."); + if(!done) + { + res = InputRedirection_DoOrUndoPatches(); + if(R_SUCCEEDED(res)) + { + res = svcCreateEvent(&inputRedirectionThreadStartedEvent, RESET_STICKY); + if(R_SUCCEEDED(res)) + { + inputRedirectionThread = inputRedirectionCreateThread(); + res = svcWaitSynchronization(inputRedirectionThreadStartedEvent, 10 * 1000 * 1000 * 1000LL); + if(res == 0) + res = (Result)inputRedirectionStartResult; + + if(res != 0) + InputRedirection_DoOrUndoPatches(); + } + } + + if(res != 0) + sprintf(buf, "Starting InputRedirection... failed (0x%08x).", (u32)res); + else + miscellaneousMenu.items[2].title = "Stop InputRedirection"; + + done = true; + } + + if(res == 0) + Draw_DrawString(10, 30, COLOR_WHITE, "Starting InputRedirection... OK."); + else + Draw_DrawString(10, 30, COLOR_WHITE, buf); + } + else + { + if(res == 0) + Draw_DrawString(10, 30, COLOR_WHITE, "InputRedirection stopped successfully."); + else + Draw_DrawString(10, 30, COLOR_WHITE, buf); + } + + Draw_FlushFramebuffer(); + Draw_Unlock(); + } + while(!(waitInput() & BUTTON_B) && !terminationRequest); +} diff --git a/sysmodules/rosalina/source/menus/n3ds.c b/sysmodules/rosalina/source/menus/n3ds.c new file mode 100644 index 000000000..1a7822ce1 --- /dev/null +++ b/sysmodules/rosalina/source/menus/n3ds.c @@ -0,0 +1,74 @@ +/* +* 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 . +* +* 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. +*/ + +#include <3ds.h> +#include "fmt.h" +#include "menus/n3ds.h" +#include "memory.h" +#include "menu.h" + +static char clkRateBuf[128 + 1]; + +Menu N3DSMenu = { + "New 3DS menu", + .nbItems = 2, + { + { "Enable L2 cache", METHOD, .method = &N3DSMenu_EnableDisableL2Cache }, + { clkRateBuf, METHOD, .method = &N3DSMenu_ChangeClockRate } + } +}; + +static s64 clkRate = 0, higherClkRate = 0, L2CacheEnabled = 0; + +void N3DSMenu_UpdateStatus(void) +{ + svcGetSystemInfo(&clkRate, 0x10001, 0); + svcGetSystemInfo(&higherClkRate, 0x10001, 1); + svcGetSystemInfo(&L2CacheEnabled, 0x10001, 2); + + N3DSMenu.items[0].title = L2CacheEnabled ? "Disable L2 cache" : "Enable L2 cache"; + sprintf(clkRateBuf, "Set clock rate to %uMHz", clkRate != 268 ? 268 : (u32)higherClkRate); +} + +void N3DSMenu_ChangeClockRate(void) +{ + N3DSMenu_UpdateStatus(); + + s64 newBitMask = (L2CacheEnabled << 1) | ((clkRate != 268 ? 1 : 0) ^ 1); + svcKernelSetState(10, (u32)newBitMask); + + N3DSMenu_UpdateStatus(); +} + +void N3DSMenu_EnableDisableL2Cache(void) +{ + N3DSMenu_UpdateStatus(); + + s64 newBitMask = ((L2CacheEnabled ^ 1) << 1) | (clkRate != 268 ? 1 : 0); + svcKernelSetState(10, (u32)newBitMask); + + N3DSMenu_UpdateStatus(); +} diff --git a/sysmodules/rosalina/source/menus/process_list.c b/sysmodules/rosalina/source/menus/process_list.c new file mode 100644 index 000000000..2499bc544 --- /dev/null +++ b/sysmodules/rosalina/source/menus/process_list.c @@ -0,0 +1,229 @@ +/* +* 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 . +* +* 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. +*/ + +#include <3ds.h> +#include "menus/process_list.h" +#include "memory.h" +#include "draw.h" +#include "menu.h" +#include "utils.h" +#include "fmt.h" +#include "gdb/server.h" +#include "minisoc.h" +#include +#include + +typedef struct ProcessInfo +{ + u32 pid; + u64 titleId; + char name[8]; + bool isZombie; +} ProcessInfo; + +static ProcessInfo infos[0x40] = {0}, infosPrev[0x40] = {0}; +extern GDBServer gdbServer; + +static inline int ProcessListMenu_FormatInfoLine(char *out, const ProcessInfo *info) +{ + const char *checkbox; + u32 id; + for(id = 0; id < MAX_DEBUG && (!(gdbServer.ctxs[id].flags & GDB_FLAG_SELECTED) || gdbServer.ctxs[id].pid != info->pid); id++); + checkbox = !gdbServer.super.running ? "" : (id < MAX_DEBUG ? "(x) " : "( ) "); + + char commentBuf[23 + 1] = { 0 }; // exactly the size of "Remote: 255.255.255.255" + memset(commentBuf, ' ', 23); + + if(info->isZombie) + memcpy(commentBuf, "Zombie", 7); + + else if(gdbServer.super.running && id < MAX_DEBUG) + { + if(gdbServer.ctxs[id].state >= GDB_STATE_CONNECTED && gdbServer.ctxs[id].state < GDB_STATE_CLOSING) + { + u8 *addr = (u8 *)&gdbServer.ctxs[id].super.addr_in.sin_addr; + checkbox = "(A) "; + sprintf(commentBuf, "Remote: %hhu.%hhu.%hhu.%hhu", addr[0], addr[1], addr[2], addr[3]); + } + else + { + checkbox = "(W) "; + sprintf(commentBuf, "Port: %d", GDB_PORT_BASE + id); + } + } + + return sprintf(out, "%s%-4u %-8.8s %s", checkbox, info->pid, info->name, commentBuf); // Theoritically PIDs are 32-bit ints, but we'll only justify 4 digits +} + +static inline void ProcessListMenu_HandleSelected(const ProcessInfo *info) +{ + if(!gdbServer.super.running || info->isZombie) + return; + + u32 id; + for(id = 0; id < MAX_DEBUG && (!(gdbServer.ctxs[id].flags & GDB_FLAG_SELECTED) || gdbServer.ctxs[id].pid != info->pid); id++); + + GDBContext *ctx = &gdbServer.ctxs[id]; + + if(id < MAX_DEBUG) + { + if(ctx->flags & GDB_FLAG_USED) + { + RecursiveLock_Lock(&ctx->lock); + ctx->super.should_close = true; + RecursiveLock_Unlock(&ctx->lock); + + while(ctx->super.should_close) + svcSleepThread(12 * 1000 * 1000LL); + } + else + { + RecursiveLock_Lock(&ctx->lock); + ctx->flags &= ~GDB_FLAG_SELECTED; + RecursiveLock_Unlock(&ctx->lock); + } + } + else + { + for(id = 0; id < MAX_DEBUG && gdbServer.ctxs[id].flags & GDB_FLAG_SELECTED; id++); + if(id < MAX_DEBUG) + { + ctx = &gdbServer.ctxs[id]; + RecursiveLock_Lock(&ctx->lock); + ctx->pid = info->pid; + ctx->flags |= GDB_FLAG_SELECTED; + RecursiveLock_Unlock(&ctx->lock); + } + } +} + +s32 ProcessListMenu_FetchInfo(void) +{ + u32 pidList[0x40]; + s32 processAmount; + + svcGetProcessList(&processAmount, pidList, 0x40); + + for(s32 i = 0; i < processAmount; i++) + { + Handle processHandle; + Result res = svcOpenProcess(&processHandle, pidList[i]); + if(R_FAILED(res)) + continue; + + infos[i].pid = pidList[i]; + svcGetProcessInfo((s64 *)&infos[i].name, processHandle, 0x10000); + svcGetProcessInfo((s64 *)&infos[i].titleId, processHandle, 0x10001); + infos[i].isZombie = svcWaitSynchronization(processHandle, 0) == 0; + svcCloseHandle(processHandle); + } + + return processAmount; +} + +void RosalinaMenu_ProcessList(void) +{ + s32 processAmount = ProcessListMenu_FetchInfo(); + s32 selected = 0, page = 0, pagePrev = 0; + nfds_t nfdsPrev; + + do + { + nfdsPrev = gdbServer.super.nfds; + memcpy(infosPrev, infos, sizeof(infos)); + + Draw_Lock(); + if(page != pagePrev) + Draw_ClearFramebuffer(); + Draw_DrawString(10, 10, COLOR_TITLE, "Process list"); + + if(gdbServer.super.running) + { + char ipBuffer[17]; + u32 ip = gethostid(); + u8 *addr = (u8 *)&ip; + int n = sprintf(ipBuffer, "%hhu.%hhu.%hhu.%hhu", addr[0], addr[1], addr[2], addr[3]); + Draw_DrawString(SCREEN_BOT_WIDTH - 10 - SPACING_X * n, 10, COLOR_WHITE, ipBuffer); + } + + + for(s32 i = 0; i < PROCESSES_PER_MENU_PAGE && page * PROCESSES_PER_MENU_PAGE + i < processAmount; i++) + { + char buf[65] = {0}; + ProcessListMenu_FormatInfoLine(buf, &infos[page * PROCESSES_PER_MENU_PAGE + i]); + + Draw_DrawString(30, 30 + i * SPACING_Y, COLOR_WHITE, buf); + Draw_DrawCharacter(10, 30 + i * SPACING_Y, COLOR_TITLE, page * PROCESSES_PER_MENU_PAGE + i == selected ? '>' : ' '); + } + + Draw_FlushFramebuffer(); + Draw_Unlock(); + + if(terminationRequest) + break; + + u32 pressed; + do + { + pressed = waitInputWithTimeout(50); + if(pressed != 0 || nfdsPrev != gdbServer.super.nfds) + break; + processAmount = ProcessListMenu_FetchInfo(); + if(memcmp(infos, infosPrev, sizeof(infos)) != 0) + break; + } + while(pressed == 0 && !terminationRequest); + + if(pressed & BUTTON_B) + break; + else if(pressed & BUTTON_A) + ProcessListMenu_HandleSelected(&infos[selected]); + else if(pressed & BUTTON_DOWN) + selected++; + else if(pressed & BUTTON_UP) + selected--; + else if(pressed & BUTTON_LEFT) + selected -= PROCESSES_PER_MENU_PAGE; + else if(pressed & BUTTON_RIGHT) + { + if(selected + PROCESSES_PER_MENU_PAGE < processAmount) + selected += PROCESSES_PER_MENU_PAGE; + else if((processAmount - 1) / PROCESSES_PER_MENU_PAGE == page) + selected %= PROCESSES_PER_MENU_PAGE; + else + selected = processAmount - 1; + } + + if(selected < 0) + selected = processAmount - 1; + else if(selected >= processAmount) + selected = 0; + + pagePrev = page; + page = selected / PROCESSES_PER_MENU_PAGE; + } + while(!terminationRequest); +} diff --git a/sysmodules/rosalina/source/menus/process_patches.c b/sysmodules/rosalina/source/menus/process_patches.c new file mode 100644 index 000000000..86604e9b0 --- /dev/null +++ b/sysmodules/rosalina/source/menus/process_patches.c @@ -0,0 +1,183 @@ +/* +* 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 . +* +* 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. +*/ + +#include <3ds.h> +#include "csvc.h" +#include "menus/process_patches.h" +#include "memory.h" +#include "draw.h" +#include "hbloader.h" +#include "fmt.h" +#include "utils.h" + +Menu processPatchesMenu = { + "Process patches menu", + .nbItems = 2, + { + { "Patch SM for the service checks", METHOD, .method = &ProcessPatchesMenu_PatchUnpatchSM }, + { "Patch FS for the archive checks", METHOD, .method = &ProcessPatchesMenu_PatchUnpatchFS }, + } +}; + +static Result ProcessPatchesMenu_DoPatchUnpatchSM(u32 textTotalRoundedSize) +{ + static bool patched = false; + static u32 *off; + static u32 origData[7]; + + if(patched) + { + memcpy(off, &origData, sizeof(origData)); + patched = false; + } + else + { + for(off = (u32 *)0x00100000; off < (u32 *)(0x00100000 + textTotalRoundedSize) - 6 && + (off[0] != 0xE1A01006 || off[1] != 0xE1A00005 || off[3] != 0xE3500000 || off[6] != 0xE2850004); + off++); + + if(off >= (u32 *)(0x00100000 + textTotalRoundedSize) - 6) + return -1; + + memcpy(&origData, off, sizeof(origData)); + + off[2] = off[3] = off[4] = off[5] = 0xE320F000; // nop + patched = true; + } + + processPatchesMenu.items[0].title = patched ? "Unpatch SM for the service checks" : "Patch SM for the service checks"; + return 0; +} + +static Result ProcessPatchesMenu_DoPatchUnpatchFS(u32 textTotalRoundedSize) +{ + static bool patched = false; + static u16 *off; + static const u16 origData[2] = { + 0x4618, // mov r0, r3 + 0x3481, // adds r4, #0x81 + }; + + if(patched) + { + memcpy(off, &origData, sizeof(origData)); + patched = false; + } + else + { + off = (u16 *)memsearch((u8 *)0x00100000, &origData, textTotalRoundedSize, sizeof(origData)); + if(off == NULL) + return -1; + + off[0] = 0x2001; // mov r0, #1 + off[1] = 0x4770; // bx lr + + patched = true; + } + + processPatchesMenu.items[1].title = patched ? "Unpatch FS for the archive checks" : "Patch FS for the archive checks"; + return 0; +} + +Result OpenProcessByName(const char *name, Handle *h) +{ + u32 pidList[0x40]; + s32 processCount; + svcGetProcessList(&processCount, pidList, 0x40); + Handle dstProcessHandle = 0; + + for(s32 i = 0; i < processCount; i++) + { + Handle processHandle; + Result res = svcOpenProcess(&processHandle, pidList[i]); + if(R_FAILED(res)) + continue; + + char procName[8] = {0}; + svcGetProcessInfo((s64 *)procName, processHandle, 0x10000); + if(strncmp(procName, name, 8) == 0) + dstProcessHandle = processHandle; + else + svcCloseHandle(processHandle); + } + + if(dstProcessHandle == 0) + return -1; + + *h = dstProcessHandle; + return 0; +} + +static u32 ProcessPatchesMenu_PatchUnpatchProcessByName(const char *name, Result (*func)(u32 size)) +{ + Result res; + Handle processHandle; + OpenProcessByName(name, &processHandle); + + s64 textTotalRoundedSize = 0, startAddress = 0; + svcGetProcessInfo(&textTotalRoundedSize, processHandle, 0x10002); // only patch .text + svcGetProcessInfo(&startAddress, processHandle, 0x10005); + if(R_FAILED(res = svcMapProcessMemoryEx(processHandle, 0x00100000, (u32) startAddress, textTotalRoundedSize))) + return res; + + res = func(textTotalRoundedSize); + + svcUnmapProcessMemory(processHandle, 0x00100000, textTotalRoundedSize); + return res; +} + +static void ProcessPatchesMenu_PatchUnpatchProcess(const char *processName, Result (*func)(u32 size)) +{ + Draw_Lock(); + Draw_ClearFramebuffer(); + Draw_FlushFramebuffer(); + Draw_Unlock(); + + Result res = ProcessPatchesMenu_PatchUnpatchProcessByName(processName, func); + + do + { + Draw_Lock(); + Draw_DrawString(10, 10, COLOR_TITLE, "Process patches menu"); + if(R_SUCCEEDED(res)) + Draw_DrawString(10, 30, COLOR_WHITE, "Operation succeeded."); + else + Draw_DrawFormattedString(10, 30, COLOR_WHITE, "Operation failed (0x%08x).", res); + Draw_FlushFramebuffer(); + Draw_Unlock(); + } + while(!(waitInput() & BUTTON_B) && !terminationRequest); +} + +void ProcessPatchesMenu_PatchUnpatchSM(void) +{ + ProcessPatchesMenu_PatchUnpatchProcess("sm", &ProcessPatchesMenu_DoPatchUnpatchSM); +} + +void ProcessPatchesMenu_PatchUnpatchFS(void) +{ + ProcessPatchesMenu_PatchUnpatchProcess("fs", &ProcessPatchesMenu_DoPatchUnpatchFS); +} diff --git a/sysmodules/rosalina/source/minisoc.c b/sysmodules/rosalina/source/minisoc.c new file mode 100644 index 000000000..69be679a8 --- /dev/null +++ b/sysmodules/rosalina/source/minisoc.c @@ -0,0 +1,434 @@ +/* +* 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 . +* +* 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. +*/ + +#include "minisoc.h" +#include +#include <3ds/ipc.h> +#include <3ds/os.h> +#include <3ds/synchronization.h> +#include "memory.h" + +s32 _net_convert_error(s32 sock_retval); + +static Result SOCU_Initialize(Handle memhandle, u32 memsize) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x1,1,4); // 0x10044 + cmdbuf[1] = memsize; + cmdbuf[2] = IPC_Desc_CurProcessHandle(); + cmdbuf[4] = IPC_Desc_SharedHandles(1); + cmdbuf[5] = memhandle; + + ret = svcSendSyncRequest(SOCU_handle); + if(ret != 0) + return ret; + + return cmdbuf[1]; +} + +static Result SOCU_Shutdown(void) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x19,0,0); // 0x190000 + + ret = svcSendSyncRequest(SOCU_handle); + if(ret != 0) + return ret; + + return cmdbuf[1]; +} + +static s32 miniSocRefCount = 0; +static u32 socContextAddr = 0x08000000; +static u32 socContextSize = 0x60000; +// SOCU_handle from ctrulib +// socMemhandle from ctrulib + +Result miniSocInit() +{ + if(AtomicPostIncrement(&miniSocRefCount)) + return 0; + + u32 tmp = 0; + Result ret = 0; + + ret = svcControlMemory(&tmp, socContextAddr, 0, socContextSize, MEMOP_ALLOC, MEMPERM_READ | MEMPERM_WRITE); + if(ret != 0) goto cleanup; + + socContextAddr = tmp; + + ret = svcCreateMemoryBlock(&socMemhandle, (u32)socContextAddr, socContextSize, 0, 3); + if(ret != 0) goto cleanup; + + ret = srvGetServiceHandle(&SOCU_handle, "soc:U"); + if(ret != 0) goto cleanup; + + ret = SOCU_Initialize(socMemhandle, socContextSize); + if(ret != 0) goto cleanup; + + svcKernelSetState(0x10000, 2); + return 0; + +cleanup: + AtomicDecrement(&miniSocRefCount); + + if(socMemhandle != 0) + { + svcCloseHandle(socMemhandle); + socMemhandle = 0; + } + + if(SOCU_handle != 0) + { + SOCU_Shutdown(); + svcCloseHandle(SOCU_handle); + SOCU_handle = 0; + } + + if(tmp != 0) + svcControlMemory(&tmp, socContextAddr, socContextAddr, socContextSize, MEMOP_FREE, MEMPERM_DONTCARE); + + return ret; +} + +Result miniSocExit(void) +{ + if(AtomicDecrement(&miniSocRefCount)) + return 0; + + Result ret = 0; + u32 tmp; + + svcCloseHandle(socMemhandle); + socMemhandle = 0; + + ret = SOCU_Shutdown(); + + svcCloseHandle(SOCU_handle); + SOCU_handle = 0; + + svcControlMemory(&tmp, socContextAddr, socContextAddr, socContextSize, MEMOP_FREE, MEMPERM_DONTCARE); + if(ret == 0) + svcKernelSetState(0x10000, 2); + return ret; +} + +int socSocket(int domain, int type, int protocol) +{ + int ret = 0; + + u32 *cmdbuf = getThreadCommandBuffer(); + + // The protocol on the 3DS *must* be 0 to work + // To that end, when appropriate, we will make the change for the user + if (domain == AF_INET + && type == SOCK_STREAM + && protocol == IPPROTO_TCP) { + protocol = 0; // TCP is the only option, so 0 will work as expected + } + if (domain == AF_INET + && type == SOCK_DGRAM + && protocol == IPPROTO_UDP) { + protocol = 0; // UDP is the only option, so 0 will work as expected + } + + cmdbuf[0] = IPC_MakeHeader(0x2,3,2); // 0x200C2 + cmdbuf[1] = domain; + cmdbuf[2] = type; + cmdbuf[3] = protocol; + cmdbuf[4] = IPC_Desc_CurProcessHandle(); + + ret = svcSendSyncRequest(SOCU_handle); + if(ret != 0) + { + //errno = SYNC_ERROR; + return ret; + } + + ret = (int)cmdbuf[1]; + if(ret == 0) ret = cmdbuf[2]; + if(ret < 0) + { + //if(cmdbuf[1] == 0)errno = _net_convert_error(ret); + //if(cmdbuf[1] != 0)errno = SYNC_ERROR; + return -1; + } + else + return cmdbuf[2]; +} + +int socBind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) +{ + Result ret = 0; + socklen_t tmp_addrlen = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + u8 tmpaddr[0x1c]; + + memset(tmpaddr, 0, 0x1c); + + if(addr->sa_family == AF_INET) + tmp_addrlen = 8; + else + tmp_addrlen = 0x1c; + + if(addrlen < tmp_addrlen) + { + //errno = EINVAL; + return -1; + } + + tmpaddr[0] = tmp_addrlen; + tmpaddr[1] = addr->sa_family; + memcpy(&tmpaddr[2], &addr->sa_data, tmp_addrlen-2); + + cmdbuf[0] = IPC_MakeHeader(0x5,2,4); // 0x50084 + cmdbuf[1] = (u32)sockfd; + cmdbuf[2] = (u32)tmp_addrlen; + cmdbuf[3] = IPC_Desc_CurProcessHandle(); + cmdbuf[5] = IPC_Desc_StaticBuffer(tmp_addrlen,0); + cmdbuf[6] = (u32)tmpaddr; + + ret = svcSendSyncRequest(SOCU_handle); + if(ret != 0) { + //errno = SYNC_ERROR; + return ret; + } + + ret = (int)cmdbuf[1]; + if(ret == 0) + ret = _net_convert_error(cmdbuf[2]); + + if(ret < 0) { + //errno = -ret; + return -1; + } + + return ret; +} + +int socListen(int sockfd, int max_connections) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x3,2,2); // 0x30082 + cmdbuf[1] = (u32)sockfd; + cmdbuf[2] = (u32)max_connections; + cmdbuf[3] = IPC_Desc_CurProcessHandle(); + + ret = svcSendSyncRequest(SOCU_handle); + if(ret != 0) + { + //errno = SYNC_ERROR; + return ret; + } + + ret = (int)cmdbuf[1]; + if(ret == 0) + ret = _net_convert_error(cmdbuf[2]); + + if(ret < 0) { + //errno = -ret; + return -1; + } + + return 0; +} + +int socAccept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) +{ + Result ret = 0; + int tmp_addrlen = 0x1c; + + u32 *cmdbuf = getThreadCommandBuffer(); + u8 tmpaddr[0x1c]; + u32 saved_threadstorage[2]; + + memset(tmpaddr, 0, 0x1c); + + cmdbuf[0] = IPC_MakeHeader(0x4,2,2); // 0x40082 + cmdbuf[1] = (u32)sockfd; + cmdbuf[2] = (u32)tmp_addrlen; + cmdbuf[3] = IPC_Desc_CurProcessHandle(); + + u32 *staticbufs = getThreadStaticBuffers(); + saved_threadstorage[0] = staticbufs[0]; + saved_threadstorage[1] = staticbufs[1]; + + staticbufs[0] = IPC_Desc_StaticBuffer(tmp_addrlen,0); + staticbufs[1] = (u32)tmpaddr; + + ret = svcSendSyncRequest(SOCU_handle); + + staticbufs[0] = saved_threadstorage[0]; + staticbufs[1] = saved_threadstorage[1]; + + if(ret != 0) + return ret; + + ret = (int)cmdbuf[1]; + if(ret == 0) + ret = _net_convert_error(cmdbuf[2]); + + if(ret < 0) + //errno = -ret; + + if(ret >= 0 && addr != NULL) + { + addr->sa_family = tmpaddr[1]; + if(*addrlen > tmpaddr[0]) + *addrlen = tmpaddr[0]; + memcpy(addr->sa_data, &tmpaddr[2], *addrlen - 2); + } + + if(ret < 0) + return -1; + + return ret; +} + +int socPoll(struct pollfd *fds, nfds_t nfds, int timeout) +{ + int ret = 0; + nfds_t i; + u32 size = sizeof(struct pollfd)*nfds; + u32 *cmdbuf = getThreadCommandBuffer(); + u32 saved_threadstorage[2]; + + if(nfds == 0) { + return -1; + } + + for(i = 0; i < nfds; ++i) { + fds[i].revents = 0; + } + + cmdbuf[0] = IPC_MakeHeader(0x14,2,4); // 0x140084 + cmdbuf[1] = (u32)nfds; + cmdbuf[2] = (u32)timeout; + cmdbuf[3] = IPC_Desc_CurProcessHandle(); + cmdbuf[5] = IPC_Desc_StaticBuffer(size,10); + cmdbuf[6] = (u32)fds; + + u32 * staticbufs = getThreadStaticBuffers(); + saved_threadstorage[0] = staticbufs[0]; + saved_threadstorage[1] = staticbufs[1]; + + staticbufs[0] = IPC_Desc_StaticBuffer(size,0); + staticbufs[1] = (u32)fds; + + ret = svcSendSyncRequest(SOCU_handle); + + staticbufs[0] = saved_threadstorage[0]; + staticbufs[1] = saved_threadstorage[1]; + + if(ret != 0) { + return ret; + } + + ret = (int)cmdbuf[1]; + if(ret == 0) + ret = _net_convert_error(cmdbuf[2]); + + if(ret < 0) { + //errno = -ret; + return -1; + } + + return ret; +} + +int socClose(int sockfd) +{ + int ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0xB,1,2); // 0xB0042 + cmdbuf[1] = (u32)sockfd; + cmdbuf[2] = IPC_Desc_CurProcessHandle(); + + ret = svcSendSyncRequest(SOCU_handle); + if(ret != 0) { + //errno = SYNC_ERROR; + return ret; + } + + ret = (int)cmdbuf[1]; + if(ret == 0) + ret =_net_convert_error(cmdbuf[2]); + + if(ret < 0) { + //errno = -ret; + return -1; + } + + return 0; +} + +int socSetsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen) +{ + int ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x12,4,4); // 0x120104 + cmdbuf[1] = (u32)sockfd; + cmdbuf[2] = (u32)level; + cmdbuf[3] = (u32)optname; + cmdbuf[4] = (u32)optlen; + cmdbuf[5] = IPC_Desc_CurProcessHandle(); + cmdbuf[7] = IPC_Desc_StaticBuffer(optlen,9); + cmdbuf[8] = (u32)optval; + + ret = svcSendSyncRequest(SOCU_handle); + if(ret != 0) { + return ret; + } + + ret = (int)cmdbuf[1]; + if(ret == 0) + ret = _net_convert_error(cmdbuf[2]); + + if(ret < 0) { + //errno = -ret; + return -1; + } + + return ret; +} + +ssize_t soc_recv(int sockfd, void *buf, size_t len, int flags) +{ + return soc_recvfrom(sockfd, buf, len, flags, NULL, 0); +} + +ssize_t soc_send(int sockfd, const void *buf, size_t len, int flags) +{ + return soc_sendto(sockfd, buf, len, flags, NULL, 0); +} diff --git a/sysmodules/rosalina/source/services.c b/sysmodules/rosalina/source/services.c new file mode 100644 index 000000000..c9ac26ccd --- /dev/null +++ b/sysmodules/rosalina/source/services.c @@ -0,0 +1,108 @@ +/* +* 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 . +* +* 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. +*/ + +#include <3ds.h> +#include +#include "fsreg.h" +#include "services.h" + +static Handle *srvHandlePtr; +static int srvRefCount; +static RecursiveLock initLock; +static int initLockinit = 0; + +Result srvSysInit(void) +{ + Result rc = 0; + + if (!initLockinit) + RecursiveLock_Init(&initLock); + + RecursiveLock_Lock(&initLock); + + if (srvRefCount > 0) + { + RecursiveLock_Unlock(&initLock); + return MAKERESULT(RL_INFO, RS_NOP, 25, RD_ALREADY_INITIALIZED); + } + + srvHandlePtr = srvGetSessionHandle(); + + while(1) + { + rc = svcConnectToPort(srvHandlePtr, "srv:"); + if (R_LEVEL(rc) != RL_PERMANENT || + R_SUMMARY(rc) != RS_NOTFOUND || + R_DESCRIPTION(rc) != RD_NOT_FOUND + ) break; + svcSleepThread(500 * 1000LL); + } + + if(R_SUCCEEDED(rc)) + { + rc = srvRegisterClient(); + srvRefCount++; + } + + RecursiveLock_Unlock(&initLock); + return rc; +} + +Result srvSysExit(void) +{ + Result rc = 0; + RecursiveLock_Lock(&initLock); + + if(srvRefCount > 1) + { + srvRefCount--; + RecursiveLock_Unlock(&initLock); + return MAKERESULT(RL_INFO, RS_NOP, 25, RD_BUSY); + } + + if(srvHandlePtr != 0) + svcCloseHandle(*srvHandlePtr); + else + svcBreak(USERBREAK_ASSERT); + + srvHandlePtr = 0; + srvRefCount--; + + RecursiveLock_Unlock(&initLock); + return rc; +} + +void fsSysInit(void) +{ + if(R_FAILED(fsregSetupPermissions())) + svcBreak(USERBREAK_ASSERT); + + Handle *fsHandlePtr = fsGetSessionHandle(); + srvGetServiceHandle(fsHandlePtr, "fs:USER"); + + FSUSER_InitializeWithSdkVersion(*fsHandlePtr, SDK_VERSION); + FSUSER_SetPriority(0); +} diff --git a/sysmodules/rosalina/source/sock_util.c b/sysmodules/rosalina/source/sock_util.c new file mode 100644 index 000000000..ad88b0e4e --- /dev/null +++ b/sysmodules/rosalina/source/sock_util.c @@ -0,0 +1,297 @@ +/* +* 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 . +* +* 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. +*/ + +#include +#include <3ds/result.h> +#include <3ds/svc.h> +#include <3ds/synchronization.h> +#include +#include "memory.h" +#include "minisoc.h" +#include "sock_util.h" + +extern Handle terminationRequestEvent; +extern bool terminationRequest; + +// soc's poll function is odd, and doesn't like -1 as fd. +// so this compacts everything together + +static void compact(struct sock_server *serv) +{ + int new_fds[MAX_CTXS]; + struct sock_ctx *new_ctxs[MAX_CTXS]; + nfds_t n = 0; + + for(nfds_t i = 0; i < serv->nfds; i++) + { + if(serv->poll_fds[i].fd != -1) + { + new_fds[n] = serv->poll_fds[i].fd; + new_ctxs[n] = serv->ctx_ptrs[i]; + n++; + } + } + + for(nfds_t i = 0; i < n; i++) + { + serv->poll_fds[i].fd = new_fds[i]; + serv->ctx_ptrs[i] = new_ctxs[i]; + serv->ctx_ptrs[i]->i = i; + } + serv->nfds = n; + serv->compact_needed = false; +} + +static struct sock_ctx *server_alloc_server_ctx(struct sock_server *serv) +{ + for(int i = 0; i < MAX_PORTS; i++) + { + if(serv->serv_ctxs[i].type == SOCK_NONE) + return &serv->serv_ctxs[i]; + } + + return NULL; +} + +static void server_close_ctx(struct sock_server *serv, struct sock_ctx *ctx) +{ + serv->compact_needed = true; + + Handle sock = serv->poll_fds[ctx->i].fd; + if(ctx->type == SOCK_CLIENT) + { + serv->close_cb(ctx); + serv->free(serv, ctx); + ctx->serv->n--; + } + + socClose(sock); + ctx->should_close = false; + + serv->poll_fds[ctx->i].fd = -1; + serv->poll_fds[ctx->i].events = 0; + serv->poll_fds[ctx->i].revents = 0; + + ctx->type = SOCK_NONE; +} + +Result server_init(struct sock_server *serv) +{ + Result ret = 0; + + ret = miniSocInit(); + if(R_FAILED(ret)) + return ret; + memset(serv, 0, sizeof(struct sock_server)); + + for(int i = 0; i < MAX_PORTS; i++) + serv->serv_ctxs[i].type = SOCK_NONE; + + for(int i = 0; i < MAX_CTXS; i++) + serv->ctx_ptrs[i] = NULL; + + ret = svcCreateEvent(&serv->started_event, RESET_STICKY); + if(R_FAILED(ret)) + return ret; + return svcCreateEvent(&serv->shall_terminate_event, RESET_STICKY); +} + +void server_bind(struct sock_server *serv, u16 port) +{ + int server_sockfd; + Handle handles[2] = { terminationRequestEvent, serv->shall_terminate_event }; + s32 idx = -1; + server_sockfd = socSocket(AF_INET, SOCK_STREAM, 0); + int res; + + while(server_sockfd == -1) + { + if(svcWaitSynchronizationN(&idx, handles, 2, false, 100 * 1000 * 1000LL) == 0) + return; + + server_sockfd = socSocket(AF_INET, SOCK_STREAM, 0); + } + + if(server_sockfd != -1) + { + struct sockaddr_in saddr; + saddr.sin_family = AF_INET; + saddr.sin_port = htons(port); + saddr.sin_addr.s_addr = gethostid(); + + res = socBind(server_sockfd, (struct sockaddr*)&saddr, sizeof(struct sockaddr_in)); + + if(res == 0) + { + res = socListen(server_sockfd, 2); + if(res == 0) + { + int idx = serv->nfds; + serv->nfds++; + serv->poll_fds[idx].fd = server_sockfd; + serv->poll_fds[idx].events = POLLIN; + + struct sock_ctx *new_ctx = server_alloc_server_ctx(serv); + memcpy(&new_ctx->addr_in, &saddr, sizeof(struct sockaddr_in)); + new_ctx->type = SOCK_SERVER; + new_ctx->sockfd = server_sockfd; + new_ctx->n = 0; + new_ctx->i = idx; + serv->ctx_ptrs[idx] = new_ctx; + } + } + } +} + +void server_run(struct sock_server *serv) +{ + struct pollfd *fds = serv->poll_fds; + Handle handles[2] = { terminationRequestEvent, serv->shall_terminate_event }; + + serv->running = true; + svcSignalEvent(serv->started_event); + + while(serv->running && !terminationRequest) + { + s32 idx = -1; + if(svcWaitSynchronizationN(&idx, handles, 2, false, 0LL) == 0) + goto abort_connections; + + if(serv->nfds == 0) + { + if(svcWaitSynchronizationN(&idx, handles, 2, false, 12 * 1000 * 1000LL) == 0) + goto abort_connections; + else + continue; + } + + for(nfds_t i = 0; i < serv->nfds; i++) + fds[i].revents = 0; + int pollres = socPoll(fds, serv->nfds, 50); + + for(nfds_t i = 0; pollres > 0 && i < serv->nfds; i++) + { + struct sock_ctx *curr_ctx = serv->ctx_ptrs[i]; + + if((fds[i].revents & POLLHUP) || curr_ctx->should_close) + server_close_ctx(serv, curr_ctx); + + else if(fds[i].revents & POLLIN) + { + if(curr_ctx->type == SOCK_SERVER) // Listening socket? + { + struct sockaddr_in saddr; + socklen_t len = sizeof(struct sockaddr_in); + int client_sockfd = socAccept(fds[i].fd, (struct sockaddr *)&saddr, &len); + + if(svcWaitSynchronizationN(&idx, handles, 2, false, 0LL) == 0) + goto abort_connections; + + if(client_sockfd < 0 || curr_ctx->n == serv->clients_per_server || serv->nfds == MAX_CTXS) + socClose(client_sockfd); + + else + { + struct sock_ctx *new_ctx = serv->alloc(serv, ntohs(curr_ctx->addr_in.sin_port)); + if(new_ctx == NULL) + socClose(client_sockfd); + else + { + fds[serv->nfds].fd = client_sockfd; + fds[serv->nfds].events = POLLIN; + + int new_idx = serv->nfds; + serv->nfds++; + curr_ctx->n++; + + new_ctx->type = SOCK_CLIENT; + new_ctx->sockfd = client_sockfd; + new_ctx->serv = curr_ctx; + new_ctx->i = new_idx; + new_ctx->n = 0; + + serv->ctx_ptrs[new_idx] = new_ctx; + + if(serv->accept_cb(new_ctx) == -1) + server_close_ctx(serv, new_ctx); + + memcpy(&new_ctx->addr_in, &saddr, sizeof(struct sockaddr_in)); + } + } + } + else + { + if(serv->data_cb(curr_ctx) == -1) + server_close_ctx(serv, curr_ctx); + } + } + } + + if(serv->compact_needed) + compact(serv); + } + + // Clean up. + for(unsigned int i = 0; i < serv->nfds; i++) + { + if(fds[i].fd != -1) + socClose(fds[i].fd); + } + + serv->running = false; + svcClearEvent(serv->started_event); + return; + +abort_connections: + for(unsigned int i = 0; i < serv->nfds; i++) + { + struct linger linger; + linger.l_onoff = 1; + linger.l_linger = 0; + + socSetsockopt(fds[i].fd, SOL_SOCKET, SO_LINGER, &linger, sizeof(struct linger)); + socClose(fds[i].fd); + } + + serv->running = false; + svcClearEvent(serv->started_event); +} + +void server_finalize(struct sock_server *serv) +{ + for(nfds_t i = 0; i < MAX_CTXS; i++) + { + if(serv->ctx_ptrs[i] != NULL) + server_close_ctx(serv, serv->ctx_ptrs[i]); + } + + miniSocExit(); + + svcClearEvent(serv->shall_terminate_event); + svcCloseHandle(serv->shall_terminate_event); + svcClearEvent(serv->started_event); + svcCloseHandle(serv->started_event); +}