Compare commits

..

25 Commits

Author SHA1 Message Date
TuxSH
bb07a7334f update gitignore and makefile 2020-07-16 18:06:14 +01:00
TuxSH
748b771618 rosalina: ndm + shutdown issue workaround 2020-07-16 17:55:31 +01:00
TuxSH
d6e72080d9 rosalina: ndm doesn't exist on SAFE_FIRM 2020-07-16 16:56:59 +01:00
TuxSH
70109fed2c Update bug-report.md, etc 2020-07-16 16:25:56 +01:00
TuxSH
cf36d21daf rosalina: forgot float suffix in luminance.c 2020-07-16 01:24:22 +01:00
TuxSH
781cd85b00 rosalina: display min/max luminance 2020-07-16 00:50:05 +01:00
TuxSH
514537a983 hbloader: allow homebrew to write to the shared config page 2020-07-15 23:04:35 +01:00
TuxSH
184f4587fb rosalina: minor menu changes 2020-07-15 22:24:08 +01:00
TuxSH
e096aaabc4 rosalina/sm: properly interact with ndm 2020-07-15 18:57:53 +01:00
TuxSH
ba26ae0f1c k11ext: refactor ndm:u workaround 2020-07-15 17:33:47 +01:00
TuxSH
786adf0268 k11ext: fix oops 2020-07-15 00:56:25 +01:00
TuxSH
2af05220c2 rosalina: properly rewrite luminance-setting menu, etc. 2020-07-14 22:10:13 +01:00
TuxSH
362c4ffff1 sysmodules: use libctru configmem defs 2020-07-12 21:26:02 +01:00
Death Mask Salesman
95fd4e763b Fix release building (#1454)
`boot.3dsx` is downloaded from a static URL via `curl`.

Fixes #1453
2020-07-12 19:39:03 +01:00
TuxSH
768e587b76 sysmodules: introduce "luma shared config", rewrite ndmu workaround 2020-07-12 19:36:18 +01:00
TuxSH
e3bb1c1b63 rosalina: autoclose menu on sleep mode/shell closed to prevent lockup 2020-07-11 22:04:13 +01:00
TuxSH
4c01bb453c rosalina: prevent disconnect when shell is closed
Fuck ndm, fuck StreetPass
2020-07-11 21:39:36 +01:00
TuxSH
dc67d438dc rosalina: properly restore screen filters when lid is reopened 2020-07-10 22:58:07 +01:00
TuxSH
2d58ec4c86 rosalina: prevent sleep mode entry if debugger/input redir is enabled to prevent lockup 2020-07-09 22:20:29 +01:00
TuxSH
555286ea47 Separate exception dump parser in another repo, add boot.3dsx to release command
https://github.com/LumaTeam/luma3ds_exception_dump_parser
2020-07-09 19:52:55 +01:00
TuxSH
b17eb66d55 rosalina inputredir: Use ir patch from @Nanquitas ; also refactor the code
Fixes #1428, #1438 (I think)
2020-07-08 22:08:57 +01:00
TuxSH
9ca52054cf rosalina: bump FS priority 2020-07-07 23:27:26 +01:00
TuxSH
991f51831d kext: add hid/ir thread locking 2020-07-07 23:27:15 +01:00
TuxSH
e69f89a0d4 Change screen filters presets (adding more) menu & print CCT. Fixes #1442.
Most new presets come from 8bitwonder
2020-07-05 20:54:27 +01:00
TuxSH
9411a8c186 rosalina: implement 800px top-screen screenshot, etc. Fixes #1443 2020-07-05 18:44:41 +01:00
85 changed files with 1083 additions and 3411 deletions

View File

@@ -7,13 +7,13 @@ about: Use this to report bugs you encounter with Luma3DS. Make sure you upload
-- THIS IS NOT A SUPPORT FORUM! For support go here: -- THIS IS NOT A SUPPORT FORUM! For support go here:
-- Nintendo Homebrew: https://discord.gg/MjzatM8 -- Nintendo Homebrew: https://discord.gg/MjzatM8
-- --
-- Rosalina feature requests go here: https://github.com/AuroraWright/Luma3DS/issues/752 -- Rosalina feature requests go here: https://github.com/LumaTeam/Luma3DS/issues/752
-- --
-- Also check the Wiki (https://github.com/AuroraWright/Luma3DS/wiki) before making an issue. -- Also check the Wiki (https://github.com/LumaTeam/Luma3DS/wiki) before making an issue.
-- --
-- For GBA/DSiWare/DS/AGB_FIRM/TWL_FIRM problems: use https://github.com/MechanicalDragon0687/TWLFix-CFW and update your system. -- For GBA/DSiWare/DS/AGB_FIRM/TWL_FIRM problems: use https://github.com/MechanicalDragon0687/TWLFix-CFW and update your system.
-- If you're using an emu/redNAND try installing anything on it to sysNAND. -- If you're using an emu/redNAND try installing anything on it to sysNAND.
-- Please make sure to read "Enable game patching" https://github.com/AuroraWright/Luma3DS/wiki/Options-and-usage before posting any issues about the "Enable game patching" option(s). -- Please make sure to read "Enable game patching" https://github.com/LumaTeam/Luma3DS/wiki/Options-and-usage before posting any issues about the "Enable game patching" option(s).
-- --
-- Luma updaters that don't support Boot9Strap/Sighax won't work. -- Luma updaters that don't support Boot9Strap/Sighax won't work.
-- This is due to support for non-B9S/Sighax entrypoints being dropped. -- This is due to support for non-B9S/Sighax entrypoints being dropped.
@@ -21,7 +21,7 @@ about: Use this to report bugs you encounter with Luma3DS. Make sure you upload
-- Please fill in the placeholders.--> -- Please fill in the placeholders.-->
**System model:** **System model:**
[e.g. 2DS, New 3DS, Old 3DS] [New 2DS XL, New 3DS XL, New 3DS, Old 2DS, Old 3DS XL, Old 3DS]
**SysNAND version (+emu/redNAND version if applicable):** **SysNAND version (+emu/redNAND version if applicable):**
@@ -34,7 +34,7 @@ about: Use this to report bugs you encounter with Luma3DS. Make sure you upload
**Luma3DS version:** **Luma3DS version:**
[e.g. v10.1.3 stable or if using non-releases specify the commit like this https://github.com/AuroraWright/Luma3DS/commit/0543c208fd154e6326ea5da8cbf66ffcbdef010c] [e.g. v10.2 stable or if using non-releases specify the commit like this https://github.com/LumaTeam/Luma3DS/commit/0543c208fd154e6326ea5da8cbf66ffcbdef010c]
**Luma3DS configuration/options:** **Luma3DS configuration/options:**
@@ -50,7 +50,7 @@ Splash duration: ( )
PIN lock: ( ) PIN lock: ( )
New 3DS CPU: ( ) New 3DS CPU: ( )
<!--This option is only available for New 3DS/2DS.--> <!--This option is only available on New 3DS (XL)/New 2DS XL.-->
-- --
@@ -70,12 +70,13 @@ Show NAND or user string in System Settings: ( )
Show GBA boot screen in patched AGB_FIRM: ( ) Show GBA boot screen in patched AGB_FIRM: ( )
Patch Arm9 access: ( )
Set developer UNITINFO: ( ) Set developer UNITINFO: ( )
Disable Arm11 exception handlers: ( ) Disable Arm11 exception handlers: ( )
Enable Rosalina on SAFE_FIRM: ( )
<!--This option is only available on New 3DS (XL)/New 2DS XL.-->
-- --

3
.gitignore vendored
View File

@@ -13,8 +13,11 @@ exceptions/arm11/build
*.d *.d
*.elf *.elf
*.cxi *.cxi
*.3dsx
.DS_Store .DS_Store
*.dmp *.dmp
.project .project
.cproject .cproject
.settings .settings
Luma3DS*.zip

View File

@@ -15,9 +15,10 @@ release: $(NAME)$(REVISION).zip
clean: clean:
@$(foreach dir, $(SUBFOLDERS), $(MAKE) -C $(dir) clean &&) true @$(foreach dir, $(SUBFOLDERS), $(MAKE) -C $(dir) clean &&) true
@rm -rf *.firm *.zip @rm -rf *.firm *.zip *.3dsx
$(NAME)$(REVISION).zip: boot.firm exception_dump_parser # boot.3dsx comes from https://github.com/fincs/new-hbmenu/releases
$(NAME)$(REVISION).zip: boot.firm boot.3dsx
@zip -r $@ $^ -x "*.DS_Store*" "*__MACOSX*" @zip -r $@ $^ -x "*.DS_Store*" "*__MACOSX*"
boot.firm: $(SUBFOLDERS) boot.firm: $(SUBFOLDERS)
@@ -25,5 +26,9 @@ boot.firm: $(SUBFOLDERS)
-A 0x18180000 -C XDMA XDMA NDMA XDMA -A 0x18180000 -C XDMA XDMA NDMA XDMA
@echo built... $(notdir $@) @echo built... $(notdir $@)
boot.3dsx:
@curl -sSL "https://github.com/fincs/new-hbmenu/releases/latest/download/boot.3dsx" -o "$@"
@echo downloaded... $(notdir $@)
$(SUBFOLDERS): $(SUBFOLDERS):
@$(MAKE) -C $@ all @$(MAKE) -C $@ all

View File

@@ -1,41 +1,7 @@
# Luma3DS-3GX Plugin Edition # Luma3DS
*Noob-proof (N)3DS "Custom Firmware", with 3GX plugins support* *Noob-proof (N)3DS "Custom Firmware"*
### 3GX Plugin Edition ### What it is
This edition of **Luma3DS** allows the loading of **.3GX plugins** in Luma3DS, which are otherwise officially unsupported.
### How to install this Edition
1. download the latest `boot.firm` from [the releases page](https://github.com/mind-overflow/Luma3DS-3GX/releases/latest)
2. put the downloaded `boot.firm` file in the `root` directory of your SD card (`sd:/boot.firm`), overwriting the official Luma3DS `boot.firm`.
3. (re)boot your 3DS, and when prompted, enable:
- "Enable game patching"
- "Show NAND or user string in System Settings"
4. press `START` and let your 3DS boot.
You successfully installed the 3GX Plugin Loader! Now, proceed to the next step to learn how to install and enable 3GX plugins.
### How to install 3GX plugins
Plugins have to be installed in the `sd:/luma/plugins` folder.
Usually, you need to put your specific plugin in the `<TITLEID>` subdirectory, eg: `sd:/luma/plugins/<TITLEID>/<filename>.3gx`.
However, a `default.3gx` plugin can also be placed in the main `sd:/luma/plugins` directory: `sd:/luma/plugins/default.3gx`.
So:
``` yaml
sd:/luma/plugins/default.3gx # will be loaded for all games, low priority
sd:/luma/plugins/<TITLEID>/<filename>.3gx # will only be loaded for the specified title, high priority
```
Now you know how to install 3GX plugins! Proceed to the next step to learn how how to enable 3GX plugins.
### How to enable 3GX plugins
1. when booted, press `L + D-Pad Down + Select` to open the Rosalina menu.
2. Press `D-Pad Down` again until `Plugin Loader`, is selected, then press `A` and set it to `[Enabled]`.
Done! You learned to install the 3GX Plugin loader, install 3GX Plugins and enable them. Now, simply launch the game you want to play and press `SELECT` to open up the 3GX menu!
### Luma3DS introduction
**Luma3DS** is a program to patch the system software of (New) Nintendo (2)3DS handheld consoles "on the fly", adding features such as per-game language settings, debugging capabilities for developers, and removing restrictions enforced by Nintendo such as the region lock. **Luma3DS** is a program to patch the system software of (New) Nintendo (2)3DS handheld consoles "on the fly", adding features such as per-game language settings, debugging capabilities for developers, and removing restrictions enforced by Nintendo such as the region lock.
It also allows you to run unauthorized ("homebrew") content by removing signature checks. It also allows you to run unauthorized ("homebrew") content by removing signature checks.
@@ -50,7 +16,7 @@ Since v8.0, Luma3DS has its own in-game menu, triggerable by <kbd>L+Down+Select<
2. [makerom](https://github.com/jakcron/Project_CTR) in PATH 2. [makerom](https://github.com/jakcron/Project_CTR) in PATH
3. [firmtool](https://github.com/TuxSH/firmtool) 3. [firmtool](https://github.com/TuxSH/firmtool)
4. Up-to-date devkitARM+libctru 4. Up-to-date devkitARM+libctru
1. Clone the repository with `git clone https://github.com/mind-overflow/Luma3DS-3GX.git` 1. Clone the repository with `git clone https://github.com/LumaTeam/Luma3DS.git`
2. Run `make`. 2. Run `make`.
The produced `boot.firm` is meant to be copied to the root of your SD card for usage with Boot9Strap. The produced `boot.firm` is meant to be copied to the root of your SD card for usage with Boot9Strap.

View File

@@ -158,7 +158,7 @@ $(OUTPUT).elf : $(OFILES)
$(OFILES_SRC) : $(HFILES_BIN) $(OFILES_SRC) : $(HFILES_BIN)
memory.o strings.o: CFLAGS += -O3 memory.o strings.o: CFLAGS += -O3
config.o: CFLAGS += -DCONFIG_TITLE="\"$(APP_TITLE) $(REVISION)_3gx_beta configuration\"" config.o: CFLAGS += -DCONFIG_TITLE="\"$(APP_TITLE) $(REVISION) configuration\""
patches.o: CFLAGS += -DVERSION_MAJOR="$(VERSION_MAJOR)" -DVERSION_MINOR="$(VERSION_MINOR)"\ patches.o: CFLAGS += -DVERSION_MAJOR="$(VERSION_MAJOR)" -DVERSION_MINOR="$(VERSION_MINOR)"\
-DVERSION_BUILD="$(VERSION_BUILD)" -DISRELEASE="$(IS_RELEASE)" -DCOMMIT_HASH="0x$(COMMIT)" -DVERSION_BUILD="$(VERSION_BUILD)" -DISRELEASE="$(IS_RELEASE)" -DCOMMIT_HASH="0x$(COMMIT)"
#--------------------------------------------------------------------------------- #---------------------------------------------------------------------------------

View File

@@ -34,6 +34,8 @@
#include "buttons.h" #include "buttons.h"
#include "arm9_exception_handlers.h" #include "arm9_exception_handlers.h"
// See https://github.com/LumaTeam/luma3ds_exception_dump_parser
void installArm9Handlers(void) void installArm9Handlers(void)
{ {
vu32 *dstVeneers = (vu32 *)0x08000000; vu32 *dstVeneers = (vu32 *)0x08000000;

View File

@@ -131,7 +131,6 @@ u32 installK11Extension(u8 *pos, u32 size, bool needToInitSd, u32 baseK11VA, u32
u32 config, multiConfig, bootConfig; u32 config, multiConfig, bootConfig;
u64 hbldr3dsxTitleId; u64 hbldr3dsxTitleId;
u32 rosalinaMenuCombo; u32 rosalinaMenuCombo;
u32 rosalinaFlags;
} info; } info;
}; };
@@ -204,7 +203,6 @@ u32 installK11Extension(u8 *pos, u32 size, bool needToInitSd, u32 baseK11VA, u32
info->bootConfig = configData.bootConfig; info->bootConfig = configData.bootConfig;
info->hbldr3dsxTitleId = configData.hbldr3dsxTitleId; info->hbldr3dsxTitleId = configData.hbldr3dsxTitleId;
info->rosalinaMenuCombo = configData.rosalinaMenuCombo; info->rosalinaMenuCombo = configData.rosalinaMenuCombo;
info->rosalinaFlags = configData.rosalinaFlags;
info->versionMajor = VERSION_MAJOR; info->versionMajor = VERSION_MAJOR;
info->versionMinor = VERSION_MINOR; info->versionMinor = VERSION_MINOR;
info->versionBuild = VERSION_BUILD; info->versionBuild = VERSION_BUILD;
@@ -231,10 +229,6 @@ u32 patchKernel11(u8 *pos, u32 size, u32 baseK11VA, u32 *arm11SvcTable, u32 *arm
u8 *ControlMemoryPos = instrPos + 8 + displ; u8 *ControlMemoryPos = instrPos + 8 + displ;
u32 *off; u32 *off;
// Patch ControlMemory bounds checks for mem mapping
for (off = (u32 *)ControlMemoryPos; *off != 0xE0E01BF5; ++off);
*off = 0;
/* /*
Here we replace currentProcess->processID == 1 by additionnalParameter == 1. Here we replace currentProcess->processID == 1 by additionnalParameter == 1.
This patch should be generic enough to work even on firmware version 5.0. This patch should be generic enough to work even on firmware version 5.0.

View File

@@ -69,7 +69,6 @@ typedef struct __attribute__((packed, aligned(4)))
u32 config, multiConfig, bootConfig; u32 config, multiConfig, bootConfig;
u64 hbldr3dsxTitleId; u64 hbldr3dsxTitleId;
u32 rosalinaMenuCombo; u32 rosalinaMenuCombo;
u32 rosalinaFlags;
} CfgData; } CfgData;
typedef struct typedef struct

View File

@@ -1,190 +0,0 @@
#!/usr/bin/env python
# Requires Python >= 3.2 or >= 2.7
# This file is part of Luma3DS
# Copyright (C) 2016-2020 Aurora Wright, TuxSH
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# Additional Terms 7.b 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.
__author__ = "TuxSH"
__copyright__ = "Copyright (c) 2016-2020 TuxSH"
__license__ = "GPLv3"
__version__ = "v1.2"
"""
Parses Luma3DS exception dumps
"""
import argparse
from struct import unpack_from
import os
import subprocess
# Source of hexdump: https://gist.github.com/ImmortalPC/c340564823f283fe530b
# Credits for hexdump go to the original authors
# Slightly edited by TuxSH
def hexdump(addr, src, length=16, sep='.' ):
'''
@brief Return {src} in hex dump.
@param[in] length {Int} Nb Bytes by row.
@param[in] sep {Char} For the text part, {sep} will be used for non ASCII char.
@return {Str} The hexdump
@note Full support for python2 and python3 !
'''
result = []
# Python3 support
try:
xrange(0,1)
except NameError:
xrange = range
for i in xrange(0, len(src), length):
subSrc = src[i:i+length]
hexa = ''
isMiddle = False
for h in xrange(0,len(subSrc)):
if h == length/2:
hexa += ' '
h = subSrc[h]
if not isinstance(h, int):
h = ord(h)
h = hex(h).replace('0x','')
if len(h) == 1:
h = '0'+h
hexa += h+' '
hexa = hexa.strip(' ')
text = ''
for c in subSrc:
if not isinstance(c, int):
c = ord(c)
if 0x20 <= c < 0x7F:
text += chr(c)
else:
text += sep
result.append(('%08x: %-'+str(length*(2+1)+1)+'s |%s|') % (addr + i, hexa, text))
return '\n'.join(result)
def makeRegisterLine(A, rA, B, rB):
return "{0:<15}{1:<20}{2:<15}{3:<20}".format(A, "{0:08x}".format(rA), B, "{0:08x}".format(rB))
handledExceptionNames = ("FIQ", "undefined instruction", "prefetch abort", "data abort")
registerNames = tuple("r{0}".format(i) for i in range(13)) + ("sp", "lr", "pc", "cpsr") + ("dfsr", "ifsr", "far") + ("fpexc", "fpinst", "fpinst2")
svcBreakReasons = ("(svcBreak: panic)", "(svcBreak: assertion failed)", "(svcBreak: user-related)")
faultStatusSources = {
0b1:'Alignment', 0b100:'Instruction cache maintenance operation fault',
0b1100:'External Abort on translation - First-level', 0b1110:'External Abort on translation - Second-level',
0b101:'Translation - Section', 0b111:'Translation - Page', 0b11:'Access bit - Section', 0b110:'Access bit - Page',
0b1001:'Domain - Section', 0b1011:'Domain - Page', 0b1101:'Permission - Section', 0b1111:'Permission - Page',
0b1000:'Precise External Abort', 0b10110:'Imprecise External Abort', 0b10:'Debug event'
}
def main(args=None):
parser = argparse.ArgumentParser(description="Parse Luma3DS exception dumps")
parser.add_argument("filename")
args = parser.parse_args()
data = b""
with open(args.filename, "rb") as f: data = f.read()
if unpack_from("<2I", data) != (0xdeadc0de, 0xdeadcafe):
raise SystemExit("Invalid file format")
version, processor, exceptionType, _, nbRegisters, codeDumpSize, stackDumpSize, additionalDataSize = unpack_from("<8I", data, 8)
nbRegisters //= 4
if version < (1 << 16) | 2:
raise SystemExit("Incompatible format version, please use the appropriate parser.")
registers = unpack_from("<{0}I".format(nbRegisters), data, 40)
codeOffset = 40 + 4 * nbRegisters
codeDump = data[codeOffset : codeOffset + codeDumpSize]
stackOffset = codeOffset + codeDumpSize
stackDump = data[stackOffset : stackOffset + stackDumpSize]
addtionalDataOffset = stackOffset + stackDumpSize
additionalData = data[addtionalDataOffset : addtionalDataOffset + additionalDataSize]
if processor == 9: print("Processor: Arm9")
else: print("Processor: Arm11 (core {0})".format(processor >> 16))
typeDetailsStr = ""
if exceptionType == 2:
if (registers[16] & 0x20) == 0 and codeDumpSize >= 4:
instr = unpack_from("<I", codeDump[-4:])[0]
if instr == 0xe12fff7e:
typeDetailsStr = " (kernel panic)"
elif instr == 0xef00003c:
typeDetailsStr = " " + (svcBreakReasons[registers[0]] if registers[0] < 3 else "(svcBreak)")
elif (registers[16] & 0x20) == 1 and codeDumpSize >= 2:
instr = unpack_from("<I", codeDump[-4:])[0]
if instr == 0xdf3c:
typeDetailsStr = " " + (svcBreakReasons[registers[0]] if registers[0] < 3 else "(svcBreak)")
elif processor != 9 and (registers[20] & 0x80000000) != 0:
typeDetailsStr = " (VFP exception)"
print("Exception type: {0}{1}".format("unknown" if exceptionType >= len(handledExceptionNames) else handledExceptionNames[exceptionType], typeDetailsStr))
if processor == 11 and exceptionType >= 2:
xfsr = registers[18] if exceptionType == 2 else registers[17]
print("Fault status: " + faultStatusSources[xfsr & 0xf])
if additionalDataSize != 0:
print("Current process: {0} ({1:016x})".format(additionalData[:8].decode("ascii"), unpack_from("<Q", additionalData, 8)[0]))
print("\nRegister dump:\n")
for i in range(0, nbRegisters - (nbRegisters % 2), 2):
if i == 16: print("")
print(makeRegisterLine(registerNames[i], registers[i], registerNames[i+1], registers[i+1]))
if nbRegisters % 2 == 1: print("{0:<15}{1:<20}".format(registerNames[nbRegisters - 1], "{0:08x}".format(registers[nbRegisters - 1])))
if processor == 11 and exceptionType == 3:
print("{0:<15}{1:<20}Access type: {2}".format("FAR", "{0:08x}".format(registers[19]), "Write" if registers[17] & (1 << 11) != 0 else "Read"))
thumb = registers[16] & 0x20 != 0
addr = registers[15] - codeDumpSize / 2 + (2 if thumb else 4)
print("\nCode dump:\n")
objdump_res = ""
try:
path = os.path.join(os.environ["DEVKITARM"], "bin", "arm-none-eabi-objdump")
if os.name == "nt" and path[0] == '/':
path = ''.join(('c:', path[0], path[5:]))
objdump_res = subprocess.check_output((
path, "-marm", "-b", "binary",
"--adjust-vma="+hex(addr - codeOffset), "--start-address="+hex(addr),
"--stop-address="+hex(addr + codeDumpSize), "-D", "-z", "-M",
"reg-names-std" + (",force-thumb" if thumb else ""), args.filename
)).decode("utf-8")
objdump_res = '\n'.join(objdump_res[objdump_res.find('<.data+'):].split('\n')[1:])
except: objdump_res = ""
print(objdump_res if objdump_res != "" else hexdump(addr, codeDump))
print("\nStack dump:\n")
print(hexdump(registers[13], stackDump))
if __name__ == "__main__":
main()

View File

@@ -1,13 +0,0 @@
from setuptools import setup, find_packages
setup(
name='luma3ds_exception_dump_parser',
version='1.2',
url='https://github.com/AuroraWright/Luma3DS',
author='TuxSH',
license='GPLv3',
description='Parses Luma3DS exception dumps',
install_requires=[''],
packages=find_packages(),
entry_points={'console_scripts': ['luma3ds_exception_dump_parser=luma3ds_exception_dump_parser.__main__:main']},
)

View File

@@ -44,12 +44,8 @@ extern KAutoObject * (*KProcessHandleTable__ToKAutoObject)(KProcessHandleTable *
extern void (*KSynchronizationObject__Signal)(KSynchronizationObject *this, bool isPulse); extern void (*KSynchronizationObject__Signal)(KSynchronizationObject *this, bool isPulse);
extern Result (*WaitSynchronization1)(void *this_unused, KThread *thread, KSynchronizationObject *syncObject, s64 timeout); 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 (*KProcessHandleTable__CreateHandle)(KProcessHandleTable *this, Handle *out, KAutoObject *obj, u8 token);
extern Result (*KProcessHwInfo__QueryMemory)(KProcessHwInfo *this, MemoryInfo *memoryInfo, PageInfo *pageInfo, void *address);
extern Result (*KProcessHwInfo__MapProcessMemory)(KProcessHwInfo *this, KProcessHwInfo *other, void *dst, void *src, u32 nbPages); 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 (*KProcessHwInfo__UnmapProcessMemory)(KProcessHwInfo *this, void *addr, u32 nbPages);
extern Result (*KProcessHwInfo__CheckVaState)(KProcessHwInfo *hwInfo, u32 va, u32 size, u32 state, u32 perm);
extern Result (*KProcessHwInfo__GetListOfKBlockInfoForVA)(KProcessHwInfo *hwInfo, KLinkedList *list, u32 va, u32 sizeInPage);
extern Result (*KProcessHwInfo__MapListOfKBlockInfo)(KProcessHwInfo *this, u32 va, KLinkedList *list, u32 state, u32 perm, u32 sbz);
extern Result (*KEvent__Clear)(KEvent *this); extern Result (*KEvent__Clear)(KEvent *this);
extern void (*KObjectMutex__WaitAndAcquire)(KObjectMutex *this); extern void (*KObjectMutex__WaitAndAcquire)(KObjectMutex *this);
extern void (*KObjectMutex__ErrorOccured)(void); extern void (*KObjectMutex__ErrorOccured)(void);
@@ -57,11 +53,8 @@ extern void (*KObjectMutex__ErrorOccured)(void);
extern void (*KScheduler__AdjustThread)(KScheduler *this, KThread *thread, u32 oldSchedulingMask); extern void (*KScheduler__AdjustThread)(KScheduler *this, KThread *thread, u32 oldSchedulingMask);
extern void (*KScheduler__AttemptSwitchingThreadContext)(KScheduler *this); extern void (*KScheduler__AttemptSwitchingThreadContext)(KScheduler *this);
extern void (*KLinkedList_KBlockInfo__Clear)(KLinkedList *list);
extern Result (*ControlMemory)(u32 *addrOut, u32 addr0, u32 addr1, u32 size, MemOp op, MemPerm perm, bool isLoader); extern Result (*ControlMemory)(u32 *addrOut, u32 addr0, u32 addr1, u32 size, MemOp op, MemPerm perm, bool isLoader);
extern void (*SleepThread)(s64 ns); extern void (*SleepThread)(s64 ns);
extern Result (*CreateEvent)(Handle *out, ResetType resetType);
extern Result (*CloseHandle)(Handle handle); extern Result (*CloseHandle)(Handle handle);
extern Result (*GetHandleInfo)(s64 *out, Handle handle, u32 type); extern Result (*GetHandleInfo)(s64 *out, Handle handle, u32 type);
extern Result (*GetSystemInfo)(s64 *out, s32 type, s32 param); extern Result (*GetSystemInfo)(s64 *out, s32 type, s32 param);
@@ -72,7 +65,6 @@ extern Result (*SendSyncRequest)(Handle handle);
extern Result (*OpenProcess)(Handle *out, u32 processId); extern Result (*OpenProcess)(Handle *out, u32 processId);
extern Result (*GetProcessId)(u32 *out, Handle process); extern Result (*GetProcessId)(u32 *out, Handle process);
extern Result (*DebugActiveProcess)(Handle *out, u32 processId); extern Result (*DebugActiveProcess)(Handle *out, u32 processId);
extern Result (*SignalEvent)(Handle event);
extern Result (*UnmapProcessMemory)(Handle processHandle, void *dst, u32 size); extern Result (*UnmapProcessMemory)(Handle processHandle, void *dst, u32 size);
extern Result (*KernelSetState)(u32 type, u32 varg1, u32 varg2, u32 varg3); extern Result (*KernelSetState)(u32 type, u32 varg1, u32 varg2, u32 varg3);
@@ -137,7 +129,6 @@ typedef struct CfwInfo
u32 config, multiConfig, bootConfig; u32 config, multiConfig, bootConfig;
u64 hbldr3dsxTitleId; u64 hbldr3dsxTitleId;
u32 rosalinaMenuCombo; u32 rosalinaMenuCombo;
u32 rosalinaFlags;
} CfwInfo; } CfwInfo;
extern CfwInfo cfwInfo; extern CfwInfo cfwInfo;
@@ -146,5 +137,3 @@ extern u32 stolenSystemMemRegionSize;
extern vu32 rosalinaState; extern vu32 rosalinaState;
extern bool hasStartedRosalinaNetworkFuncsOnce; extern bool hasStartedRosalinaNetworkFuncsOnce;
KLinkedList* KLinkedList__Initialize(KLinkedList *list);

View File

@@ -105,14 +105,6 @@ typedef struct ALIGN(4) KMutex
union KProcess *owner; union KProcess *owner;
} KMutex; } KMutex;
typedef struct KAddressArbiter
{
KAutoObject autoObject;
struct KThread *first;
struct KThread *last;
union KProcess *owner;
} KAddressArbiter;
/* 92 */ /* 92 */
typedef struct KMutexLinkedList typedef struct KMutexLinkedList
{ {
@@ -120,30 +112,6 @@ typedef struct KMutexLinkedList
KMutex *last; KMutex *last;
} KMutexLinkedList; } KMutexLinkedList;
enum
{
TOKEN_KAUTOOBJECT = 0,
TOKEN_KSYNCHRONIZATIONOBJECT = 1,
TOKEN_KEVENT = 0x1F,
TOKEN_KSEMAPHORE = 0x2F,
TOKEN_KTIMER = 0x35,
TOKEN_KMUTEX = 0x39,
TOKEN_KDEBUG = 0x4D,
TOKEN_KSERVERPORT = 0x55,
TOKEN_KDMAOBJECT = 0x59,
TOKEN_KCLIENTPORT = 0x65,
TOKEN_KCODESET = 0x68,
TOKEN_KSESSION = 0x70,
TOKEN_KTHREAD = 0x8D,
TOKEN_KSERVERSESSION = 0x95,
TOKEN_KADDRESSARBITER = 0x98,
TOKEN_KCLIENTSESSION = 0xA5,
TOKEN_KPORT = 0xA8,
TOKEN_KSHAREDMEMORY = 0xB0,
TOKEN_KPROCESS = 0xC5,
TOKEN_KRESOURCELIMIT = 0xC8
};
/* 45 */ /* 45 */
typedef struct KClassToken typedef struct KClassToken
{ {
@@ -572,20 +540,6 @@ typedef struct KBlockInfo
u32 pageCount; u32 pageCount;
} KBlockInfo; } KBlockInfo;
typedef struct KSharedMemory
{
KAutoObject autoObject;
KLinkedList ownedKBlockInfo;
union KProcess *owner;
u32 ownerPermissions;
u32 otherPermissions;
u8 isBlockInfoGenerated;
s8 allBlockInfoGenerated;
u8 unknown_1;
u8 unknown_2;
u32 address;
} KSharedMemory;
/* 25 */ /* 25 */
typedef struct KMemoryBlock typedef struct KMemoryBlock
{ {
@@ -1083,26 +1037,10 @@ typedef struct KProcess##sys\
KThread *mainThread;\ KThread *mainThread;\
u32 interruptEnabledFlags[4];\ u32 interruptEnabledFlags[4];\
KProcessHandleTable handleTable;\ KProcessHandleTable handleTable;\
/* Custom fields for plugin system u8 gap234[52];\
{ */ \
u32 customFlags; /* see KProcess_CustomFlags enum below */ \
Handle onMemoryLayoutChangeEvent;\
Handle onProcessExitEvent;\
Handle resumeProcessExitEvent;\
/* } */ \
u8 gap234[36];\
u64 unused;\ u64 unused;\
} KProcess##sys; } KProcess##sys;
enum KProcess_CustomFlags
{
ForceRWXPages = 1 << 0,
SignalOnMemLayoutChanges = 1 << 1,
SignalOnExit = 1 << 2,
MemLayoutChanged = 1 << 16
};
INSTANCIATE_KPROCESS(N3DS); INSTANCIATE_KPROCESS(N3DS);
INSTANCIATE_KPROCESS(O3DS8x); INSTANCIATE_KPROCESS(O3DS8x);
INSTANCIATE_KPROCESS(O3DSPre8x); INSTANCIATE_KPROCESS(O3DSPre8x);

View File

@@ -1,129 +0,0 @@
#pragma once
#include "types.h"
#include "kernel.h"
typedef struct
{
u32 bits1_0 : 2; ///< 0b00
} Desc_TranslationFault;
typedef struct
{
u32 bits1_0 : 2; ///< 0b01
u32 sbz : 3;
u32 domain : 4;
u32 p : 1;
u32 addr : 21;
} Desc_CoarsePageTable;
typedef struct
{
u32 bits1_0 : 2; ///< 0b10
u32 b : 1;
u32 c : 1;
u32 xn : 1;
u32 domain : 4;
u32 p : 1;
u32 ap : 2;
u32 tex : 3;
u32 apx : 1;
u32 s : 1;
u32 ng : 1;
u32 bit18 : 1; ///< 0
u32 sbz : 1;
u32 addr : 12;
} Desc_Section;
typedef struct
{
u32 bits1_0 : 2; ///< 0b10
u32 b : 1;
u32 c : 1;
u32 xn : 1;
u32 domain : 4;
u32 p : 1;
u32 ap : 2;
u32 tex : 3;
u32 sbz : 3;
u32 bit18 : 1; ///< 1
u32 sbz2 : 5;
u32 addr : 8;
} Desc_Supersection;
typedef struct
{
u32 bits1_0 : 2; ///< 0b11
} Desc_Reserved;
typedef struct
{
u32 bits1_0 : 2; ///< 0b01
u32 b : 1;
u32 c : 1;
u32 ap : 2;
u32 sbz : 3;
u32 apx : 1;
u32 s : 1;
u32 ng : 1;
u32 tex : 3;
u32 xn : 1;
u32 addr : 16;
} Desc_LargePage;
typedef struct
{
u32 xn : 1;
u32 bit1 : 1; ///< 1
u32 b : 1;
u32 c : 1;
u32 ap : 2;
u32 tex : 3;
u32 apx : 1;
u32 s : 1;
u32 ng : 1;
u32 addr : 20;
} Desc_SmallPage;
typedef union
{
u32 raw;
Desc_TranslationFault translationFault;
Desc_CoarsePageTable coarsePageTable;
Desc_Section section;
Desc_Supersection supersection;
Desc_Reserved reserved;
} L1Descriptor;
typedef union
{
u32 raw;
Desc_TranslationFault translationFault;
Desc_LargePage largePage;
Desc_SmallPage smallPage;
} L2Descriptor;
typedef enum
{
Descriptor_TranslationFault,
Descriptor_CoarsePageTable,
Descriptor_Section,
Descriptor_Supersection,
Descriptor_Reserved,
Descriptor_LargePage,
Descriptor_SmallPage
} DescType;
void L1MMUTable__RWXForAll(u32 *table);
void L2MMUTable__RWXForAll(u32 *table);
u32 L1MMUTable__GetPAFromVA(u32 *table, u32 va);
u32 L2MMUTable__GetPAFromVA(u32 *table, u32 va);
u32 L1MMUTable__GetAddressUserPerm(u32 *table, u32 va);
u32 L2MMUTable__GetAddressUserPerm(u32 *table, u32 va);
void KProcessHwInfo__SetMMUTableToRWX(KProcessHwInfo *hwInfo);
u32 KProcessHwInfo__GetPAFromVA(KProcessHwInfo *hwInfo, u32 va);
u32 KProcessHwInfo__GetAddressUserPerm(KProcessHwInfo *hwInfo, u32 va);

View File

@@ -1,21 +0,0 @@
#pragma once
#include "utils.h"
#include "kernel.h"
#include "svc.h"
/// Operations for svcControlProcess
typedef enum ProcessOp
{
PROCESSOP_GET_ALL_HANDLES, ///< List all handles of the process, varg3 can be either 0 to fetch all handles, or token of the type to fetch
///< svcControlProcess(handle, PROCESSOP_GET_ALL_HANDLES, (u32)&outBuf, 0)
PROCESSOP_SET_MMU_TO_RWX, ///< Set the whole memory of the process with rwx access
///< svcControlProcess(handle, PROCESSOP_SET_MMU_TO_RWX, 0, 0)
PROCESSOP_GET_ON_MEMORY_CHANGE_EVENT,
PROCESSOP_GET_ON_EXIT_EVENT,
PROCESSOP_GET_PA_FROM_VA, ///< Get the physical address of the va within the process
///< svcControlProcess(handle, PROCESSOP_GET_PA_FROM_VA, (u32)&outPa, va)
PROCESSOP_SCHEDULE_THREADS,
} ProcessOp;
Result ControlProcess(Handle process, ProcessOp op, u32 varg2, u32 varg3);

View File

@@ -30,5 +30,4 @@
#include "kernel.h" #include "kernel.h"
#include "svc.h" #include "svc.h"
Result MapProcessMemoryEx(Handle dstProcessHandle, u32 vaDst, Handle srcProcessHandle, u32 vaSrc, u32 size); Result MapProcessMemoryEx(Handle processHandle, void *dst, void *src, u32 size);
Result MapProcessMemoryExWrapper(Handle dstProcessHandle, u32 vaDst, Handle srcProcessHandle, u32 vaSrc, u32 size);

View File

@@ -36,11 +36,12 @@ void executeFunctionOnCores(SGI0Handler_t func, u8 targetList, u8 targetListFilt
void KScheduler__TriggerCrossCoreInterrupt(KScheduler *this); void KScheduler__TriggerCrossCoreInterrupt(KScheduler *this);
void KThread__DebugReschedule(KThread *this, bool lock); void KThread__DebugReschedule(KThread *this, bool lock);
bool rosalinaThreadLockPredicate(KThread *thread);
bool rosalinaThreadLockPredicate(KThread *thread, u32 mask);
void rosalinaRescheduleThread(KThread *thread, bool lock); void rosalinaRescheduleThread(KThread *thread, bool lock);
void rosalinaLockThread(KThread *thread);
void rosalinaLockAllThreads(void); void rosalinaLockThreads(u32 mask);
void rosalinaUnlockAllThreads(void); void rosalinaUnlockThreads(u32 mask);
// Taken from ctrulib: // Taken from ctrulib:
@@ -49,6 +50,11 @@ static inline void __dsb(void)
__asm__ __volatile__("mcr p15, 0, %[val], c7, c10, 4" :: [val] "r" (0) : "memory"); __asm__ __volatile__("mcr p15, 0, %[val], c7, c10, 4" :: [val] "r" (0) : "memory");
} }
static inline void __dmb(void)
{
__asm__ __volatile__("mcr p15, 0, %[val], c7, c10, 5" :: [val] "r" (0) : "memory");
}
static inline void __clrex(void) static inline void __clrex(void)
{ {
__asm__ __volatile__("clrex" ::: "memory"); __asm__ __volatile__("clrex" ::: "memory");

View File

@@ -28,43 +28,10 @@
#include "fatalExceptionHandlers.h" #include "fatalExceptionHandlers.h"
#include "utils.h" #include "utils.h"
#include "kernel.h" #include "kernel.h"
#include "memory.h"
#include "mmu.h"
#include "globals.h" #include "globals.h"
#define REG_DUMP_SIZE 4 * 23 #define REG_DUMP_SIZE 4 * 23
#define CODE_DUMP_SIZE 96 #define CODE_DUMP_SIZE 48
// Return true if parameters are invalid
static bool checkExceptionHandlerValidity(KProcess *process, vu32 *threadLocalStorage)
{
if (process == NULL)
return true;
u32 stackBottom = threadLocalStorage[0x11];
u32 exceptionBuf = threadLocalStorage[0x12];
MemoryInfo memInfo;
PageInfo pageInfo;
KProcessHwInfo *hwInfo = hwInfoOfProcess(process);
u32 perm = KProcessHwInfo__GetAddressUserPerm(hwInfo, threadLocalStorage[0x10]);
if (stackBottom != 1)
{
if (KProcessHwInfo__QueryMemory(hwInfo, &memInfo, &pageInfo, (void *)stackBottom)
|| (memInfo.permissions & MEMPERM_RW) != MEMPERM_RW)
return true;
}
if (exceptionBuf > 1)
{
if (KProcessHwInfo__QueryMemory(hwInfo, &memInfo, &pageInfo, (void *)exceptionBuf)
|| (memInfo.permissions & MEMPERM_RW) != MEMPERM_RW)
return true;
}
return (perm & MEMPERM_RX) != MEMPERM_RX;
}
bool isExceptionFatal(u32 spsr, u32 *regs, u32 index) bool isExceptionFatal(u32 spsr, u32 *regs, u32 index)
{ {
@@ -76,7 +43,7 @@ bool isExceptionFatal(u32 spsr, u32 *regs, u32 index)
KProcess *currentProcess = currentCoreContext->objectContext.currentProcess; KProcess *currentProcess = currentCoreContext->objectContext.currentProcess;
if(thread != NULL && thread->threadLocalStorage != NULL && *((vu32 *)thread->threadLocalStorage + 0x10) != 0) if(thread != NULL && thread->threadLocalStorage != NULL && *((vu32 *)thread->threadLocalStorage + 0x10) != 0)
return checkExceptionHandlerValidity(currentProcess, (vu32 *)thread->threadLocalStorage); return false;
if(currentProcess != NULL) if(currentProcess != NULL)
{ {
@@ -85,7 +52,7 @@ bool isExceptionFatal(u32 spsr, u32 *regs, u32 index)
thread = KPROCESS_GET_RVALUE(currentProcess, mainThread); thread = KPROCESS_GET_RVALUE(currentProcess, mainThread);
if(thread != NULL && thread->threadLocalStorage != NULL && *((vu32 *)thread->threadLocalStorage + 0x10) != 0) if(thread != NULL && thread->threadLocalStorage != NULL && *((vu32 *)thread->threadLocalStorage + 0x10) != 0)
return checkExceptionHandlerValidity(currentProcess, thread->threadLocalStorage); return false;
if(index == 3 && strcmp(codeSetOfProcess(currentProcess)->processName, "menu") == 0 && // workaround a Home Menu bug leading to a dabort if(index == 3 && strcmp(codeSetOfProcess(currentProcess)->processName, "menu") == 0 && // workaround a Home Menu bug leading to a dabort
regs[0] == 0x3FFF && regs[2] == 0 && regs[5] == 2 && regs[7] == 1) regs[0] == 0x3FFF && regs[2] == 0 && regs[5] == 2 && regs[7] == 1)
@@ -103,7 +70,6 @@ bool isDataAbortExceptionRangeControlled(u32 spsr, u32 addr)
((u32)safecpy <= addr && addr < (u32)safecpy + safecpy_sz) ((u32)safecpy <= addr && addr < (u32)safecpy + safecpy_sz)
); );
} }
void fatalExceptionHandlersMain(u32 *registerDump, u32 type, u32 cpuId) void fatalExceptionHandlersMain(u32 *registerDump, u32 type, u32 cpuId)
{ {
ExceptionDumpHeader dumpHeader; ExceptionDumpHeader dumpHeader;
@@ -130,7 +96,7 @@ void fatalExceptionHandlersMain(u32 *registerDump, u32 type, u32 cpuId)
registerDump[15] = pc; registerDump[15] = pc;
//Dump code //Dump code
u8 *instr = (u8 *)pc + ((cpsr & 0x20) ? 2 : 4) - (dumpHeader.codeDumpSize >> 1) ; //wouldn't work well on 32-bit Thumb instructions, but it isn't much of a problem u8 *instr = (u8 *)pc + ((cpsr & 0x20) ? 2 : 4) - dumpHeader.codeDumpSize; //wouldn'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); dumpHeader.codeDumpSize = ((u32)instr & (((cpsr & 0x20) != 0) ? 1 : 3)) != 0 ? 0 : safecpy(codeDump, instr, dumpHeader.codeDumpSize);
//Copy register dump and code dump //Copy register dump and code dump

View File

@@ -40,12 +40,8 @@ KAutoObject * (*KProcessHandleTable__ToKAutoObject)(KProcessHandleTable *this, H
void (*KSynchronizationObject__Signal)(KSynchronizationObject *this, bool isPulse); void (*KSynchronizationObject__Signal)(KSynchronizationObject *this, bool isPulse);
Result (*WaitSynchronization1)(void *this_unused, KThread *thread, KSynchronizationObject *syncObject, s64 timeout); Result (*WaitSynchronization1)(void *this_unused, KThread *thread, KSynchronizationObject *syncObject, s64 timeout);
Result (*KProcessHandleTable__CreateHandle)(KProcessHandleTable *this, Handle *out, KAutoObject *obj, u8 token); Result (*KProcessHandleTable__CreateHandle)(KProcessHandleTable *this, Handle *out, KAutoObject *obj, u8 token);
Result (*KProcessHwInfo__QueryMemory)(KProcessHwInfo *this, MemoryInfo *memoryInfo, PageInfo *pageInfo, void *address);
Result (*KProcessHwInfo__MapProcessMemory)(KProcessHwInfo *this, KProcessHwInfo *other, void *dst, void *src, u32 nbPages); Result (*KProcessHwInfo__MapProcessMemory)(KProcessHwInfo *this, KProcessHwInfo *other, void *dst, void *src, u32 nbPages);
Result (*KProcessHwInfo__UnmapProcessMemory)(KProcessHwInfo *this, void *addr, u32 nbPages); Result (*KProcessHwInfo__UnmapProcessMemory)(KProcessHwInfo *this, void *addr, u32 nbPages);
Result (*KProcessHwInfo__CheckVaState)(KProcessHwInfo *hwInfo, u32 va, u32 size, u32 state, u32 perm);
Result (*KProcessHwInfo__GetListOfKBlockInfoForVA)(KProcessHwInfo *hwInfo, KLinkedList *list, u32 va, u32 sizeInPage);
Result (*KProcessHwInfo__MapListOfKBlockInfo)(KProcessHwInfo *this, u32 va, KLinkedList *list, u32 state, u32 perm, u32 sbz);
Result (*KEvent__Clear)(KEvent *this); Result (*KEvent__Clear)(KEvent *this);
void (*KObjectMutex__WaitAndAcquire)(KObjectMutex *this); void (*KObjectMutex__WaitAndAcquire)(KObjectMutex *this);
void (*KObjectMutex__ErrorOccured)(void); void (*KObjectMutex__ErrorOccured)(void);
@@ -53,11 +49,8 @@ void (*KObjectMutex__ErrorOccured)(void);
void (*KScheduler__AdjustThread)(KScheduler *this, KThread *thread, u32 oldSchedulingMask); void (*KScheduler__AdjustThread)(KScheduler *this, KThread *thread, u32 oldSchedulingMask);
void (*KScheduler__AttemptSwitchingThreadContext)(KScheduler *this); void (*KScheduler__AttemptSwitchingThreadContext)(KScheduler *this);
void (*KLinkedList_KBlockInfo__Clear)(KLinkedList *list);
Result (*ControlMemory)(u32 *addrOut, u32 addr0, u32 addr1, u32 size, MemOp op, MemPerm perm, bool isLoader); Result (*ControlMemory)(u32 *addrOut, u32 addr0, u32 addr1, u32 size, MemOp op, MemPerm perm, bool isLoader);
void (*SleepThread)(s64 ns); void (*SleepThread)(s64 ns);
Result (*CreateEvent)(Handle *out, ResetType resetType);
Result (*CloseHandle)(Handle handle); Result (*CloseHandle)(Handle handle);
Result (*GetHandleInfo)(s64 *out, Handle handle, u32 type); Result (*GetHandleInfo)(s64 *out, Handle handle, u32 type);
Result (*GetSystemInfo)(s64 *out, s32 type, s32 param); Result (*GetSystemInfo)(s64 *out, s32 type, s32 param);
@@ -68,7 +61,6 @@ Result (*SendSyncRequest)(Handle handle);
Result (*OpenProcess)(Handle *out, u32 processId); Result (*OpenProcess)(Handle *out, u32 processId);
Result (*GetProcessId)(u32 *out, Handle process); Result (*GetProcessId)(u32 *out, Handle process);
Result (*DebugActiveProcess)(Handle *out, u32 processId); Result (*DebugActiveProcess)(Handle *out, u32 processId);
Result (*SignalEvent)(Handle event);
Result (*UnmapProcessMemory)(Handle processHandle, void *dst, u32 size); Result (*UnmapProcessMemory)(Handle processHandle, void *dst, u32 size);
Result (*KernelSetState)(u32 type, u32 varg1, u32 varg2, u32 varg3); Result (*KernelSetState)(u32 type, u32 varg1, u32 varg2, u32 varg3);
@@ -121,10 +113,3 @@ u32 stolenSystemMemRegionSize;
vu32 rosalinaState; vu32 rosalinaState;
bool hasStartedRosalinaNetworkFuncsOnce; bool hasStartedRosalinaNetworkFuncsOnce;
KLinkedList* KLinkedList__Initialize(KLinkedList *list)
{
list->size = 0;
list->nodes.first = list->nodes.last = (KLinkedListNode *)&list->nodes;
return list;
}

View File

@@ -123,61 +123,11 @@ void configHook(vu8 *cfgPage)
*isDevUnit = true; // enable debug features *isDevUnit = true; // enable debug features
} }
void KProcessHwInfo__MapL1Section_Hook(void);
void KProcessHwInfo__MapL2Section_Hook(void);
static void installMmuHooks(void)
{
u32 *mapL1Section = NULL;
u32 *mapL2Section = NULL;
u32 *off;
for(off = (u32 *)officialSVCs[0x1F]; *off != 0xE1CD60F0; ++off);
off = decodeArmBranch(off + 1);
for (; *off != 0xE58D5000; ++off);
off = decodeArmBranch(off + 1);
for (; *off != 0xE58DC000; ++off);
off = decodeArmBranch(off + 1);
for (; *off != 0xE1A0000B; ++off);
off = decodeArmBranch(off + 1);
for (; *off != 0xE59D2030; ++off);
off = decodeArmBranch(off + 1);
for (; *off != 0xE88D1100; ++off);
mapL2Section = (u32 *)PA_FROM_VA_PTR(decodeArmBranch(off + 1));
do
{
for (; *off != 0xE58D8000; ++off);
u32 *loc = (u32 *)PA_FROM_VA_PTR(decodeArmBranch(++off));
if (loc != mapL2Section)
mapL1Section = loc;
} while (mapL1Section == NULL);
mapL1Section[1] = 0xE28FE004; // add lr, pc, #4
mapL1Section[2] = 0xE51FF004; // ldr pc, [pc, #-4]
mapL1Section[3] = (u32)KProcessHwInfo__MapL1Section_Hook;
mapL2Section[1] = 0xE28FE004; // add lr, pc, #4
mapL2Section[2] = 0xE51FF004; // ldr pc, [pc, #-4]
mapL2Section[3] = (u32)KProcessHwInfo__MapL2Section_Hook;
}
static void findUsefulSymbols(void) static void findUsefulSymbols(void)
{ {
u32 *off; u32 *off;
// Patch ERRF__DumpException for(off = (u32 *)0xFFFF0000; *off != 0xE1A0D002; off++);
for(off = (u32 *)0xFFFF0000; *off != 0xE1A04005; ++off);
++off;
*(u32 *)PA_FROM_VA_PTR(off) = makeArmBranch(off, off + 51, false);
for(; *off != 0xE2100102; ++off);
KProcessHwInfo__QueryMemory = (Result (*)(KProcessHwInfo *, MemoryInfo *, PageInfo *, void *))decodeArmBranch(off - 1);
for(; *off != 0xE1A0D002; off++);
off += 3; off += 3;
initFPU = (void (*) (void))off; initFPU = (void (*) (void))off;
@@ -240,18 +190,6 @@ static void findUsefulSymbols(void)
for(off = (u32 *)officialSVCs[0x72]; *off != 0xE2041102; off++); for(off = (u32 *)officialSVCs[0x72]; *off != 0xE2041102; off++);
KProcessHwInfo__UnmapProcessMemory = (Result (*)(KProcessHwInfo *, void *, u32))decodeArmBranch(off - 1); KProcessHwInfo__UnmapProcessMemory = (Result (*)(KProcessHwInfo *, void *, u32))decodeArmBranch(off - 1);
for (off = (u32 *)officialSVCs[0x70]; *off != 0xE8881200 && *off != 0xE8891900; ++off);
for (off = (u32 *)decodeArmBranch(off + 1); *off != 0xE2101102; ++off);
KProcessHwInfo__CheckVaState = (Result (*)(KProcessHwInfo *, u32, u32, u32, u32))decodeArmBranch(off - 1);
for (; *off != 0xE28D1008; ++off);
KProcessHwInfo__GetListOfKBlockInfoForVA = (Result (*)(KProcessHwInfo*, KLinkedList*, u32, u32))decodeArmBranch(off + 1);
for (; *off != 0xE2000102; ++off);
KProcessHwInfo__MapListOfKBlockInfo = (Result (*)(KProcessHwInfo*, u32, KLinkedList*, u32, u32, u32))decodeArmBranch(off - 1);
for (; *off != 0xE8BD8FF0; ++off);
KLinkedList_KBlockInfo__Clear = (void (*)(KLinkedList *))decodeArmBranch(off - 6);
for(off = (u32 *)officialSVCs[0x7C]; *off != 0x03530000; off++); for(off = (u32 *)officialSVCs[0x7C]; *off != 0x03530000; off++);
KObjectMutex__WaitAndAcquire = (void (*)(KObjectMutex *))decodeArmBranch(++off); KObjectMutex__WaitAndAcquire = (void (*)(KObjectMutex *))decodeArmBranch(++off);
for(; *off != 0xE320F000; off++); for(; *off != 0xE320F000; off++);
@@ -297,7 +235,6 @@ static void findUsefulSymbols(void)
ControlMemory = (Result (*)(u32 *, u32, u32, u32, MemOp, MemPerm, bool)) ControlMemory = (Result (*)(u32 *, u32, u32, u32, MemOp, MemPerm, bool))
decodeArmBranch((u32 *)officialSVCs[0x01] + 5); decodeArmBranch((u32 *)officialSVCs[0x01] + 5);
SleepThread = (void (*)(s64))officialSVCs[0x0A]; SleepThread = (void (*)(s64))officialSVCs[0x0A];
CreateEvent = (Result (*)(Handle *, ResetType))decodeArmBranch((u32 *)officialSVCs[0x17] + 3);
CloseHandle = (Result (*)(Handle))officialSVCs[0x23]; CloseHandle = (Result (*)(Handle))officialSVCs[0x23];
GetHandleInfo = (Result (*)(s64 *, Handle, u32))decodeArmBranch((u32 *)officialSVCs[0x29] + 3); GetHandleInfo = (Result (*)(s64 *, Handle, u32))decodeArmBranch((u32 *)officialSVCs[0x29] + 3);
GetSystemInfo = (Result (*)(s64 *, s32, s32))decodeArmBranch((u32 *)officialSVCs[0x2A] + 3); GetSystemInfo = (Result (*)(s64 *, s32, s32))decodeArmBranch((u32 *)officialSVCs[0x2A] + 3);
@@ -308,7 +245,6 @@ static void findUsefulSymbols(void)
OpenProcess = (Result (*)(Handle *, u32))decodeArmBranch((u32 *)officialSVCs[0x33] + 3); OpenProcess = (Result (*)(Handle *, u32))decodeArmBranch((u32 *)officialSVCs[0x33] + 3);
GetProcessId = (Result (*)(u32 *, Handle))decodeArmBranch((u32 *)officialSVCs[0x35] + 3); GetProcessId = (Result (*)(u32 *, Handle))decodeArmBranch((u32 *)officialSVCs[0x35] + 3);
DebugActiveProcess = (Result (*)(Handle *, u32))decodeArmBranch((u32 *)officialSVCs[0x60] + 3); DebugActiveProcess = (Result (*)(Handle *, u32))decodeArmBranch((u32 *)officialSVCs[0x60] + 3);
SignalEvent = (Result (*)(Handle event))officialSVCs[0x18];
UnmapProcessMemory = (Result (*)(Handle, void *, u32))officialSVCs[0x72]; UnmapProcessMemory = (Result (*)(Handle, void *, u32))officialSVCs[0x72];
KernelSetState = (Result (*)(u32, u32, u32, u32))((u32 *)officialSVCs[0x7C] + 1); KernelSetState = (Result (*)(u32, u32, u32, u32))((u32 *)officialSVCs[0x7C] + 1);
@@ -340,8 +276,6 @@ static void findUsefulSymbols(void)
invalidateInstructionCacheRange = (void (*)(void *, u32))off2; invalidateInstructionCacheRange = (void (*)(void *, u32))off2;
} }
} }
installMmuHooks();
} }
void main(FcramLayout *layout, KCoreContext *ctxs) void main(FcramLayout *layout, KCoreContext *ctxs)

View File

@@ -1,315 +0,0 @@
#include "mmu.h"
#include "globals.h"
#include "utils.h"
DescType L1Descriptor__GetType(u32 descriptor)
{
L1Descriptor pdesc = {descriptor};
if (pdesc.reserved.bits1_0 == 0b00)
return Descriptor_TranslationFault;
if (pdesc.reserved.bits1_0 == 0b01)
return Descriptor_CoarsePageTable;
if (pdesc.reserved.bits1_0 == 0b10)
return pdesc.section.bit18 == 0 ? Descriptor_Section : Descriptor_Supersection;
return Descriptor_Reserved;
}
DescType L2Descriptor__GetType(u32 descriptor)
{
L2Descriptor pdesc = {descriptor};
if (pdesc.translationFault.bits1_0 == 0b01)
return Descriptor_LargePage;
if (pdesc.smallPage.bit1 == 1)
return Descriptor_SmallPage;
return Descriptor_TranslationFault;
}
void L1MMUTable__RWXForAll(u32 *table)
{
u32 *tableEnd = table + 1024;
for (; table != tableEnd; ++table)
{
L1Descriptor descriptor = {*table};
switch (L1Descriptor__GetType(descriptor.raw))
{
case Descriptor_CoarsePageTable:
{
u32 *l2table = (u32 *)((descriptor.coarsePageTable.addr << 10) - 0x40000000);
L2MMUTable__RWXForAll(l2table);
break;
}
case Descriptor_Section:
{
descriptor.section.xn = 0;
descriptor.section.apx = 0;
descriptor.section.ap = 3;
*table = descriptor.raw;
break;
}
case Descriptor_Supersection:
{
descriptor.supersection.xn = 0;
descriptor.supersection.ap = 3;
*table = descriptor.raw;
break;
}
default:
break;
}
}
}
void L2MMUTable__RWXForAll(u32 *table)
{
u32 *tableEnd = table + 256;
for (; table != tableEnd; ++table)
{
L2Descriptor descriptor = {*table};
switch (L2Descriptor__GetType(descriptor.raw))
{
case Descriptor_LargePage:
{
descriptor.largePage.xn = 0;
descriptor.largePage.apx = 0;
descriptor.largePage.ap = 3;
*table = descriptor.raw;
break;
}
case Descriptor_SmallPage:
{
descriptor.smallPage.xn = 0;
descriptor.smallPage.apx = 0;
descriptor.smallPage.ap = 3;
*table = descriptor.raw;
break;
}
default:
break;
}
}
}
u32 L1MMUTable__GetPAFromVA(u32 *table, u32 va)
{
u32 pa = 0;
L1Descriptor descriptor = {table[va >> 20]};
switch (L1Descriptor__GetType(descriptor.raw))
{
case Descriptor_CoarsePageTable:
{
u32 *l2table = (u32 *)((descriptor.coarsePageTable.addr << 10) - 0x40000000);
pa = L2MMUTable__GetPAFromVA(l2table, va);
break;
}
case Descriptor_Section:
{
pa = descriptor.section.addr << 20;
pa |= (va << 12) >> 12;
break;
}
case Descriptor_Supersection:
{
pa = descriptor.supersection.addr << 24;
pa |= (va << 8) >> 8;
break;
}
default:
// VA not found
break;
}
return pa;
}
u32 L2MMUTable__GetPAFromVA(u32 *table, u32 va)
{
u32 pa = 0;
L2Descriptor descriptor = {table[(va << 12) >> 24]};
switch(L2Descriptor__GetType(descriptor.raw))
{
case Descriptor_LargePage:
{
pa = descriptor.largePage.addr << 16;
pa |= va & 0xFFFF;
break;
}
case Descriptor_SmallPage:
{
pa = descriptor.smallPage.addr << 12;
pa |= va & 0xFFF;
break;
}
default:
break;
}
return pa;
}
u32 L1MMUTable__GetAddressUserPerm(u32 *table, u32 va)
{
u32 perm = 0;
L1Descriptor descriptor = {table[va >> 20]};
switch (L1Descriptor__GetType(descriptor.raw))
{
case Descriptor_CoarsePageTable:
{
u32 *l2table = (u32 *)((descriptor.coarsePageTable.addr << 10) - 0x40000000);
perm = L2MMUTable__GetAddressUserPerm(l2table, va);
break;
}
case Descriptor_Section:
{
perm = descriptor.section.ap >> 1;
if (perm)
{
perm |= (!descriptor.section.apx && (descriptor.section.ap & 1)) << 1;
perm |= (!descriptor.section.xn) << 2;
}
break;
}
case Descriptor_Supersection:
{
perm = descriptor.supersection.ap >> 1;
if (perm)
{
perm |= (descriptor.supersection.ap & 1) << 1;
perm |= (!descriptor.supersection.xn) << 2;
}
break;
}
default:
// VA not found
break;
}
return perm;
}
u32 L2MMUTable__GetAddressUserPerm(u32 *table, u32 va)
{
u32 perm = 0;
L2Descriptor descriptor = {table[(va << 12) >> 24]};
switch(L2Descriptor__GetType(descriptor.raw))
{
case Descriptor_LargePage:
{
perm = descriptor.largePage.ap >> 1;
if (perm)
{
perm |= (!descriptor.largePage.apx && (descriptor.largePage.ap & 1)) << 1;
perm |= (!descriptor.largePage.xn) << 2;
}
break;
}
case Descriptor_SmallPage:
{
perm = descriptor.smallPage.ap >> 1;
if (perm)
{
perm |= (!descriptor.smallPage.apx && (descriptor.smallPage.ap & 1)) << 1;
perm |= (!descriptor.smallPage.xn) << 2;
}
break;
}
default:
break;
}
return perm;
}
void KProcessHwInfo__SetMMUTableToRWX(KProcessHwInfo *hwInfo)
{
KObjectMutex *mutex = KPROCESSHWINFO_GET_PTR(hwInfo, mutex);
u32 *table = KPROCESSHWINFO_GET_RVALUE(hwInfo, mmuTableVA);
KObjectMutex__Acquire(mutex);
L1MMUTable__RWXForAll(table);
KObjectMutex__Release(mutex);
}
u32 KProcessHwInfo__GetPAFromVA(KProcessHwInfo *hwInfo, u32 va)
{
KObjectMutex *mutex = KPROCESSHWINFO_GET_PTR(hwInfo, mutex);
u32 *table = KPROCESSHWINFO_GET_RVALUE(hwInfo, mmuTableVA);
KObjectMutex__Acquire(mutex);
u32 pa = L1MMUTable__GetPAFromVA(table, va);
KObjectMutex__Release(mutex);
return pa;
}
u32 KProcessHwInfo__GetAddressUserPerm(KProcessHwInfo *hwInfo, u32 va)
{
KObjectMutex *mutex = KPROCESSHWINFO_GET_PTR(hwInfo, mutex);
u32 *table = KPROCESSHWINFO_GET_RVALUE(hwInfo, mmuTableVA);
KObjectMutex__Acquire(mutex);
u32 perm = L1MMUTable__GetAddressUserPerm(table, va);
KObjectMutex__Release(mutex);
return perm;
}
static union
{
u32 raw;
struct
{
u32 xn : 1;
u32 unkn : 1;
u32 cb : 2;
u32 ap : 2;
u32 tex : 3;
u32 apx : 1;
u32 s : 1;
u32 ng : 1;
};
} g_rwxState;
// This function patch the permission when memory is mapped in the mmu table (rwx)
KProcessHwInfo *PatchDescriptorAccessControl(KProcessHwInfo *hwInfo, u32 **outState)
{
KProcess *process = (KProcess *)((u32)hwInfo - 0x1C);
u32 state = **outState;
u32 flags = KPROCESS_GET_RVALUE(process, customFlags);
if (flags & SignalOnMemLayoutChanges)
*KPROCESS_GET_PTR(process, customFlags) |= MemLayoutChanged;
if (!(flags & ForceRWXPages))
return hwInfo;
g_rwxState.raw = state;
g_rwxState.xn = 0;
g_rwxState.ap = 3;
g_rwxState.apx = 0;
*outState = &g_rwxState.raw;
return hwInfo;
}

View File

@@ -44,7 +44,6 @@
#include "svc/MapProcessMemoryEx.h" #include "svc/MapProcessMemoryEx.h"
#include "svc/UnmapProcessMemoryEx.h" #include "svc/UnmapProcessMemoryEx.h"
#include "svc/ControlService.h" #include "svc/ControlService.h"
#include "svc/ControlProcess.h"
#include "svc/CopyHandle.h" #include "svc/CopyHandle.h"
#include "svc/TranslateHandle.h" #include "svc/TranslateHandle.h"
@@ -60,16 +59,13 @@ void signalSvcEntry(u8 *pageEnd)
// Since DBGEVENT_SYSCALL_ENTRY is non blocking, we'll cheat using EXCEVENT_UNDEFINED_SYSCALL (debug->svcId is fortunately an u16!) // 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)) if(debugOfProcess(currentProcess) != NULL && shouldSignalSyscallDebugEvent(currentProcess, svcId))
{
SignalDebugEvent(DBGEVENT_OUTPUT_STRING, 0xFFFFFFFE, svcId); SignalDebugEvent(DBGEVENT_OUTPUT_STRING, 0xFFFFFFFE, svcId);
}
} }
void signalSvcReturn(u8 *pageEnd) void signalSvcReturn(u8 *pageEnd)
{ {
u32 svcId = (u32) *(u8 *)(pageEnd - 0xB5); u32 svcId = (u32) *(u8 *)(pageEnd - 0xB5);
KProcess *currentProcess = currentCoreContext->objectContext.currentProcess; KProcess *currentProcess = currentCoreContext->objectContext.currentProcess;
u32 flags = KPROCESS_GET_RVALUE(currentProcess, customFlags);
if(svcId == 0xFE) 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 svcId = *(u32 *)(pageEnd - 0x110 + 8 * 4); // r12 ; note: max theortical SVC atm: 0x1FFFFFFF. We don't support catching svcIds >= 0x100 atm either
@@ -77,19 +73,12 @@ void signalSvcReturn(u8 *pageEnd)
// Since DBGEVENT_SYSCALL_RETURN is non blocking, we'll cheat using EXCEVENT_UNDEFINED_SYSCALL (debug->svcId is fortunately an u16!) // 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)) if(debugOfProcess(currentProcess) != NULL && shouldSignalSyscallDebugEvent(currentProcess, svcId))
SignalDebugEvent(DBGEVENT_OUTPUT_STRING, 0xFFFFFFFF, svcId); SignalDebugEvent(DBGEVENT_OUTPUT_STRING, 0xFFFFFFFF, svcId);
// Signal if the memory layout of the process changed
if (flags & SignalOnMemLayoutChanges && flags & MemLayoutChanged)
{
*KPROCESS_GET_PTR(currentProcess, customFlags) = flags & ~MemLayoutChanged;
SignalEvent(KPROCESS_GET_RVALUE(currentProcess, onMemoryLayoutChangeEvent));
}
} }
void postprocessSvc(void) void postprocessSvc(void)
{ {
KThread *currentThread = currentCoreContext->objectContext.currentThread; KThread *currentThread = currentCoreContext->objectContext.currentThread;
if(!currentThread->shallTerminate && rosalinaThreadLockPredicate(currentThread)) if(!currentThread->shallTerminate && rosalinaThreadLockPredicate(currentThread, rosalinaState & 5))
rosalinaRescheduleThread(currentThread, true); rosalinaRescheduleThread(currentThread, true);
officialPostProcessSvc(); officialPostProcessSvc();
@@ -102,27 +91,10 @@ void *svcHook(u8 *pageEnd)
u32 svcId = *(u8 *)(pageEnd - 0xB5); u32 svcId = *(u8 *)(pageEnd - 0xB5);
if(svcId == 0xFE) 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 svcId = *(u32 *)(pageEnd - 0x110 + 8 * 4); // r12 ; note: max theortical SVC atm: 0x3FFFFFFF. We don't support catching svcIds >= 0x100 atm either
switch(svcId) switch(svcId)
{ {
case 0x01: case 0x01:
return ControlMemoryHookWrapper; return ControlMemoryHookWrapper;
case 0x03: /* svcExitProcess */
{
// Signal that the process is about to be terminated
u32 flags = KPROCESS_GET_RVALUE(currentProcess, customFlags);
if (flags & SignalOnExit)
{
SignalEvent(KPROCESS_GET_RVALUE(currentProcess, onProcessExitEvent));
KEvent* event = (KEvent *)KProcessHandleTable__ToKAutoObject(handleTableOfProcess(currentProcess),
KPROCESS_GET_RVALUE(currentProcess, resumeProcessExitEvent));
WaitSynchronization1(NULL, currentCoreContext->objectContext.currentThread, (KSynchronizationObject *)event, 10000000000ULL);
((KAutoObject *)event)->vtable->DecrementReferenceCount((KAutoObject *)event);
}
return officialSVCs[0x3];
}
case 0x29: case 0x29:
return GetHandleInfoHookWrapper; return GetHandleInfoHookWrapper;
case 0x2A: case 0x2A:
@@ -164,7 +136,7 @@ void *svcHook(u8 *pageEnd)
return invalidateEntireInstructionCache; return invalidateEntireInstructionCache;
case 0xA0: case 0xA0:
return MapProcessMemoryExWrapper; return MapProcessMemoryEx;
case 0xA1: case 0xA1:
return UnmapProcessMemoryEx; return UnmapProcessMemoryEx;
case 0xA2: case 0xA2:
@@ -176,8 +148,6 @@ void *svcHook(u8 *pageEnd)
return CopyHandleWrapper; return CopyHandleWrapper;
case 0xB2: case 0xB2:
return TranslateHandleWrapper; return TranslateHandleWrapper;
case 0xB3:
return ControlProcess;
default: default:
return (svcId <= 0x7D) ? officialSVCs[svcId] : NULL; return (svcId <= 0x7D) ? officialSVCs[svcId] : NULL;

View File

@@ -1,215 +0,0 @@
#include "svc/ControlProcess.h"
#include "memory.h"
#include "mmu.h"
#include "synchronization.h"
typedef bool (*ThreadPredicate)(KThread *thread);
void rosalinaLockThread(KThread *thread);
void rosalinaRescheduleThread(KThread *thread, bool lock);
Result ControlProcess(Handle processHandle, ProcessOp op, u32 varg2, u32 varg3)
{
Result res = 0;
KProcess *process;
KProcessHandleTable *handleTable = handleTableOfProcess(currentCoreContext->objectContext.currentProcess);
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 (op)
{
case PROCESSOP_GET_ALL_HANDLES:
{
KProcessHandleTable *table = handleTableOfProcess(process);
u32 *originalHandleList = (u32 *)varg2;
u32 count = 0;
u32 searchForToken = varg3;
HandleDescriptor *handleDesc = table->handleTable == NULL ? table->internalTable : table->handleTable;
for (u32 idx = 0; idx < (u32)table->maxHandleCount; ++idx, ++handleDesc)
{
if (handleDesc->pointer == NULL)
continue;
if (searchForToken)
{
KClassToken token;
handleDesc->pointer->vtable->GetClassToken(&token, handleDesc->pointer);
if (searchForToken != token.flags)
continue;
}
*originalHandleList++ = idx | ((handleDesc->info << 16) >> 1);
++count;
}
res = count;
break;
}
case PROCESSOP_SET_MMU_TO_RWX:
{
KProcessHwInfo *hwInfo = hwInfoOfProcess(process);
*KPROCESS_GET_PTR(process, customFlags) |= ForceRWXPages;
KProcessHwInfo__SetMMUTableToRWX(hwInfo);
break;
}
case PROCESSOP_GET_ON_MEMORY_CHANGE_EVENT:
{
// Only accept current process for this command
if (process != currentCoreContext->objectContext.currentProcess)
{
res = 0xD8E007F7; // invalid handle
break;
}
Handle *onMemoryLayoutChangeEvent = KPROCESS_GET_PTR(process, onMemoryLayoutChangeEvent);
if (*onMemoryLayoutChangeEvent == 0)
res = CreateEvent(onMemoryLayoutChangeEvent, RESET_ONESHOT);
if (res >= 0)
{
*KPROCESS_GET_PTR(process, customFlags) |= SignalOnMemLayoutChanges;
KAutoObject * event = KProcessHandleTable__ToKAutoObject(handleTable, *onMemoryLayoutChangeEvent);
createHandleForThisProcess((Handle *)varg2, event);
((KAutoObject *)event)->vtable->DecrementReferenceCount((KAutoObject *)event); ///< This avoid an extra operation on process exit
///< Closing the handle in the handle table will destroy the event
}
break;
}
case PROCESSOP_GET_ON_EXIT_EVENT:
{
// Only accept current process for this command
if (process != currentCoreContext->objectContext.currentProcess)
{
res = 0xD8E007F7; // invalid handle
break;
}
Handle *onProcessExitEvent = KPROCESS_GET_PTR(process, onProcessExitEvent);
Handle *resumeProcessExitEvent = KPROCESS_GET_PTR(process, resumeProcessExitEvent);
if (*onProcessExitEvent == 0)
res = CreateEvent(onProcessExitEvent, RESET_ONESHOT);
if (*resumeProcessExitEvent == 0)
res |= CreateEvent(resumeProcessExitEvent, RESET_ONESHOT);
if (res >= 0)
{
*KPROCESS_GET_PTR(process, customFlags) |= SignalOnExit;
KAutoObject * event = KProcessHandleTable__ToKAutoObject(handleTable, *onProcessExitEvent);
createHandleForThisProcess((Handle *)varg2, event);
((KAutoObject *)event)->vtable->DecrementReferenceCount((KAutoObject *)event); ///< See higher
event = KProcessHandleTable__ToKAutoObject(handleTable, *resumeProcessExitEvent);
createHandleForThisProcess((Handle *)varg3, event);
((KAutoObject *)event)->vtable->DecrementReferenceCount((KAutoObject *)event); ///< See higher
}
break;
}
case PROCESSOP_GET_PA_FROM_VA:
{
KProcessHwInfo *hwInfo = hwInfoOfProcess(process);
u32 pa = KProcessHwInfo__GetPAFromVA(hwInfo, varg3);
*(u32 *)varg2 = pa;
if (pa == 0)
res = 0xE0E01BF5; ///< Invalid address
break;
}
case PROCESSOP_SCHEDULE_THREADS:
{
ThreadPredicate threadPredicate = (ThreadPredicate)varg3;
KRecursiveLock__Lock(criticalSectionLock);
if (varg2 == 0) // Unlock
{
for(KLinkedListNode *node = threadList->list.nodes.first; node != (KLinkedListNode *)&threadList->list.nodes; node = node->next)
{
KThread *thread = (KThread *)node->key;
if((thread->schedulingMask & 0xF) == 2) // thread is terminating
continue;
if(thread->schedulingMask & 0x40)
rosalinaRescheduleThread(thread, false);
}
}
else // Lock
{
bool currentThreadsFound = false;
for(KLinkedListNode *node = threadList->list.nodes.first; node != (KLinkedListNode *)&threadList->list.nodes; node = node->next)
{
KThread *thread = (KThread *)node->key;
if(thread->ownerProcess != process
|| (threadPredicate != NULL && !threadPredicate(thread)))
continue;
if(thread == coreCtxs[thread->coreId].objectContext.currentThread)
currentThreadsFound = true;
else
rosalinaLockThread(thread);
}
if(currentThreadsFound)
{
for(KLinkedListNode *node = threadList->list.nodes.first; node != (KLinkedListNode *)&threadList->list.nodes; node = node->next)
{
KThread *thread = (KThread *)node->key;
if(thread->ownerProcess != process
|| (threadPredicate != NULL && !threadPredicate(thread)))
continue;
if(!(thread->schedulingMask & 0x40))
{
rosalinaLockThread(thread);
KRecursiveLock__Lock(criticalSectionLock);
if(thread->coreId != getCurrentCoreID())
{
u32 cpsr = __get_cpsr();
__disable_irq();
coreCtxs[thread->coreId].objectContext.currentScheduler->triggerCrossCoreInterrupt = true;
currentCoreContext->objectContext.currentScheduler->triggerCrossCoreInterrupt = true;
__set_cpsr_cx(cpsr);
}
KRecursiveLock__Unlock(criticalSectionLock);
}
}
KScheduler__TriggerCrossCoreInterrupt(currentCoreContext->objectContext.currentScheduler);
}
}
KRecursiveLock__Unlock(criticalSectionLock);
break;
}
default:
res = 0xF8C007F4;
}
((KAutoObject *)process)->vtable->DecrementReferenceCount((KAutoObject *)process);
return res;
}

View File

@@ -29,14 +29,11 @@
Result GetHandleInfoHook(s64 *out, Handle handle, u32 type) Result GetHandleInfoHook(s64 *out, Handle handle, u32 type)
{ {
Result res = 0; if(type == 0x10000) // KDebug and KProcess: get context ID
if(type >= 0x10000)
{ {
KProcessHwInfo *hwInfo; KProcessHwInfo *hwInfo;
KProcessHandleTable *handleTable = handleTableOfProcess(currentCoreContext->objectContext.currentProcess); KProcessHandleTable *handleTable = handleTableOfProcess(currentCoreContext->objectContext.currentProcess);
KAutoObject *obj; KAutoObject *obj;
if(handle == CUR_PROCESS_HANDLE) if(handle == CUR_PROCESS_HANDLE)
{ {
obj = (KAutoObject *)(currentCoreContext->objectContext.currentProcess); obj = (KAutoObject *)(currentCoreContext->objectContext.currentProcess);
@@ -48,82 +45,18 @@ Result GetHandleInfoHook(s64 *out, Handle handle, u32 type)
if(obj == NULL) if(obj == NULL)
return 0xD8E007F7; return 0xD8E007F7;
switch (type) if(strcmp(classNameOfAutoObject(obj), "KDebug") == 0)
{ hwInfo = hwInfoOfProcess(((KDebug *)obj)->owner);
case 0x10000: ///< Get ctx id (should probably move it to GetProcessInfo) else if(strcmp(classNameOfAutoObject(obj), "KProcess") == 0)
{ hwInfo = hwInfoOfProcess((KProcess *)obj);
if(strcmp(classNameOfAutoObject(obj), "KDebug") == 0) else
hwInfo = hwInfoOfProcess(((KDebug *)obj)->owner); hwInfo = NULL;
else if(strcmp(classNameOfAutoObject(obj), "KProcess") == 0)
hwInfo = hwInfoOfProcess((KProcess *)obj);
else
hwInfo = NULL;
*out = hwInfo != NULL ? KPROCESSHWINFO_GET_RVALUE(hwInfo, contextId) : -1; *out = hwInfo != NULL ? KPROCESSHWINFO_GET_RVALUE(hwInfo, contextId) : -1;
break;
}
case 0x10001: ///< Get referenced object flags (token)
{
KClassToken token;
obj->vtable->GetClassToken(&token, obj);
*out = token.flags;
break;
}
case 0x10002: ///< Get object owner
{
Handle hOut;
KClassToken token;
KProcess * owner = NULL;
obj->vtable->GetClassToken(&token, obj);
switch(token.flags)
{
case TOKEN_KEVENT:
owner = ((KEvent *)obj)->owner;
break;
case TOKEN_KSEMAPHORE:
owner = ((KSemaphore *)obj)->owner;
break;
case TOKEN_KTIMER:
owner = ((KTimer *)obj)->owner;
break;
case TOKEN_KMUTEX:
owner = ((KMutex *)obj)->owner;
break;
case TOKEN_KDEBUG:
owner = ((KDebug *)obj)->owner;
break;
case TOKEN_KTHREAD:
owner = ((KThread *)obj)->ownerProcess;
break;
case TOKEN_KADDRESSARBITER:
owner = ((KAddressArbiter *)obj)->owner;
break;
case TOKEN_KSHAREDMEMORY:
owner = ((KSharedMemory *)obj)->owner;
break;
default:
break;
}
if (owner == NULL)
res = 0xD8E007F7;
res = createHandleForThisProcess(&hOut, (KAutoObject *)owner);
*out = hOut;
break;
}
default:
res = 0xF8C007F4;
break;
}
obj->vtable->DecrementReferenceCount(obj); obj->vtable->DecrementReferenceCount(obj);
return res; return 0;
} }
else
return GetHandleInfo(out, handle, type); return GetHandleInfo(out, handle, type);
} }

View File

@@ -79,14 +79,6 @@ Result GetProcessInfoHook(s64 *out, Handle processHandle, u32 type)
*out = ttb & ~((1 << (14 - TTBCR)) - 1); *out = ttb & ~((1 << (14 - TTBCR)) - 1);
break; break;
} }
case 0x10009:
{
KProcessHwInfo *hwInfo = hwInfoOfProcess(process);
u32 mmusize = KPROCESSHWINFO_GET_RVALUE(hwInfo, mmuTableSize);
u32 mmupa = (u32)PA_FROM_VA_PTR(KPROCESSHWINFO_GET_RVALUE(hwInfo, mmuTableVA));
*out = (s64)(mmusize | ((s64)mmupa << 32));
break;
}
default: default:
res = 0xD8E007ED; // invalid enum value res = 0xD8E007ED; // invalid enum value
break; break;

View File

@@ -64,9 +64,6 @@ Result GetSystemInfoHook(s64 *out, s32 type, s32 param)
case 0x101: case 0x101:
*out = cfwInfo.rosalinaMenuCombo; *out = cfwInfo.rosalinaMenuCombo;
break; break;
case 0x102:
*out = cfwInfo.rosalinaFlags;
break;
case 0x200: // isRelease case 0x200: // isRelease
*out = cfwInfo.flags & 1; *out = cfwInfo.flags & 1;

View File

@@ -35,7 +35,6 @@
static u32 nbEnabled = 0; static u32 nbEnabled = 0;
static u32 maskedPids[MAX_DEBUG]; static u32 maskedPids[MAX_DEBUG];
static u32 masks[MAX_DEBUG][8] = {0}; static u32 masks[MAX_DEBUG][8] = {0};
static u32 *homeBtnPressed = NULL;
bool shouldSignalSyscallDebugEvent(KProcess *process, u8 svcId) bool shouldSignalSyscallDebugEvent(KProcess *process, u8 svcId)
{ {
@@ -105,14 +104,22 @@ Result KernelSetStateHook(u32 type, u32 varg1, u32 varg2, u32 varg3)
__ldrex((s32 *)&rosalinaState); __ldrex((s32 *)&rosalinaState);
} }
while(__strex((s32 *)&rosalinaState, (s32)(rosalinaState ^ varg1))); while(__strex((s32 *)&rosalinaState, (s32)(rosalinaState ^ varg1)));
__dmb();
if(rosalinaState & 2) if(rosalinaState & 0x10)
hasStartedRosalinaNetworkFuncsOnce = true; hasStartedRosalinaNetworkFuncsOnce = true;
if(rosalinaState & 1) // 1: all applet/app/dsp/csnd... threads 2: gsp 4: hid/ir
rosalinaLockAllThreads(); for (u32 v = 4; v != 0; v >>= 1)
else if(varg1 & 1) {
rosalinaUnlockAllThreads(); if (varg1 & v)
{
if (rosalinaState & v)
rosalinaLockThreads(v);
else
rosalinaUnlockThreads(v);
}
}
break; break;
} }
@@ -179,15 +186,6 @@ Result KernelSetStateHook(u32 type, u32 varg1, u32 varg2, u32 varg3)
KRecursiveLock__Unlock(&dbgParamsLock); KRecursiveLock__Unlock(&dbgParamsLock);
break; break;
} }
case 0x10007:
{
// A bit crude but do the job for a simple notification + reboot, nothing sensitive here
if (varg1 > 255 && homeBtnPressed == NULL)
homeBtnPressed = PA_FROM_VA_PTR((u32 *)varg1);
else if (homeBtnPressed != NULL && *homeBtnPressed == 0)
*homeBtnPressed = varg1;
break;
}
default: default:
{ {
res = KernelSetState(type, varg1, varg2, varg3); res = KernelSetState(type, varg1, varg2, varg3);

View File

@@ -26,61 +26,19 @@
#include "svc/MapProcessMemoryEx.h" #include "svc/MapProcessMemoryEx.h"
Result MapProcessMemoryEx(Handle dstProcessHandle, u32 vaDst, Handle srcProcessHandle, u32 vaSrc, u32 size) Result MapProcessMemoryEx(Handle processHandle, void *dst, void *src, u32 size)
{ {
Result res = 0;
u32 sizeInPage = size >> 12;
KLinkedList list;
KProcess *srcProcess;
KProcess *dstProcess;
KProcessHandleTable *handleTable = handleTableOfProcess(currentCoreContext->objectContext.currentProcess); KProcessHandleTable *handleTable = handleTableOfProcess(currentCoreContext->objectContext.currentProcess);
KProcessHwInfo *currentHwInfo = hwInfoOfProcess(currentCoreContext->objectContext.currentProcess);
KProcess *process = KProcessHandleTable__ToKProcess(handleTable, processHandle);
if (dstProcessHandle == CUR_PROCESS_HANDLE) if(process == NULL)
{
dstProcess = currentCoreContext->objectContext.currentProcess;
KAutoObject__AddReference((KAutoObject *)dstProcess);
}
else
dstProcess = KProcessHandleTable__ToKProcess(handleTable, dstProcessHandle);
if (dstProcess == NULL)
return 0xD8E007F7; return 0xD8E007F7;
if (srcProcessHandle == CUR_PROCESS_HANDLE) Result res = KProcessHwInfo__MapProcessMemory(currentHwInfo, hwInfoOfProcess(process), dst, src, size >> 12);
{
srcProcess = currentCoreContext->objectContext.currentProcess;
KAutoObject__AddReference((KAutoObject *)srcProcess);
}
else
srcProcess = KProcessHandleTable__ToKProcess(handleTable, srcProcessHandle);
if (srcProcess == NULL) KAutoObject *obj = (KAutoObject *)process;
{ obj->vtable->DecrementReferenceCount(obj);
res = 0xD8E007F7;
goto exit1;
}
KLinkedList__Initialize(&list);
res = KProcessHwInfo__GetListOfKBlockInfoForVA(hwInfoOfProcess(srcProcess), &list, vaSrc, sizeInPage);
if (res >= 0)
{
// Check if the destination address is free and large enough
res = KProcessHwInfo__CheckVaState(hwInfoOfProcess(dstProcess), vaDst, size, 0, 0);
if (res == 0)
res = KProcessHwInfo__MapListOfKBlockInfo(hwInfoOfProcess(dstProcess), vaDst, &list, 0x5806, MEMPERM_RW | 0x18, 0);
}
KLinkedList_KBlockInfo__Clear(&list);
((KAutoObject *)srcProcess)->vtable->DecrementReferenceCount((KAutoObject *)srcProcess);
exit1:
((KAutoObject *)dstProcess)->vtable->DecrementReferenceCount((KAutoObject *)dstProcess);
invalidateEntireInstructionCache();
flushEntireDataCache();
return res; return res;
} }

View File

@@ -28,9 +28,16 @@
#include "svc/SendSyncRequest.h" #include "svc/SendSyncRequest.h"
#include "ipc.h" #include "ipc.h"
static inline bool isNdmuWorkaround(const SessionInfo *info, u32 pid)
{
return info != NULL && strcmp(info->name, "ndm:u") == 0 && hasStartedRosalinaNetworkFuncsOnce && pid >= nbSection0Modules;
}
Result SendSyncRequestHook(Handle handle) Result SendSyncRequestHook(Handle handle)
{ {
KProcessHandleTable *handleTable = handleTableOfProcess(currentCoreContext->objectContext.currentProcess); KProcess *currentProcess = currentCoreContext->objectContext.currentProcess;
KProcessHandleTable *handleTable = handleTableOfProcess(currentProcess);
u32 pid = idOfProcess(currentProcess);
KClientSession *clientSession = (KClientSession *)KProcessHandleTable__ToKAutoObject(handleTable, handle); KClientSession *clientSession = (KClientSession *)KProcessHandleTable__ToKAutoObject(handleTable, handle);
u32 *cmdbuf = (u32 *)((u8 *)currentCoreContext->objectContext.currentThread->threadLocalStorage + 0x80); u32 *cmdbuf = (u32 *)((u8 *)currentCoreContext->objectContext.currentThread->threadLocalStorage + 0x80);
@@ -47,7 +54,7 @@ Result SendSyncRequestHook(Handle handle)
case 0x10042: case 0x10042:
{ {
SessionInfo *info = SessionInfo_Lookup(clientSession->parentSession); SessionInfo *info = SessionInfo_Lookup(clientSession->parentSession);
if(info != NULL && strcmp(info->name, "ndm:u") == 0 && hasStartedRosalinaNetworkFuncsOnce) if(isNdmuWorkaround(info, pid))
{ {
cmdbuf[0] = 0x10040; cmdbuf[0] = 0x10040;
cmdbuf[1] = 0; cmdbuf[1] = 0;
@@ -87,7 +94,7 @@ Result SendSyncRequestHook(Handle handle)
case 0x20002: case 0x20002:
{ {
SessionInfo *info = SessionInfo_Lookup(clientSession->parentSession); SessionInfo *info = SessionInfo_Lookup(clientSession->parentSession);
if(info != NULL && strcmp(info->name, "ndm:u") == 0 && hasStartedRosalinaNetworkFuncsOnce) if(isNdmuWorkaround(info, pid))
{ {
cmdbuf[0] = 0x20040; cmdbuf[0] = 0x20040;
cmdbuf[1] = 0; cmdbuf[1] = 0;
@@ -129,7 +136,7 @@ Result SendSyncRequestHook(Handle handle)
if(!hasStartedRosalinaNetworkFuncsOnce) if(!hasStartedRosalinaNetworkFuncsOnce)
break; break;
SessionInfo *info = SessionInfo_Lookup(clientSession->parentSession); SessionInfo *info = SessionInfo_Lookup(clientSession->parentSession);
skip = info != NULL && strcmp(info->name, "ndm:u") == 0; // SuspendScheduler skip = isNdmuWorkaround(info, pid); // SuspendScheduler
if(skip) if(skip)
cmdbuf[1] = 0; cmdbuf[1] = 0;
break; break;
@@ -140,7 +147,7 @@ Result SendSyncRequestHook(Handle handle)
if(!hasStartedRosalinaNetworkFuncsOnce) if(!hasStartedRosalinaNetworkFuncsOnce)
break; break;
SessionInfo *info = SessionInfo_Lookup(clientSession->parentSession); SessionInfo *info = SessionInfo_Lookup(clientSession->parentSession);
if(info != NULL && strcmp(info->name, "ndm:u") == 0) // ResumeScheduler if(isNdmuWorkaround(info, pid)) // ResumeScheduler
{ {
cmdbuf[0] = 0x90040; cmdbuf[0] = 0x90040;
cmdbuf[1] = 0; cmdbuf[1] = 0;

View File

@@ -29,45 +29,12 @@
Result UnmapProcessMemoryEx(Handle processHandle, void *dst, u32 size) Result UnmapProcessMemoryEx(Handle processHandle, void *dst, u32 size)
{ {
if (GET_VERSION_MINOR(kernelVersion) < 37) // < 6.x if(GET_VERSION_MINOR(kernelVersion) < 37) // < 6.x
return UnmapProcessMemory(processHandle, dst, size); // equivalent when size <= 64MB return UnmapProcessMemory(processHandle, dst, size); // equivalent when size <= 64MB
Result res = 0; KProcessHwInfo *currentHwInfo = hwInfoOfProcess(currentCoreContext->objectContext.currentProcess);
u32 sizeInPage = size >> 12;
KLinkedList list;
KProcess *process;
KProcessHwInfo *hwInfo;
KProcessHandleTable *handleTable = handleTableOfProcess(currentCoreContext->objectContext.currentProcess);
if (processHandle == CUR_PROCESS_HANDLE) Result res = KProcessHwInfo__UnmapProcessMemory(currentHwInfo, dst, size >> 12);
{
process = currentCoreContext->objectContext.currentProcess;
KAutoObject__AddReference((KAutoObject *)process);
}
else
process = KProcessHandleTable__ToKProcess(handleTable, processHandle);
if (process == NULL)
return 0xD8E007F7;
hwInfo = hwInfoOfProcess(process);
KLinkedList__Initialize(&list);
res = KProcessHwInfo__GetListOfKBlockInfoForVA(hwInfo, &list, (u32)dst, sizeInPage);
if (res >= 0)
{
// Check for dst address to be in the right state (0x5806 as we set it with svcMapProcessMemoryEx)
res = KProcessHwInfo__CheckVaState(hwInfo, (u32)dst, size, 0x5806, 0);
if (res == 0)
res = KProcessHwInfo__MapListOfKBlockInfo(hwInfo, (u32)dst, &list, 0, 0, 0);
}
KLinkedList_KBlockInfo__Clear(&list);
((KAutoObject *)process)->vtable->DecrementReferenceCount((KAutoObject *)process);
invalidateEntireInstructionCache(); invalidateEntireInstructionCache();
flushEntireDataCache(); flushEntireDataCache();

View File

@@ -84,12 +84,3 @@ ControlMemoryEx:
ldr r1, [sp, #12] ldr r1, [sp, #12]
add sp, #20 add sp, #20
pop {pc} pop {pc}
.global MapProcessMemoryExWrapper
.type MapProcessMemoryExWrapper, %function
MapProcessMemoryExWrapper:
push {lr}
str r4, [sp, #-4]!
bl MapProcessMemoryEx
add sp, #4
pop {pc}

View File

@@ -66,17 +66,12 @@ void KThread__DebugReschedule(KThread *this, bool lock)
KRecursiveLock__Unlock(criticalSectionLock); KRecursiveLock__Unlock(criticalSectionLock);
} }
bool rosalinaThreadLockPredicate(KThread *thread) static void rosalinaLockThread(KThread *thread)
{ {
KProcess *process = thread->ownerProcess; KThread *syncThread = synchronizationMutex->owner;
if(process == NULL)
return false;
u64 titleId = codeSetOfProcess(process)->titleId; if(syncThread == NULL || syncThread != thread)
u32 highTitleId = (u32)(titleId >> 32), lowTitleId = (u32)(titleId & ~0xF0000001); // clear N3DS and SAFE_FIRM bits rosalinaRescheduleThread(thread, true);
return
((rosalinaState & 1) && idOfProcess(process) >= nbSection0Modules &&
(highTitleId != 0x00040130 || (highTitleId == 0x00040130 && (lowTitleId == 0x1A02 || lowTitleId == 0x1C02))));
} }
void rosalinaRescheduleThread(KThread *thread, bool lock) void rosalinaRescheduleThread(KThread *thread, bool lock)
@@ -89,20 +84,45 @@ void rosalinaRescheduleThread(KThread *thread, bool lock)
else else
thread->schedulingMask &= ~0x40; thread->schedulingMask &= ~0x40;
KScheduler__AdjustThread(currentCoreContext->objectContext.currentScheduler, thread, oldSchedulingMask); if (oldSchedulingMask != thread->schedulingMask)
KScheduler__AdjustThread(currentCoreContext->objectContext.currentScheduler, thread, oldSchedulingMask);
KRecursiveLock__Unlock(criticalSectionLock); KRecursiveLock__Unlock(criticalSectionLock);
} }
void rosalinaLockThread(KThread *thread) bool rosalinaThreadLockPredicate(KThread *thread, u32 mask)
{ {
KThread *syncThread = synchronizationMutex->owner; KProcess *process = thread->ownerProcess;
if(process == NULL || idOfProcess(process) < nbSection0Modules)
return false;
if(syncThread == NULL || syncThread != thread) u64 titleId = codeSetOfProcess(process)->titleId;
rosalinaRescheduleThread(thread, true); u32 highTitleId = (u32)(titleId >> 32), lowTitleId = (u32)(titleId & ~0xF0000001); // clear N3DS and SAFE_FIRM bits
if (mask & 1)
{
if (highTitleId != 0x00040130) // non-sysmodules
return true;
else
return lowTitleId == 0x1A02 || lowTitleId == 0x2702; // dsp, csnd
}
if (mask & 2)
{
if (highTitleId != 0x00040130) // non-sysmodules
false;
return lowTitleId == 0x1C02; // gsp
}
if (mask & 4)
{
if (highTitleId != 0x00040130) // non-sysmodules
return false;
return lowTitleId == 0x1D02 || lowTitleId == 0x3302;
}
return false;
} }
void rosalinaLockAllThreads(void) void rosalinaLockThreads(u32 mask)
{ {
bool currentThreadsFound = false; bool currentThreadsFound = false;
@@ -110,7 +130,7 @@ void rosalinaLockAllThreads(void)
for(KLinkedListNode *node = threadList->list.nodes.first; node != (KLinkedListNode *)&threadList->list.nodes; node = node->next) for(KLinkedListNode *node = threadList->list.nodes.first; node != (KLinkedListNode *)&threadList->list.nodes; node = node->next)
{ {
KThread *thread = (KThread *)node->key; KThread *thread = (KThread *)node->key;
if(!rosalinaThreadLockPredicate(thread)) if(!rosalinaThreadLockPredicate(thread, mask))
continue; continue;
if(thread == coreCtxs[thread->coreId].objectContext.currentThread) if(thread == coreCtxs[thread->coreId].objectContext.currentThread)
currentThreadsFound = true; currentThreadsFound = true;
@@ -123,7 +143,7 @@ void rosalinaLockAllThreads(void)
for(KLinkedListNode *node = threadList->list.nodes.first; node != (KLinkedListNode *)&threadList->list.nodes; node = node->next) for(KLinkedListNode *node = threadList->list.nodes.first; node != (KLinkedListNode *)&threadList->list.nodes; node = node->next)
{ {
KThread *thread = (KThread *)node->key; KThread *thread = (KThread *)node->key;
if(!rosalinaThreadLockPredicate(thread)) if(!rosalinaThreadLockPredicate(thread, mask))
continue; continue;
if(!(thread->schedulingMask & 0x40)) if(!(thread->schedulingMask & 0x40))
{ {
@@ -145,7 +165,7 @@ void rosalinaLockAllThreads(void)
KRecursiveLock__Unlock(criticalSectionLock); KRecursiveLock__Unlock(criticalSectionLock);
} }
void rosalinaUnlockAllThreads(void) void rosalinaUnlockThreads(u32 mask)
{ {
for(KLinkedListNode *node = threadList->list.nodes.first; node != (KLinkedListNode *)&threadList->list.nodes; node = node->next) for(KLinkedListNode *node = threadList->list.nodes.first; node != (KLinkedListNode *)&threadList->list.nodes; node = node->next)
{ {
@@ -154,7 +174,7 @@ void rosalinaUnlockAllThreads(void)
if((thread->schedulingMask & 0xF) == 2) // thread is terminating if((thread->schedulingMask & 0xF) == 2) // thread is terminating
continue; continue;
if(thread->schedulingMask & 0x40) if((thread->schedulingMask & 0x40) && rosalinaThreadLockPredicate(thread, mask))
rosalinaRescheduleThread(thread, false); rosalinaRescheduleThread(thread, false);
} }
} }

View File

@@ -96,36 +96,6 @@ KObjectMutex__Release:
blx r12 blx r12
bx lr bx lr
.global KProcessHwInfo__MapL1Section_Hook
.type KProcessHwInfo__MapL1Section_Hook, %function
KProcessHwInfo__MapL1Section_Hook:
@r0 => hwInfo
@sp + 0x34 => our ptr to state
add r1, sp, #0x34
str lr, [sp, #-4]!
bl PatchDescriptorAccessControl
ldr lr, [sp], #4
ldmfd sp, {r0-r4}
sub sp, sp, #0x14
add r4, sp, #0x48
mov r11, #0
mov pc, lr
.global KProcessHwInfo__MapL2Section_Hook
.type KProcessHwInfo__MapL2Section_Hook, %function
KProcessHwInfo__MapL2Section_Hook:
@r0 => hwInfo
@sp + 0x34 => our ptr to state
add r1, sp, #0x34
str lr, [sp, #-4]!
bl PatchDescriptorAccessControl
ldr lr, [sp], #4
ldmfd sp, {r0-r4}
sub sp, sp, #0x4C
mov r4, r1
mov r6, r2
mov pc, lr
.global safecpy .global safecpy
.type safecpy, %function .type safecpy, %function
safecpy: safecpy:

View File

@@ -2,8 +2,6 @@
#include <3ds/exheader.h> #include <3ds/exheader.h>
#define HBLDR_3DSX_TID (*(vu64 *)0x1FF81100)
Result hbldrInit(void); Result hbldrInit(void);
void hbldrExit(void); void hbldrExit(void);

View File

@@ -4,6 +4,7 @@
#include "ifile.h" #include "ifile.h"
#include "util.h" #include "util.h"
#include "hbldr.h" #include "hbldr.h"
#include "luma_shared_config.h"
extern u32 config, multiConfig, bootConfig; extern u32 config, multiConfig, bootConfig;
extern bool isN3DS, isSdMode; extern bool isN3DS, isSdMode;
@@ -91,6 +92,11 @@ static int lzss_decompress(u8 *end)
return ret; return ret;
} }
static inline bool hbldrIs3dsxTitle(u64 tid)
{
return Luma_SharedConfig->use_hbldr && tid == Luma_SharedConfig->hbldr_3dsx_tid;
}
static Result allocateSharedMem(prog_addrs_t *shared, prog_addrs_t *vaddr, int flags) static Result allocateSharedMem(prog_addrs_t *shared, prog_addrs_t *vaddr, int flags)
{ {
u32 dummy; u32 dummy;
@@ -148,21 +154,6 @@ static Result loadCode(u64 titleId, prog_addrs_t *shared, u64 programHandle, int
return 0; return 0;
} }
static Result PLGLDR_Init(Handle *session)
{
Result res;
while (1)
{
res = svcConnectToPort(session, "plg: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 GetProgramInfo(ExHeader_Info *exheaderInfo, u64 programHandle) static Result GetProgramInfo(ExHeader_Info *exheaderInfo, u64 programHandle)
{ {
Result res = 0; Result res = 0;
@@ -184,11 +175,8 @@ static Result GetProgramInfo(ExHeader_Info *exheaderInfo, u64 programHandle)
} }
} }
s64 nbSection0Modules;
svcGetSystemInfo(&nbSection0Modules, 26, 0);
// Tweak 3dsx placeholder title exheaderInfo // Tweak 3dsx placeholder title exheaderInfo
if (nbSection0Modules == 6 && exheaderInfo->aci.local_caps.title_id == HBLDR_3DSX_TID) if (hbldrIs3dsxTitle(exheaderInfo->aci.local_caps.title_id))
{ {
assertSuccess(hbldrInit()); assertSuccess(hbldrInit());
HBLDR_PatchExHeaderInfo(exheaderInfo); HBLDR_PatchExHeaderInfo(exheaderInfo);
@@ -219,7 +207,7 @@ static Result LoadProcess(Handle *process, u64 programHandle)
u64 titleId; u64 titleId;
// make sure the cached info corrosponds to the current programHandle // make sure the cached info corrosponds to the current programHandle
if (g_cached_programHandle != programHandle || g_exheaderInfo.aci.local_caps.title_id == HBLDR_3DSX_TID) if (g_cached_programHandle != programHandle || hbldrIs3dsxTitle(g_exheaderInfo.aci.local_caps.title_id))
{ {
res = GetProgramInfo(&g_exheaderInfo, programHandle); res = GetProgramInfo(&g_exheaderInfo, programHandle);
g_cached_programHandle = programHandle; g_cached_programHandle = programHandle;
@@ -245,7 +233,7 @@ static Result LoadProcess(Handle *process, u64 programHandle)
titleId = g_exheaderInfo.aci.local_caps.title_id; titleId = g_exheaderInfo.aci.local_caps.title_id;
ExHeader_CodeSetInfo *csi = &g_exheaderInfo.sci.codeset_info; ExHeader_CodeSetInfo *csi = &g_exheaderInfo.sci.codeset_info;
if (titleId == HBLDR_3DSX_TID) if (hbldrIs3dsxTitle(titleId))
{ {
assertSuccess(hbldrInit()); assertSuccess(hbldrInit());
assertSuccess(HBLDR_LoadProcess(&codeset, csi->text.address, flags & 0xF00, titleId, csi->name)); assertSuccess(HBLDR_LoadProcess(&codeset, csi->text.address, flags & 0xF00, titleId, csi->name));
@@ -269,9 +257,6 @@ static Result LoadProcess(Handle *process, u64 programHandle)
// load code // load code
if (R_SUCCEEDED(res = loadCode(titleId, &sharedAddr, programHandle, csi->flags.compress_exefs_code))) if (R_SUCCEEDED(res = loadCode(titleId, &sharedAddr, programHandle, csi->flags.compress_exefs_code)))
{ {
u32 *code = (u32 *)sharedAddr.text_addr;
bool isHomebrew = code[0] == 0xEA000006 && code[8] == 0xE1A0400E;
memcpy(&codesetinfo.name, csi->name, 8); memcpy(&codesetinfo.name, csi->name, 8);
codesetinfo.program_id = titleId; codesetinfo.program_id = titleId;
codesetinfo.text_addr = vaddr.text_addr; codesetinfo.text_addr = vaddr.text_addr;
@@ -288,37 +273,7 @@ static Result LoadProcess(Handle *process, u64 programHandle)
{ {
res = svcCreateProcess(process, codeset, g_exheaderInfo.aci.kernel_caps.descriptors, count); res = svcCreateProcess(process, codeset, g_exheaderInfo.aci.kernel_caps.descriptors, count);
svcCloseHandle(codeset); svcCloseHandle(codeset);
if (res >= 0) res = R_SUCCEEDED(res) ? 0 : res;
{
// Try to load a plugin for the game
if (!isHomebrew && ((u32)((titleId >> 0x20) & 0xFFFFFFEDULL) == 0x00040000))
{
// Special case handling: games rebooting the 3DS on old models
if (!isN3DS && g_exheaderInfo.aci.local_caps.core_info.o3ds_system_mode > 0)
{
// Check if the plugin loader is enabled, otherwise skip the loading part
s64 out;
svcGetSystemInfo(&out, 0x10000, 0x102);
if ((out & 1) == 0)
return 0;
}
Handle plgldr = 0;
if (R_SUCCEEDED(PLGLDR_Init(&plgldr)))
{
u32* cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(1, 0, 2);
cmdbuf[1] = IPC_Desc_SharedHandles(1);
cmdbuf[2] = *process;
svcSendSyncRequest(plgldr);
svcCloseHandle(plgldr);
}
}
return 0;
}
} }
} }
@@ -425,7 +380,7 @@ void loaderHandleCommands(void *ctx)
break; break;
case 4: // GetProgramInfo case 4: // GetProgramInfo
memcpy(&programHandle, &cmdbuf[1], 8); memcpy(&programHandle, &cmdbuf[1], 8);
if (programHandle != g_cached_programHandle || g_exheaderInfo.aci.local_caps.title_id == HBLDR_3DSX_TID) if (programHandle != g_cached_programHandle || hbldrIs3dsxTitle(g_exheaderInfo.aci.local_caps.title_id))
{ {
res = GetProgramInfo(&g_exheaderInfo, programHandle); res = GetProgramInfo(&g_exheaderInfo, programHandle);
g_cached_programHandle = R_SUCCEEDED(res) ? programHandle : 0; g_cached_programHandle = R_SUCCEEDED(res) ? programHandle : 0;

View File

@@ -0,0 +1,28 @@
/* 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>
/// Luma shared config type.
typedef struct LumaSharedConfig {
u64 hbldr_3dsx_tid; ///< Title ID to use for 3DSX loading.
bool use_hbldr; ///< Whether or not Loader should use hb:ldr (Rosalina writes 1).
} LumaSharedConfig;
/// Luma shared config.
#define Luma_SharedConfig ((volatile LumaSharedConfig *)(OS_SHAREDCFG_VADDR + 0x800))

View File

@@ -3,7 +3,7 @@ Open source replacement of the Arm11 PM system module.
This is licensed under the MIT license. This is licensed under the MIT license.
# Usage # Usage
To run this system module, use a recent release or commit of [Luma3DS](https://github.com/AuroraWright/Luma3DS/), build this project and copy the generated CXI file to `/luma/sysmodules/pm.cxi`. To run this system module, use a recent release or commit of [Luma3DS](https://github.com/LumaTeam/Luma3DS/), build this project and copy the generated CXI file to `/luma/sysmodules/pm.cxi`.
# Credits # Credits
@fincs @fincs

View File

@@ -218,8 +218,9 @@ static Result launchTitleImpl(Handle *debug, ProcessData **outProcessData, const
programInfoUpdate = (launchFlags & PMLAUNCHFLAG_USE_UPDATE_TITLE) ? programInfoUpdate : programInfo; programInfoUpdate = (launchFlags & PMLAUNCHFLAG_USE_UPDATE_TITLE) ? programInfoUpdate : programInfo;
TRY(registerProgram(&programHandle, programInfo, programInfoUpdate)); TRY(registerProgram(&programHandle, programInfo, programInfoUpdate));
u32 coreVer = OS_KernelConfig->kernel_syscore_ver;
res = LOADER_GetProgramInfo(exheaderInfo, programHandle); res = LOADER_GetProgramInfo(exheaderInfo, programHandle);
res = R_SUCCEEDED(res) && SYSCOREVER == 2 && exheaderInfo->aci.local_caps.core_info.core_version != SYSCOREVER ? (Result)0xC8A05800 : res; res = R_SUCCEEDED(res) && coreVer == 2 && exheaderInfo->aci.local_caps.core_info.core_version != coreVer ? (Result)0xC8A05800 : res;
if (R_FAILED(res)) { if (R_FAILED(res)) {
LOADER_UnregisterProgram(programHandle); LOADER_UnregisterProgram(programHandle);
@@ -227,7 +228,7 @@ static Result launchTitleImpl(Handle *debug, ProcessData **outProcessData, const
} }
// Change APPMEMALLOC if needed // Change APPMEMALLOC if needed
if (IS_N3DS && APPMEMTYPE == 6 && (launchFlags & PMLAUNCHFLAG_NORMAL_APPLICATION) != 0) { if (IS_N3DS && OS_KernelConfig->app_memtype == 6 && (launchFlags & PMLAUNCHFLAG_NORMAL_APPLICATION) != 0) {
u32 limitMb; u32 limitMb;
SystemMode n3dsSystemMode = exheaderInfo->aci.local_caps.core_info.n3ds_system_mode; SystemMode n3dsSystemMode = exheaderInfo->aci.local_caps.core_info.n3ds_system_mode;
bool forceO3dsAppMem = (launchFlags & PMLAUNCHFLAG_FORCE_USE_O3DS_APP_MEM) != 0; bool forceO3dsAppMem = (launchFlags & PMLAUNCHFLAG_FORCE_USE_O3DS_APP_MEM) != 0;
@@ -332,9 +333,11 @@ Result LaunchTitle(u32 *outPid, const FS_ProgramInfo *programInfo, u32 launchFla
u32 tidh = (u32)(programInfo->programId >> 32); u32 tidh = (u32)(programInfo->programId >> 32);
u32 tidl = (u32)programInfo->programId; u32 tidl = (u32)programInfo->programId;
if ((tidh == 0x00040030 || tidh == 0x00040130) && (tidl & 0xFF) != SYSCOREVER) { u32 coreVer = OS_KernelConfig->kernel_syscore_ver;
if (coreVer == 2 && (tidh == 0x00040030 || tidh == 0x00040130) && (tidl & 0xFF) != coreVer) {
// Panic if launching SAFE_MODE sysmodules or applets (note: exheader syscorever check above only done for applications in official PM) // Panic if launching SAFE_MODE sysmodules or applets (note: exheader syscorever check above only done for applications in official PM)
// Official PM also hardcodes SYSCOREVER = 2 here. // Official PM also hardcodes SYSCOREVER = 2 here.
// NATIVE_FIRM-only.
panic(4); panic(4);
} }
@@ -520,8 +523,8 @@ Result autolaunchSysmodules(void)
FS_ProgramInfo programInfo = { .mediaType = MEDIATYPE_NAND }; FS_ProgramInfo programInfo = { .mediaType = MEDIATYPE_NAND };
// Launch NS // Launch NS
if (NSTID != 0) { if (OS_KernelConfig->ns_tid != 0) {
programInfo.programId = NSTID; programInfo.programId = OS_KernelConfig->ns_tid;
TRY(launchTitleImplWrapper(NULL, NULL, &programInfo, &programInfo, PMLAUNCHFLAG_LOAD_DEPENDENCIES)); TRY(launchTitleImplWrapper(NULL, NULL, &programInfo, &programInfo, PMLAUNCHFLAG_LOAD_DEPENDENCIES));
} }

View File

@@ -29,7 +29,7 @@ static void cleanupProcess(ProcessData *process)
ProcessList_Lock(&g_manager.processList); ProcessList_Lock(&g_manager.processList);
if (g_manager.runningApplicationData != NULL && process->handle == g_manager.runningApplicationData->handle) { if (g_manager.runningApplicationData != NULL && process->handle == g_manager.runningApplicationData->handle) {
if (IS_N3DS && APPMEMTYPE == 6) { if (IS_N3DS && OS_KernelConfig->app_memtype == 6) {
assertSuccess(resetAppMemLimit()); assertSuccess(resetAppMemLimit());
} }
g_manager.runningApplicationData = NULL; g_manager.runningApplicationData = NULL;

View File

@@ -252,7 +252,8 @@ static ReslimitValues *fixupReslimitValues(void)
// Note: we lie in the reslimit and make as if neither KExt nor Roslina existed, to avoid breakage // Note: we lie in the reslimit and make as if neither KExt nor Roslina existed, to avoid breakage
u32 sysmemalloc = SYSMEMALLOC + (hasKExt() ? getStolenSystemMemRegionSize() : 0); u32 appmemalloc = OS_KernelConfig->memregion_sz[0];
u32 sysmemalloc = OS_KernelConfig->memregion_sz[1] + (hasKExt() ? getStolenSystemMemRegionSize() : 0);
ReslimitValues *values = !IS_N3DS ? g_o3dsReslimitValues : g_n3dsReslimitValues; ReslimitValues *values = !IS_N3DS ? g_o3dsReslimitValues : g_n3dsReslimitValues;
static const u32 minAppletMemAmount = 0x1200000; static const u32 minAppletMemAmount = 0x1200000;
@@ -261,7 +262,7 @@ static ReslimitValues *fixupReslimitValues(void)
u32 baseRegionSize = !IS_N3DS ? 0x1400000 : 0x2000000; u32 baseRegionSize = !IS_N3DS ? 0x1400000 : 0x2000000;
if (sysmemalloc < minAppletMemAmount) { if (sysmemalloc < minAppletMemAmount) {
values[1][0] = SYSMEMALLOC - minAppletMemAmount / 3; values[1][0] = sysmemalloc - minAppletMemAmount / 3;
values[2][0] = 0; values[2][0] = 0;
values[3][0] = baseRegionSize + otherMinOvercommitAmount; values[3][0] = baseRegionSize + otherMinOvercommitAmount;
} else { } else {
@@ -271,8 +272,8 @@ static ReslimitValues *fixupReslimitValues(void)
values[3][0] = baseRegionSize + (otherMinOvercommitAmount + excess / 4); values[3][0] = baseRegionSize + (otherMinOvercommitAmount + excess / 4);
} }
values[0][0] = APPMEMALLOC; values[0][0] = appmemalloc;
g_defaultAppMemLimit = APPMEMALLOC; g_defaultAppMemLimit = appmemalloc;
return values; return values;
} }

View File

@@ -8,13 +8,7 @@
#define REG32(reg) (*(vu32 *)reg) #define REG32(reg) (*(vu32 *)reg)
#define REG64(reg) (*(vu64 *)reg) #define REG64(reg) (*(vu64 *)reg)
#define NSTID REG64(0x1FF80008) #define IS_N3DS (OS_KernelConfig->app_memtype >= 6) // APPMEMTYPE. Hacky but doesn't use APT
#define SYSCOREVER REG32(0x1FF80010)
#define APPMEMTYPE REG32(0x1FF80030)
#define APPMEMALLOC REG32(0x1FF80040)
#define SYSMEMALLOC REG32(0x1FF80044)
#define IS_N3DS (*(vu32 *)0x1FF80030 >= 6) // APPMEMTYPE. Hacky but doesn't use APT
#define N3DS_TID_MASK 0xF0000000ULL #define N3DS_TID_MASK 0xF0000000ULL
#define N3DS_TID_BIT 0x20000000ULL #define N3DS_TID_BIT 0x20000000ULL

View File

@@ -3,7 +3,7 @@ Open source replacement of the Arm11 PXI system module.
This is licensed under the MIT license. This is licensed under the MIT license.
# Usage # Usage
To run this system module, use a recent release or commit of [Luma3DS](https://github.com/AuroraWright/Luma3DS/) and copy pxi.cxi to /luma/sysmodules/. To run this system module, use a recent release or commit of [Luma3DS](https://github.com/LumaTeam/Luma3DS/) and copy pxi.cxi to /luma/sysmodules/.
# Credits # Credits
This list is not complete at all: This list is not complete at all:

View File

@@ -28,9 +28,8 @@ INCLUDES := include include/gdb include/menus include/redshift
ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard -mtp=soft ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard -mtp=soft
DEFINES := -DARM11 -D_3DS DEFINES := -DARM11 -D_3DS
CFLAGS := -g -std=gnu11 -Wall -Wextra -Werror -Wno-unused-value -Os -mword-relocations \
CFLAGS := -g -std=gnu11 -Wall -Wextra -Wno-unused-value -O2 -mword-relocations \ -fomit-frame-pointer -ffunction-sections -fdata-sections -fno-math-errno \
-fomit-frame-pointer -ffunction-sections -fdata-sections \
$(ARCH) $(DEFINES) $(ARCH) $(DEFINES)
CFLAGS += $(INCLUDE) CFLAGS += $(INCLUDE)

View File

@@ -1,37 +0,0 @@
#pragma once
#include <3ds/types.h>
#include "ifile.h"
#define _3GX_MAGIC (0x3130303024584733) /* "3GX$0001" */
typedef struct PACKED
{
u32 authorLen;
const char * authorMsg;
u32 titleLen;
const char * titleMsg;
u32 summaryLen;
const char * summaryMsg;
u32 descriptionLen;
const char * descriptionMsg;
} _3gx_Infos;
typedef struct PACKED
{
u32 count;
u32 * titles;
} _3gx_Targets;
typedef struct PACKED
{
u64 magic;
u32 version;
u32 codeSize;
u32 * code;
_3gx_Infos infos;
_3gx_Targets targets;
} _3gx_Header;
Result Read_3gx_Header(IFile *file, _3gx_Header *header);
Result Read_3gx_Code(IFile *file, _3gx_Header *header, void *dst);

View File

@@ -71,20 +71,18 @@ void svcInvalidateEntireInstructionCache(void);
///@{ ///@{
/** /**
* @brief Maps a block of process memory. * @brief Maps a block of process memory.
* @param dstProcessHandle Handle of the process to map the memory in (destination) * @param process Handle of the process.
* @param destAddress Address of the mapped block in the current process. * @param destAddress Address of the mapped block in the current process.
* @param srcProcessHandle Handle of the process to map the memory from (source)
* @param srcAddress Address of the mapped block in the source 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). * @param size Size of the block of the memory to map (truncated to a multiple of 0x1000 bytes).
*/ */
Result svcMapProcessMemoryEx(Handle dstProcessHandle, u32 destAddress, Handle srcProcessHandle, u32 vaSrc, u32 size); Result svcMapProcessMemoryEx(Handle process, u32 destAddr, u32 srcAddr, u32 size);
/** /**
* @brief Unmaps a block of process memory. * @brief Unmaps a block of process memory.
* @param process Handle of the process to unmap the memory from * @param process Handle of the process.
* @param destAddress Address of the block of memory to unmap * @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). * @param size Size of the block of memory to unmap (truncated to a multiple of 0x1000 bytes).
* This function should only be used to unmap memory mapped with svcMapProcessMemoryEx
*/ */
Result svcUnmapProcessMemoryEx(Handle process, u32 destAddress, u32 size); Result svcUnmapProcessMemoryEx(Handle process, u32 destAddress, u32 size);
@@ -136,19 +134,4 @@ Result svcCopyHandle(Handle *out, Handle outProcess, Handle in, Handle inProcess
* @param in The input handle. * @param in The input handle.
*/ */
Result svcTranslateHandle(u32 *outKAddr, char *outClassName, Handle in); Result svcTranslateHandle(u32 *outKAddr, char *outClassName, Handle in);
/// Operations for svcControlProcess
typedef enum ProcessOp
{
PROCESSOP_GET_ALL_HANDLES, ///< List all handles of the process, varg3 can be either 0 to fetch all handles, or token of the type to fetch
///< svcControlProcess(handle, PROCESSOP_GET_ALL_HANDLES, (u32)&outBuf, 0)
PROCESSOP_SET_MMU_TO_RWX, ///< Set the whole memory of the process with rwx access
///< svcControlProcess(handle, PROCESSOP_SET_MMU_TO_RWX, 0, 0)
PROCESSOP_GET_ON_MEMORY_CHANGE_EVENT,
PROCESSOP_GET_ON_EXIT_EVENT,
PROCESSOP_GET_PA_FROM_VA, ///< Get the physical address of the va within the process
///< svcControlProcess(handle, PROCESSOP_GET_PA_FROM_VA, (u32)&outPa, va)
} ProcessOp;
Result svcControlProcess(Handle process, ProcessOp op, u32 varg2, u32 varg3);
///@} ///@}

View File

@@ -73,7 +73,6 @@
#define COLOR_WHITE RGB565(0x1F, 0x3F, 0x1F) #define COLOR_WHITE RGB565(0x1F, 0x3F, 0x1F)
#define COLOR_RED RGB565(0x1F, 0x00, 0x00) #define COLOR_RED RGB565(0x1F, 0x00, 0x00)
#define COLOR_GREEN RGB565(0x00, 0x1F, 0x00) #define COLOR_GREEN RGB565(0x00, 0x1F, 0x00)
#define COLOR_LIME RGB565(0x00, 0xFF, 0x00)
#define COLOR_BLACK RGB565(0x00, 0x00, 0x00) #define COLOR_BLACK RGB565(0x00, 0x00, 0x00)
#define DRAW_MAX_FORMATTED_STRING_SIZE 512 #define DRAW_MAX_FORMATTED_STRING_SIZE 512
@@ -91,7 +90,8 @@ u32 Draw_DrawFormattedString(u32 posX, u32 posY, u32 color, const char *fmt, ...
void Draw_FillFramebuffer(u32 value); void Draw_FillFramebuffer(u32 value);
void Draw_ClearFramebuffer(void); void Draw_ClearFramebuffer(void);
u32 Draw_AllocateFramebufferCache(void); Result Draw_AllocateFramebufferCache(u32 size);
Result Draw_AllocateFramebufferCacheForScreenshot(u32 size);
void Draw_FreeFramebufferCache(void); void Draw_FreeFramebufferCache(void);
void *Draw_GetFramebufferCache(void); void *Draw_GetFramebufferCache(void);
u32 Draw_GetFramebufferCacheSize(void); u32 Draw_GetFramebufferCacheSize(void);
@@ -99,6 +99,8 @@ u32 Draw_SetupFramebuffer(void);
void Draw_RestoreFramebuffer(void); void Draw_RestoreFramebuffer(void);
void Draw_FlushFramebuffer(void); void Draw_FlushFramebuffer(void);
u32 Draw_GetCurrentFramebufferAddress(bool top, bool left); u32 Draw_GetCurrentFramebufferAddress(bool top, bool left);
// Width is actually height as the 3ds screen is rotated 90 degrees
void Draw_GetCurrentScreenInfo(u32 *width, bool *is3d, bool top);
void Draw_CreateBitmapHeader(u8 *dst, u32 width, u32 heigth); void Draw_CreateBitmapHeader(u8 *dst, u32 width, u32 heigth);
void Draw_ConvertFrameBufferLines(u8 *buf, u32 startingLine, u32 numLines, bool top, bool left); void Draw_ConvertFrameBufferLines(u8 *buf, u32 width, u32 startingLine, u32 numLines, bool top, bool left);

View File

@@ -12,14 +12,11 @@
#define GDB_REMOTE_COMMAND_HANDLER(name) GDB_HANDLER(RemoteCommand##name) #define GDB_REMOTE_COMMAND_HANDLER(name) GDB_HANDLER(RemoteCommand##name)
#define GDB_DECLARE_REMOTE_COMMAND_HANDLER(name) GDB_DECLARE_HANDLER(RemoteCommand##name) #define GDB_DECLARE_REMOTE_COMMAND_HANDLER(name) GDB_DECLARE_HANDLER(RemoteCommand##name)
GDB_DECLARE_REMOTE_COMMAND_HANDLER(ConvertVAToPA);
GDB_DECLARE_REMOTE_COMMAND_HANDLER(SyncRequestInfo); GDB_DECLARE_REMOTE_COMMAND_HANDLER(SyncRequestInfo);
GDB_DECLARE_REMOTE_COMMAND_HANDLER(TranslateHandle); GDB_DECLARE_REMOTE_COMMAND_HANDLER(TranslateHandle);
GDB_DECLARE_REMOTE_COMMAND_HANDLER(ListAllHandles);
GDB_DECLARE_REMOTE_COMMAND_HANDLER(GetMmuConfig); GDB_DECLARE_REMOTE_COMMAND_HANDLER(GetMmuConfig);
GDB_DECLARE_REMOTE_COMMAND_HANDLER(GetMemRegions); GDB_DECLARE_REMOTE_COMMAND_HANDLER(GetMemRegions);
GDB_DECLARE_REMOTE_COMMAND_HANDLER(FlushCaches); GDB_DECLARE_REMOTE_COMMAND_HANDLER(FlushCaches);
GDB_DECLARE_REMOTE_COMMAND_HANDLER(ToggleExternalMemoryAccess); GDB_DECLARE_REMOTE_COMMAND_HANDLER(ToggleExternalMemoryAccess);
GDB_DECLARE_REMOTE_COMMAND_HANDLER(CatchSvc);
GDB_DECLARE_QUERY_HANDLER(Rcmd); GDB_DECLARE_QUERY_HANDLER(Rcmd);

View File

@@ -31,7 +31,6 @@
#include "MyThread.h" #include "MyThread.h"
#define HBLDR_DEFAULT_3DSX_TID 0x000400000D921E00ULL #define HBLDR_DEFAULT_3DSX_TID 0x000400000D921E00ULL
#define HBLDR_3DSX_TID (*(vu64 *)0x1FF81100)
void HBLDR_RestartHbApplication(void *p); void HBLDR_RestartHbApplication(void *p);
void HBLDR_HandleCommands(void *ctx); void HBLDR_HandleCommands(void *ctx);

View File

@@ -0,0 +1,30 @@
/* 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>
#include <3ds/types.h>
/// Luma shared config type.
typedef struct LumaSharedConfig {
u64 hbldr_3dsx_tid; ///< Title ID to use for 3DSX loading.
bool use_hbldr; ///< Whether or not Loader should use hb:ldr (Rosalina writes 1).
} LumaSharedConfig;
/// Luma shared config.
#define Luma_SharedConfig ((volatile LumaSharedConfig *)(OS_SHAREDCFG_VADDR + 0x800))

View File

@@ -1,6 +1,6 @@
/* /*
* This file is part of Luma3DS * This file is part of Luma3DS
* Copyright (C) 2016-2018 Aurora Wright, TuxSH * Copyright (C) 2016-2020 Aurora Wright, TuxSH
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@@ -26,6 +26,8 @@
#pragma once #pragma once
void Sleep__Init(void); #include <3ds/types.h>
void Sleep__HandleNotification(u32 notifId);
bool Sleep__Status(void); u32 getMinLuminancePreset(void);
u32 getMaxLuminancePreset(void);
u32 getCurrentLuminance(bool top);

View File

@@ -30,8 +30,6 @@
#include <string.h> #include <string.h>
u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSize); u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSize);
void *memset32(void *dest, u32 value, u32 size);
void hexItoa(u64 number, char *out, u32 digits, bool uppercase); 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); unsigned long int xstrtoul(const char *nptr, char **endptr, int base, bool allowPrefix, bool *ok);
unsigned long long int xstrtoull(const char *nptr, char **endptr, int base, bool allowPrefix, bool *ok); unsigned long long int xstrtoull(const char *nptr, char **endptr, int base, bool allowPrefix, bool *ok);

View File

@@ -81,10 +81,7 @@ bool menuCheckN3ds(void);
u32 menuCountItems(const Menu *menu); u32 menuCountItems(const Menu *menu);
MyThread *menuCreateThread(void); MyThread *menuCreateThread(void);
void menuEnter(void); void menuEnter(void);
void menuLeave(void); void menuLeave(void);
void menuThreadMain(void); void menuThreadMain(void);
void menuShow(Menu *root); void menuShow(Menu *root);
void DispMessage(const char *title, const char *message);
u32 DispErrMessage(const char *title, const char *message, const Result error);
void DisplayPluginMenu(u32 *cmdbuf);

View File

@@ -32,10 +32,16 @@ extern Menu screenFiltersMenu;
extern int screenFiltersCurrentTemperature; extern int screenFiltersCurrentTemperature;
void screenFiltersSetDisabled(void); void ScreenFiltersMenu_RestoreCct(void);
void screenFiltersReduceBlueLevel1(void);
void screenFiltersReduceBlueLevel2(void); void ScreenFiltersMenu_SetDefault(void); // 6500K (default)
void screenFiltersReduceBlueLevel3(void);
void screenFiltersReduceBlueLevel4(void); void ScreenFiltersMenu_SetAquarium(void); // 10000K
void screenFiltersReduceBlueLevel5(void); void ScreenFiltersMenu_SetOvercastSky(void); // 7500K
void screenFiltersSetTemperature(int temperature); void ScreenFiltersMenu_SetDaylight(void); // 5500K
void ScreenFiltersMenu_SetFluorescent(void); // 4200K
void ScreenFiltersMenu_SetHalogen(void); // 3400K
void ScreenFiltersMenu_SetIncandescent(void); // 2700K
void ScreenFiltersMenu_SetWarmIncandescent(void); // 2300K
void ScreenFiltersMenu_SetCandle(void); // 1900K
void ScreenFiltersMenu_SetEmber(void); // 1200K

View File

@@ -21,6 +21,10 @@
extern bool miniSocEnabled; extern bool miniSocEnabled;
Result miniSocInit(void); Result miniSocInit(void);
void miniSocLockState(void);
void miniSocUnlockState(bool force);
Result miniSocExitDirect(void); Result miniSocExitDirect(void);
Result miniSocExit(void); Result miniSocExit(void);

View File

@@ -1,32 +0,0 @@
#pragma once
#include <3ds/types.h>
#define MAX_BUFFER (50)
#define MAX_ITEMS_COUNT (64)
typedef struct
{
bool noFlash;
u32 lowTitleId;
char path[256];
u32 config[32];
} PluginLoadParameters;
typedef struct
{
u32 nbItems;
u8 states[MAX_ITEMS_COUNT];
char title[MAX_BUFFER];
char items[MAX_ITEMS_COUNT][MAX_BUFFER];
char hints[MAX_ITEMS_COUNT][MAX_BUFFER];
} PluginMenu;
Result plgLdrInit(void);
void plgLdrExit(void);
Result PLGLDR__IsPluginLoaderEnabled(bool *isEnabled);
Result PLGLDR__SetPluginLoaderState(bool enabled);
Result PLGLDR__SetPluginLoadParameters(PluginLoadParameters *parameters);
Result PLGLDR__DisplayMenu(PluginMenu *menu);
Result PLGLDR__DisplayMessage(const char *title, const char *body);
Result PLGLDR__DisplayErrMessage(const char *title, const char *body, u32 error);

View File

@@ -1,9 +0,0 @@
#pragma once
#include <3ds/types.h>
#include "MyThread.h"
MyThread * PluginLoader__CreateThread(void);
bool PluginLoader__IsEnabled(void);
void PluginLoader__MenuCallback(void);
void PluginLoader__UpdateMenu(void);

View File

@@ -77,4 +77,3 @@ void server_run(struct sock_server *serv);
void server_kill_connections(struct sock_server *serv); void server_kill_connections(struct sock_server *serv);
void server_set_should_close_all(struct sock_server *serv); void server_set_should_close_all(struct sock_server *serv);
void server_finalize(struct sock_server *serv); void server_finalize(struct sock_server *serv);
bool Wifi__IsConnected(void);

View File

@@ -29,8 +29,8 @@
#include <3ds/svc.h> #include <3ds/svc.h>
#include <3ds/srv.h> #include <3ds/srv.h>
#include <3ds/result.h> #include <3ds/result.h>
#include <3ds/ipc.h>
#include "csvc.h" #include "csvc.h"
#include "luma_shared_config.h"
// For accessing physmem uncached (and directly) // For accessing physmem uncached (and directly)
#define PA_PTR(addr) (void *)((u32)(addr) | 1 << 31) #define PA_PTR(addr) (void *)((u32)(addr) | 1 << 31)
@@ -58,22 +58,6 @@ static inline void *decodeArmBranch(const void *src)
return (void *)((const u8 *)src + 8 + off); return (void *)((const u8 *)src + 8 + off);
} }
static inline void assertSuccess(Result res)
{
if(R_FAILED(res))
svcBreak(USERBREAK_PANIC);
}
static inline void error(u32* cmdbuf, Result rc)
{
cmdbuf[0] = IPC_MakeHeader(0, 1, 0);
cmdbuf[1] = rc;
}
extern bool isN3DS;
Result OpenProcessByName(const char *name, Handle *h);
Result SaveSettings(void);
static inline bool isServiceUsable(const char *name) static inline bool isServiceUsable(const char *name)
{ {
bool r; bool r;

View File

@@ -1,62 +0,0 @@
#include <3ds.h>
#include "3gx.h"
Result Read_3gx_Header(IFile *file, _3gx_Header *header)
{
u64 total;
char * dst;
Result res = 0;
res = IFile_Read(file, &total, header, sizeof(_3gx_Header));
if (R_FAILED(res))
return res;
// Read author
file->pos = (u32)header->infos.authorMsg;
dst = (char *)header + sizeof(_3gx_Header);
res = IFile_Read(file, &total, dst, header->infos.authorLen);
if (R_FAILED(res))
return res;
// Relocate ptr
header->infos.authorMsg = dst;
// Read title
file->pos = (u32)header->infos.titleMsg;
dst += header->infos.authorLen;
res = IFile_Read(file, &total, dst, header->infos.titleLen);
if (R_FAILED(res))
return res;
// Relocate ptr
header->infos.titleMsg = dst;
// Declare other members as null (unused in our case)
header->infos.summaryLen = 0;
header->infos.summaryMsg = NULL;
header->infos.descriptionLen = 0;
header->infos.descriptionMsg = NULL;
// Read targets compatibility
file->pos = (u32)header->targets.titles;
dst += header->infos.titleLen;
dst += 4 - ((u32)dst & 3); // 4 bytes aligned
res = IFile_Read(file, &total, dst, header->targets.count * sizeof(u32));
if (R_FAILED(res))
return res;
// Relocate ptr
header->targets.titles = (u32 *)dst;
return res;
}
Result Read_3gx_Code(IFile *file, _3gx_Header *header, void *dst)
{
u64 total;
Result res = 0;
file->pos = (u32)header->code;
res = IFile_Read(file, &total, dst, header->codeSize);
return res;
}

View File

@@ -59,10 +59,7 @@ SVC_BEGIN svcInvalidateEntireInstructionCache
SVC_END SVC_END
SVC_BEGIN svcMapProcessMemoryEx SVC_BEGIN svcMapProcessMemoryEx
str r4, [sp, #-4]!
ldr r4, [sp, #4]
svc 0xA0 svc 0xA0
ldr r4, [sp], #4
bx lr bx lr
SVC_END SVC_END
@@ -102,8 +99,3 @@ SVC_BEGIN svcTranslateHandle
str r1, [r2] str r1, [r2]
bx lr bx lr
SVC_END SVC_END
SVC_BEGIN svcControlProcess
svc 0xB3
bx lr
SVC_END

View File

@@ -129,18 +129,19 @@ void Draw_ClearFramebuffer(void)
Draw_FillFramebuffer(0); Draw_FillFramebuffer(0);
} }
u32 Draw_AllocateFramebufferCache(void) Result Draw_AllocateFramebufferCache(u32 size)
{ {
// Try to see how much we can allocate...
// Can't use fbs in FCRAM when Home Menu is active (AXI config related maybe?) // Can't use fbs in FCRAM when Home Menu is active (AXI config related maybe?)
u32 addr = 0x0D000000; u32 addr = 0x0D000000;
u32 tmp; u32 tmp;
u32 minSize = (FB_BOTTOM_SIZE + 0xFFF) & ~0xFFF;
u32 maxSize = (FB_SCREENSHOT_SIZE + 0xFFF) & ~0xFFF;
u32 remaining = (u32)osGetMemRegionFree(MEMREGION_SYSTEM);
u32 size = remaining < maxSize ? remaining : maxSize;
if (size < minSize || R_FAILED(svcControlMemoryEx(&tmp, addr, 0, size, MEMOP_ALLOC, MEMREGION_SYSTEM | MEMPERM_READ | MEMPERM_WRITE, true))) size = (size + 0xFFF) >> 12 << 12; // round-up
if (framebufferCache != NULL)
__builtin_trap();
Result res = svcControlMemoryEx(&tmp, addr, 0, size, MEMOP_ALLOC, MEMREGION_SYSTEM | MEMPERM_READWRITE, true);
if (R_FAILED(res))
{ {
framebufferCache = NULL; framebufferCache = NULL;
framebufferCacheSize = 0; framebufferCacheSize = 0;
@@ -151,13 +152,21 @@ u32 Draw_AllocateFramebufferCache(void)
framebufferCacheSize = size; framebufferCacheSize = size;
} }
return framebufferCacheSize; return res;
}
Result Draw_AllocateFramebufferCacheForScreenshot(u32 size)
{
u32 remaining = (u32)osGetMemRegionFree(MEMREGION_SYSTEM);
u32 sz = remaining < size ? remaining : size;
return Draw_AllocateFramebufferCache(sz);
} }
void Draw_FreeFramebufferCache(void) void Draw_FreeFramebufferCache(void)
{ {
u32 tmp; u32 tmp;
svcControlMemory(&tmp, (u32)framebufferCache, 0, framebufferCacheSize, MEMOP_FREE, 0); if (framebufferCache != NULL)
svcControlMemory(&tmp, (u32)framebufferCache, 0, framebufferCacheSize, MEMOP_FREE, 0);
framebufferCacheSize = 0; framebufferCacheSize = 0;
framebufferCache = NULL; framebufferCache = NULL;
} }
@@ -180,13 +189,19 @@ u32 Draw_SetupFramebuffer(void)
memcpy(framebufferCache, FB_BOTTOM_VRAM_ADDR, FB_BOTTOM_SIZE); memcpy(framebufferCache, FB_BOTTOM_VRAM_ADDR, FB_BOTTOM_SIZE);
Draw_ClearFramebuffer(); Draw_ClearFramebuffer();
Draw_FlushFramebuffer(); Draw_FlushFramebuffer();
u32 format = GPU_FB_BOTTOM_FMT;
gpuSavedFramebufferAddr1 = GPU_FB_BOTTOM_ADDR_1; gpuSavedFramebufferAddr1 = GPU_FB_BOTTOM_ADDR_1;
gpuSavedFramebufferAddr2 = GPU_FB_BOTTOM_ADDR_2; gpuSavedFramebufferAddr2 = GPU_FB_BOTTOM_ADDR_2;
gpuSavedFramebufferFormat = GPU_FB_BOTTOM_FMT; gpuSavedFramebufferFormat = format;
gpuSavedFramebufferStride = GPU_FB_BOTTOM_STRIDE; gpuSavedFramebufferStride = GPU_FB_BOTTOM_STRIDE;
format = (format & ~7) | GSP_RGB565_OES;
format |= 3 << 8; // set VRAM bits
GPU_FB_BOTTOM_ADDR_1 = GPU_FB_BOTTOM_ADDR_2 = FB_BOTTOM_VRAM_PA; GPU_FB_BOTTOM_ADDR_1 = GPU_FB_BOTTOM_ADDR_2 = FB_BOTTOM_VRAM_PA;
GPU_FB_BOTTOM_FMT = (GPU_FB_BOTTOM_FMT & ~7) | GSP_RGB565_OES; GPU_FB_BOTTOM_FMT = format;
GPU_FB_BOTTOM_STRIDE = 240 * 2; GPU_FB_BOTTOM_STRIDE = 240 * 2;
return framebufferCacheSize; return framebufferCacheSize;
@@ -205,7 +220,7 @@ void Draw_RestoreFramebuffer(void)
void Draw_FlushFramebuffer(void) void Draw_FlushFramebuffer(void)
{ {
svcFlushProcessDataCache(CUR_PROCESS_HANDLE, FB_BOTTOM_VRAM_ADDR, FB_BOTTOM_SIZE); svcFlushProcessDataCache(CUR_PROCESS_HANDLE, (u32)FB_BOTTOM_VRAM_ADDR, FB_BOTTOM_SIZE);
} }
u32 Draw_GetCurrentFramebufferAddress(bool top, bool left) u32 Draw_GetCurrentFramebufferAddress(bool top, bool left)
@@ -226,6 +241,21 @@ u32 Draw_GetCurrentFramebufferAddress(bool top, bool left)
} }
} }
void Draw_GetCurrentScreenInfo(u32 *width, bool *is3d, bool top)
{
if (top)
{
bool isNormal2d = (GPU_FB_TOP_FMT & BIT(6)) != 0;
*is3d = (GPU_FB_TOP_FMT & BIT(5)) != 0;
*width = !(*is3d) && !isNormal2d ? 800 : 400;
}
else
{
*is3d = false;
*width = 320;
}
}
static inline void Draw_WriteUnaligned(u8 *dst, u32 tmp, u32 size) static inline void Draw_WriteUnaligned(u8 *dst, u32 tmp, u32 size)
{ {
memcpy(dst, &tmp, size); memcpy(dst, &tmp, size);
@@ -247,7 +277,7 @@ void Draw_CreateBitmapHeader(u8 *dst, u32 width, u32 heigth)
Draw_WriteUnaligned(dst + 0x22, 3 * width * heigth, 4); Draw_WriteUnaligned(dst + 0x22, 3 * width * heigth, 4);
} }
static inline void Draw_ConvertPixelToBGR8(u8 *dst, const u8 *src, GSPGPU_FramebufferFormats srcFormat) static inline void Draw_ConvertPixelToBGR8(u8 *dst, const u8 *src, GSPGPU_FramebufferFormat srcFormat)
{ {
u8 red, green, blue; u8 red, green, blue;
switch(srcFormat) switch(srcFormat)
@@ -313,6 +343,7 @@ static inline void Draw_ConvertPixelToBGR8(u8 *dst, const u8 *src, GSPGPU_Frameb
typedef struct FrameBufferConvertArgs { typedef struct FrameBufferConvertArgs {
u8 *buf; u8 *buf;
u32 width;
u8 startingLine; u8 startingLine;
u8 numLines; u8 numLines;
bool top; bool top;
@@ -323,8 +354,8 @@ static void Draw_ConvertFrameBufferLinesKernel(const FrameBufferConvertArgs *arg
{ {
static const u8 formatSizes[] = { 4, 3, 2, 2, 2 }; static const u8 formatSizes[] = { 4, 3, 2, 2, 2 };
GSPGPU_FramebufferFormats fmt = args->top ? (GSPGPU_FramebufferFormats)(GPU_FB_TOP_FMT & 7) : (GSPGPU_FramebufferFormats)(GPU_FB_BOTTOM_FMT & 7); GSPGPU_FramebufferFormat fmt = args->top ? (GSPGPU_FramebufferFormat)(GPU_FB_TOP_FMT & 7) : (GSPGPU_FramebufferFormat)(GPU_FB_BOTTOM_FMT & 7);
u32 width = args->top ? 400 : 320; u32 width = args->width;
u32 stride = args->top ? GPU_FB_TOP_STRIDE : GPU_FB_BOTTOM_STRIDE; u32 stride = args->top ? GPU_FB_TOP_STRIDE : GPU_FB_BOTTOM_STRIDE;
u32 pa = Draw_GetCurrentFramebufferAddress(args->top, args->left); u32 pa = Draw_GetCurrentFramebufferAddress(args->top, args->left);
@@ -340,8 +371,8 @@ static void Draw_ConvertFrameBufferLinesKernel(const FrameBufferConvertArgs *arg
} }
} }
void Draw_ConvertFrameBufferLines(u8 *buf, u32 startingLine, u32 numLines, bool top, bool left) void Draw_ConvertFrameBufferLines(u8 *buf, u32 width, u32 startingLine, u32 numLines, bool top, bool left)
{ {
FrameBufferConvertArgs args = { buf, (u8)startingLine, (u8)numLines, top, left }; FrameBufferConvertArgs args = { buf, width, (u8)startingLine, (u8)numLines, top, left };
svcCustomBackdoor(Draw_ConvertFrameBufferLinesKernel, &args); svcCustomBackdoor(Draw_ConvertFrameBufferLinesKernel, &args);
} }

View File

@@ -33,6 +33,13 @@
#include "ifile.h" #include "ifile.h"
extern Handle preTerminationEvent; extern Handle preTerminationEvent;
static inline void assertSuccess(Result res)
{
if(R_FAILED(res))
svcBreak(USERBREAK_PANIC);
}
static MyThread errDispThread; static MyThread errDispThread;
static u8 ALIGN(8) errDispThreadStack[0xD00]; static u8 ALIGN(8) errDispThreadStack[0xD00];

View File

@@ -10,7 +10,6 @@
#include "csvc.h" #include "csvc.h"
#include "fmt.h" #include "fmt.h"
#include "gdb/breakpoints.h" #include "gdb/breakpoints.h"
#include "utils.h"
#include "../utils.h" #include "../utils.h"
@@ -20,15 +19,12 @@ struct
GDBCommandHandler handler; GDBCommandHandler handler;
} remoteCommandHandlers[] = } remoteCommandHandlers[] =
{ {
{ "convertvatopa" , GDB_REMOTE_COMMAND_HANDLER(ConvertVAToPA) },
{ "syncrequestinfo" , GDB_REMOTE_COMMAND_HANDLER(SyncRequestInfo) }, { "syncrequestinfo" , GDB_REMOTE_COMMAND_HANDLER(SyncRequestInfo) },
{ "translatehandle" , GDB_REMOTE_COMMAND_HANDLER(TranslateHandle) }, { "translatehandle" , GDB_REMOTE_COMMAND_HANDLER(TranslateHandle) },
{ "listallhandles" , GDB_REMOTE_COMMAND_HANDLER(ListAllHandles) },
{ "getmmuconfig" , GDB_REMOTE_COMMAND_HANDLER(GetMmuConfig) }, { "getmmuconfig" , GDB_REMOTE_COMMAND_HANDLER(GetMmuConfig) },
{ "getmemregions" , GDB_REMOTE_COMMAND_HANDLER(GetMemRegions) }, { "getmemregions" , GDB_REMOTE_COMMAND_HANDLER(GetMemRegions) },
{ "flushcaches" , GDB_REMOTE_COMMAND_HANDLER(FlushCaches) }, { "flushcaches" , GDB_REMOTE_COMMAND_HANDLER(FlushCaches) },
{ "toggleextmemaccess", GDB_REMOTE_COMMAND_HANDLER(ToggleExternalMemoryAccess) }, { "toggleextmemaccess", GDB_REMOTE_COMMAND_HANDLER(ToggleExternalMemoryAccess) },
{ "catchsvc" , GDB_REMOTE_COMMAND_HANDLER(CatchSvc) },
}; };
static const char *GDB_SkipSpaces(const char *pos) static const char *GDB_SkipSpaces(const char *pos)
@@ -38,50 +34,6 @@ static const char *GDB_SkipSpaces(const char *pos)
return nextpos; return nextpos;
} }
GDB_DECLARE_REMOTE_COMMAND_HANDLER(ConvertVAToPA)
{
bool ok;
int n;
u32 val;
u32 pa;
char * end;
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);
if (val >= 0x40000000)
pa = svcConvertVAToPA((const void *)val, false);
else
{
Handle process;
Result r = svcOpenProcess(&process, ctx->pid);
if(R_FAILED(r))
{
n = sprintf(outbuf, "Invalid process (wtf?)\n");
goto end;
}
r = svcControlProcess(process, PROCESSOP_GET_PA_FROM_VA, (u32)&pa, val);
svcCloseHandle(process);
if (R_FAILED(r))
{
n = sprintf(outbuf, "An error occured: %08X\n", r);
goto end;
}
}
n = sprintf(outbuf, "va: 0x%08X, pa: 0x%08X, b31: 0x%08X\n", val, pa, pa | (1 << 31));
end:
return GDB_SendHexPacket(ctx, outbuf, n);
}
GDB_DECLARE_REMOTE_COMMAND_HANDLER(SyncRequestInfo) GDB_DECLARE_REMOTE_COMMAND_HANDLER(SyncRequestInfo)
{ {
char outbuf[GDB_BUF_LEN / 2 + 1]; char outbuf[GDB_BUF_LEN / 2 + 1];
@@ -166,29 +118,6 @@ end:
return GDB_SendHexPacket(ctx, outbuf, n); return GDB_SendHexPacket(ctx, outbuf, n);
} }
enum
{
TOKEN_KAUTOOBJECT = 0,
TOKEN_KSYNCHRONIZATIONOBJECT = 1,
TOKEN_KEVENT = 0x1F,
TOKEN_KSEMAPHORE = 0x2F,
TOKEN_KTIMER = 0x35,
TOKEN_KMUTEX = 0x39,
TOKEN_KDEBUG = 0x4D,
TOKEN_KSERVERPORT = 0x55,
TOKEN_KDMAOBJECT = 0x59,
TOKEN_KCLIENTPORT = 0x65,
TOKEN_KCODESET = 0x68,
TOKEN_KSESSION = 0x70,
TOKEN_KTHREAD = 0x8D,
TOKEN_KSERVERSESSION = 0x95,
TOKEN_KCLIENTSESSION = 0xA5,
TOKEN_KPORT = 0xA8,
TOKEN_KSHAREDMEMORY = 0xB0,
TOKEN_KPROCESS = 0xC5,
TOKEN_KRESOURCELIMIT = 0xC8
};
GDB_DECLARE_REMOTE_COMMAND_HANDLER(TranslateHandle) GDB_DECLARE_REMOTE_COMMAND_HANDLER(TranslateHandle)
{ {
bool ok; bool ok;
@@ -197,11 +126,10 @@ GDB_DECLARE_REMOTE_COMMAND_HANDLER(TranslateHandle)
int n; int n;
Result r; Result r;
u32 kernelAddr; u32 kernelAddr;
s64 token;
Handle handle, process; Handle handle, process;
s64 refcountRaw; s64 refcountRaw;
u32 refcount; u32 refcount;
char classBuf[32], serviceBuf[12] = { 0 }, ownerBuf[50] = { 0 }; char classBuf[32], serviceBuf[12] = { 0 };
char outbuf[GDB_BUF_LEN / 2 + 1]; char outbuf[GDB_BUF_LEN / 2 + 1];
if(ctx->commandData[0] == 0) if(ctx->commandData[0] == 0)
@@ -233,28 +161,12 @@ GDB_DECLARE_REMOTE_COMMAND_HANDLER(TranslateHandle)
svcTranslateHandle(&kernelAddr, classBuf, handle); svcTranslateHandle(&kernelAddr, classBuf, handle);
svcGetHandleInfo(&refcountRaw, handle, 1); svcGetHandleInfo(&refcountRaw, handle, 1);
svcGetHandleInfo(&token, handle, 0x10001);
svcControlService(SERVICEOP_GET_NAME, serviceBuf, handle); svcControlService(SERVICEOP_GET_NAME, serviceBuf, handle);
refcount = (u32)(refcountRaw - 1); refcount = (u32)(refcountRaw - 1);
if(serviceBuf[0] != 0) if(serviceBuf[0] != 0)
n = sprintf(outbuf, "(%s *)0x%08lx /* %s handle, %lu %s */\n", classBuf, kernelAddr, serviceBuf, refcount, refcount == 1 ? "reference" : "references"); n = sprintf(outbuf, "(%s *)0x%08lx /* %s handle, %lu %s */\n", classBuf, kernelAddr, serviceBuf, refcount, refcount == 1 ? "reference" : "references");
else if (token == TOKEN_KPROCESS)
{
svcGetProcessInfo((s64 *)serviceBuf, handle, 0x10000);
n = sprintf(outbuf, "(%s *)0x%08x /* process: %s, %u %s */\n", classBuf, kernelAddr, serviceBuf, refcount, refcount == 1 ? "reference" : "references");
}
else else
{ n = sprintf(outbuf, "(%s *)0x%08lx /* %lu %s */\n", classBuf, kernelAddr, refcount, refcount == 1 ? "reference" : "references");
s64 owner;
if (R_SUCCEEDED(svcGetHandleInfo(&owner, handle, 0x10002)))
{
svcGetProcessInfo((s64 *)serviceBuf, (u32)owner, 0x10000);
svcCloseHandle((u32)owner);
sprintf(ownerBuf, " owner: %s", serviceBuf);
}
n = sprintf(outbuf, "(%s *)0x%08x /* %u %s%s */\n", classBuf, kernelAddr, refcount, refcount == 1 ? "reference" : "references", ownerBuf);
}
end: end:
svcCloseHandle(handle); svcCloseHandle(handle);
@@ -262,69 +174,6 @@ end:
return GDB_SendHexPacket(ctx, outbuf, n); return GDB_SendHexPacket(ctx, outbuf, n);
} }
GDB_DECLARE_REMOTE_COMMAND_HANDLER(ListAllHandles)
{
bool ok;
u32 val;
char *end;
int n = 0;
Result r;
s32 count = 0;
Handle process, procHandles[0x100];
char outbuf[GDB_BUF_LEN / 2 + 1];
if(ctx->commandData[0] == 0)
val = 0; ///< All handles
else
{ // Get handles of specified type
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;
}
if (R_FAILED(count = svcControlProcess(process, PROCESSOP_GET_ALL_HANDLES, (u32)procHandles, val)))
n = sprintf(outbuf, "An error occured: %08X\n", count);
else if (count == 0)
n = sprintf(outbuf, "Process has no handles ?\n");
else
{
n = sprintf(outbuf, "Found %d handles.\n", count);
const char *comma = "";
for (s32 i = 0; i < count && n < (GDB_BUF_LEN >> 1) - 20; ++i)
{
Handle handle = procHandles[i];
n += sprintf(outbuf + n, "%s0x%08X", comma, handle);
if (((i + 1) % 8) == 0)
{
outbuf[n++] = '\n';
comma = "";
}
else
comma = ", ";
}
}
end:
svcCloseHandle(process);
return GDB_SendHexPacket(ctx, outbuf, n);
}
extern bool isN3DS; extern bool isN3DS;
GDB_DECLARE_REMOTE_COMMAND_HANDLER(GetMmuConfig) GDB_DECLARE_REMOTE_COMMAND_HANDLER(GetMmuConfig)
{ {
@@ -400,41 +249,6 @@ GDB_DECLARE_REMOTE_COMMAND_HANDLER(ToggleExternalMemoryAccess)
return GDB_SendHexPacket(ctx, outbuf, n); return GDB_SendHexPacket(ctx, outbuf, n);
} }
GDB_DECLARE_REMOTE_COMMAND_HANDLER(CatchSvc)
{
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);
}
GDB_DECLARE_QUERY_HANDLER(Rcmd) GDB_DECLARE_QUERY_HANDLER(Rcmd)
{ {
char commandData[GDB_BUF_LEN / 2 + 1]; char commandData[GDB_BUF_LEN / 2 + 1];

View File

@@ -36,9 +36,6 @@
#include "gdb/server.h" #include "gdb/server.h"
#include "pmdbgext.h" #include "pmdbgext.h"
#define SYSCOREVER (*(vu32 *)0x1FF80010)
#define APPMEMTYPE (*(vu32 *)0x1FF80030)
extern GDBContext *nextApplicationGdbCtx; extern GDBContext *nextApplicationGdbCtx;
extern GDBServer gdbServer; extern GDBServer gdbServer;
@@ -148,12 +145,24 @@ static const u32 kernelCaps[] =
0xFF81FF78, // RW static mapping: 0x1FF78000 0xFF81FF78, // RW static mapping: 0x1FF78000
0xFF91F000, // RO static mapping: 0x1F000000 0xFF91F000, // RO static mapping: 0x1F000000
0xFF91F600, // RO static mapping: 0x1F600000 0xFF91F600, // RO static mapping: 0x1F600000
0xFF002101, // Exflags: APPLICATION memtype + "Allow debug" + "Access core2" 0xFF002109, // Exflags: APPLICATION memtype + "Shared page writing" + "Allow debug" + "Access core2"
0xFE000200, // Handle table size: 0x200 0xFE000200, // Handle table size: 0x200
}; };
static inline void assertSuccess(Result res)
{
if(R_FAILED(res))
svcBreak(USERBREAK_PANIC);
}
static u16 hbldrTarget[PATH_MAX+1]; static u16 hbldrTarget[PATH_MAX+1];
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) static u16 *u16_strncpy(u16 *dest, const u16 *src, u32 size)
{ {
u32 i; u32 i;
@@ -310,21 +319,22 @@ void HBLDR_HandleCommands(void *ctx)
memcpy(&exhi->sci.codeset_info.stack_size, &stacksize, 4); memcpy(&exhi->sci.codeset_info.stack_size, &stacksize, 4);
memset(&exhi->sci.dependencies, 0, sizeof(exhi->sci.dependencies)); memset(&exhi->sci.dependencies, 0, sizeof(exhi->sci.dependencies));
if (SYSCOREVER == 2) u32 coreVer = OS_KernelConfig->kernel_syscore_ver;
if (coreVer == 2)
memcpy(exhi->sci.dependencies, dependencyListNativeFirm, sizeof(dependencyListNativeFirm)); memcpy(exhi->sci.dependencies, dependencyListNativeFirm, sizeof(dependencyListNativeFirm));
else if (SYSCOREVER == 3) else if (coreVer == 3)
memcpy(exhi->sci.dependencies, dependencyListSafeFirm, sizeof(dependencyListSafeFirm)); memcpy(exhi->sci.dependencies, dependencyListSafeFirm, sizeof(dependencyListSafeFirm));
ExHeader_Arm11SystemLocalCapabilities* localcaps0 = &exhi->aci.local_caps; ExHeader_Arm11SystemLocalCapabilities* localcaps0 = &exhi->aci.local_caps;
localcaps0->core_info.core_version = SYSCOREVER; localcaps0->core_info.core_version = coreVer;
localcaps0->core_info.use_cpu_clockrate_804MHz = false; localcaps0->core_info.use_cpu_clockrate_804MHz = false;
localcaps0->core_info.enable_l2c = false; localcaps0->core_info.enable_l2c = false;
localcaps0->core_info.ideal_processor = 0; localcaps0->core_info.ideal_processor = 0;
localcaps0->core_info.affinity_mask = BIT(0); localcaps0->core_info.affinity_mask = BIT(0);
localcaps0->core_info.priority = 0x30; localcaps0->core_info.priority = 0x30;
u32 appmemtype = APPMEMTYPE; u32 appmemtype = OS_KernelConfig->app_memtype;
localcaps0->core_info.o3ds_system_mode = appmemtype < 6 ? (SystemMode)appmemtype : SYSMODE_O3DS_PROD; localcaps0->core_info.o3ds_system_mode = appmemtype < 6 ? (SystemMode)appmemtype : SYSMODE_O3DS_PROD;
localcaps0->core_info.n3ds_system_mode = appmemtype >= 6 ? (SystemMode)(appmemtype - 6 + 1) : SYSMODE_N3DS_PROD; localcaps0->core_info.n3ds_system_mode = appmemtype >= 6 ? (SystemMode)(appmemtype - 6 + 1) : SYSMODE_N3DS_PROD;
@@ -334,7 +344,7 @@ void HBLDR_HandleCommands(void *ctx)
// See the big comment in sysmodules/pm/source/reslimit.c for technical details. // See the big comment in sysmodules/pm/source/reslimit.c for technical details.
localcaps0->reslimits[0] = BIT(7) | 89; localcaps0->reslimits[0] = BIT(7) | 89;
//localcaps0->storage_info.fs_access_info = 0xFFFFFFFF; // Give access to everything localcaps0->storage_info.fs_access_info = 0xFFFFFFFF; // Give access to everything
localcaps0->storage_info.no_romfs = true; localcaps0->storage_info.no_romfs = true;
localcaps0->storage_info.use_extended_savedata_access = true; // Whatever localcaps0->storage_info.use_extended_savedata_access = true; // Whatever
@@ -351,7 +361,7 @@ void HBLDR_HandleCommands(void *ctx)
// Set kernel release version to the current kernel version // Set kernel release version to the current kernel version
kcaps0->descriptors[0] = 0xFC000000 | (osGetKernelVersion() >> 16); kcaps0->descriptors[0] = 0xFC000000 | (osGetKernelVersion() >> 16);
if (GET_VERSION_MINOR(osGetKernelVersion()) >= 50 && SYSCOREVER == 2) // 9.6+ NFIRM if (GET_VERSION_MINOR(osGetKernelVersion()) >= 50 && coreVer == 2) // 9.6+ NFIRM
{ {
u64 lastdep = sizeof(dependencyListNativeFirm)/8; u64 lastdep = sizeof(dependencyListNativeFirm)/8;
exhi->sci.dependencies[lastdep++] = 0x0004013000004002ULL; // nfc exhi->sci.dependencies[lastdep++] = 0x0004013000004002ULL; // nfc

View File

@@ -32,8 +32,6 @@
#include "process_patches.h" #include "process_patches.h"
#include "menus.h" #include "menus.h"
#include "memory.h" #include "memory.h"
#include "sleep.h"
#include "sock_util.h"
bool inputRedirectionEnabled = false; bool inputRedirectionEnabled = false;
Handle inputRedirectionThreadStartedEvent; Handle inputRedirectionThreadStartedEvent;
@@ -123,13 +121,6 @@ void inputRedirectionThreadMain(void)
pfd.events = POLLIN; pfd.events = POLLIN;
pfd.revents = 0; pfd.revents = 0;
if (Sleep__Status())
{
while (!Wifi__IsConnected()
&& inputRedirectionEnabled && !preTerminationRequested)
svcSleepThread(1000000000ULL);
}
int pollres = socPoll(&pfd, 1, 10); int pollres = socPoll(&pfd, 1, 10);
if(pollres > 0 && (pfd.revents & POLLIN)) if(pollres > 0 && (pfd.revents & POLLIN))
{ {
@@ -177,6 +168,246 @@ void inputRedirectionThreadMain(void)
void hidCodePatchFunc(void); void hidCodePatchFunc(void);
void irCodePatchFunc(void); void irCodePatchFunc(void);
static Result InputRedirection_DoUndoIrPatches(Handle processHandle, bool doPatch)
{
static u32* hookLoc = NULL;
static u32* syncLoc = NULL;
static u32* cppFlagLoc = NULL;
static u32 origIrSync = 0;
static u32 origCppFlag = 0;
static bool patchPrepared = false;
static u32 irOrigReadingCode[5] = {
0xE5940000, // ldr r0, [r4]
0xE1A01005, // mov r1, r5
0xE3A03005, // mov r3, #5
0xE3A02011, // mov r2, #17
0x00000000 // (bl i2c_read_raw goes here)
};
static u32 irHook[] = {
0xE5940000, // ldr r0, [r4]
0xE1A01005, // mov r1, r5
0xE59FC000, // ldr r12, [pc] (actually +8)
0xE12FFF3C, // blx r12
0x00000000 // irCodePhys goes here
};
static u32 syncHookCode[] = {
0xE5900000, // ldr r0, [r0]
0xEF000024, // svc 0x24
0xE3A00000, // mov r0, #0
0xE51FF004, // ldr pc, [pc, #-4]
0x00000000, // (return address goes here)
};
// Find offsets for required patches
s64 startAddress, textTotalRoundedSize, rodataTotalRoundedSize, dataTotalRoundedSize;
u32 totalSize;
Result 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) && !patchPrepared)
{
static const u32 irOrigWaitSyncCode[] = {
0xEF000024, // svc 0x24 (WaitSynchronization)
0xE1B01FA0, // movs r1, r0, lsr#31
0xE1A0A000, // mov r10, r0
}, irOrigWaitSyncCodeOld[] = {
0xE0AC6000, // adc r6, r12, r0
0xE5D70000, // ldrb r0, [r7]
}; // pattern for 8.1
static const u32 irOrigCppFlagCode[] = {
0xE3550000, // cmp r5, #0
0xE3A0B080, // mov r11, #0x80
};
u32 irDataPhys = (u32)PA_FROM_VA_PTR(irData);
u32 irCodePhys = (u32)PA_FROM_VA_PTR(&irCodePatchFunc);
u32 *off = (u32 *)memsearch((u8 *)0x00100000, &irOrigReadingCode, totalSize, sizeof(irOrigReadingCode) - 4);
if(off == NULL)
{
svcUnmapProcessMemoryEx(processHandle, 0x00100000, totalSize);
return -1;
}
u32 *off2 = (u32 *)memsearch((u8 *)0x00100000, &irOrigWaitSyncCode, totalSize, sizeof(irOrigWaitSyncCode));
if(off2 == NULL)
{
off2 = (u32 *)memsearch((u8 *)0x00100000, &irOrigWaitSyncCodeOld, totalSize, sizeof(irOrigWaitSyncCodeOld));
if(off2 == NULL)
{
svcUnmapProcessMemoryEx(processHandle, 0x00100000, totalSize);
return -2;
}
}
u32 *off3 = (u32 *)memsearch((u8 *)0x00100000, &irOrigCppFlagCode, totalSize, sizeof(irOrigCppFlagCode));
if(off3 == NULL)
{
svcUnmapProcessMemoryEx(processHandle, 0x00100000, totalSize);
return -3;
}
origIrSync = *off2;
origCppFlag = *off3;
*(void **)(irCodePhys + 8) = decodeArmBranch(off + 4);
*(void **)(irCodePhys + 12) = (void*)irDataPhys;
irHook[4] = irCodePhys;
irOrigReadingCode[4] = off[4]; // Copy the branch.
syncHookCode[4] = (u32)off2 + 4; // Hook return address
hookLoc = PA_FROM_VA_PTR(off);
syncLoc = PA_FROM_VA_PTR(off2);
cppFlagLoc = PA_FROM_VA_PTR(off3);
patchPrepared = true;
}
if (R_SUCCEEDED(res))
{
if (doPatch)
{
memcpy(hookLoc, &irHook, sizeof(irHook));
// We keep the WaitSynchronization1 to avoid general slowdown because of the high cpu load
if (*syncLoc == 0xEF000024) // svc 0x24 (WaitSynchronization)
{
syncLoc[-1] = 0xE51FF004;
syncLoc[0] = (u32)PA_FROM_VA_PTR(&syncHookCode);
}
else
{
// This "NOP"s out a WaitSynchronisation1 (on the event bound to the 'IR' interrupt) or the check of a previous one
*syncLoc = 0xE3A00000; // mov r0, #0
}
// This NOPs out a flag check in ir:user's CPP emulation
*cppFlagLoc = 0xE3150000; // tst r5, #0
}
else
{
memcpy(hookLoc, irOrigReadingCode, sizeof(irOrigReadingCode));
if (*syncLoc == 0xE3A00000)
*syncLoc = origIrSync;
else
{
syncLoc[-1] = 0xE5900000; // ldr r0, [r0]
syncLoc[0] = 0xEF000024; // svc 0x24
}
*cppFlagLoc = origCppFlag;
}
}
svcInvalidateEntireInstructionCache();
svcUnmapProcessMemoryEx(processHandle, 0x00100000, totalSize);
return res;
}
static Result InputRedirection_DoUndoHidPatches(Handle processHandle, bool doPatches)
{
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 bool patchPrepared = false;
static u32 *hidRegPatchOffsets[2];
static u32 *hidPatchJumpLoc;
// Find offsets for required patches
s64 startAddress, textTotalRoundedSize, rodataTotalRoundedSize, dataTotalRoundedSize;
u32 totalSize;
Result 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) && !patchPrepared)
{
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;
patchPrepared = true;
}
if(R_SUCCEEDED(res))
{
if (doPatches)
{
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,
};
*hidRegPatchOffsets[0] = *hidRegPatchOffsets[1] = hidDataPhys;
memcpy(hidPatchJumpLoc, &hidHook, sizeof(hidHook));
}
else
{
memcpy(hidRegPatchOffsets[0], &hidOrigRegisterAndValue, sizeof(hidOrigRegisterAndValue));
memcpy(hidRegPatchOffsets[1], &hidOrigRegisterAndValue, sizeof(hidOrigRegisterAndValue));
memcpy(hidPatchJumpLoc, &hidOrigCode, sizeof(hidOrigCode));
}
}
svcUnmapProcessMemoryEx(processHandle, 0x00100000, totalSize);
return res;
}
Result InputRedirection_Disable(s64 timeout) Result InputRedirection_Disable(s64 timeout)
{ {
if(!inputRedirectionEnabled) if(!inputRedirectionEnabled)
@@ -195,209 +426,46 @@ Result InputRedirection_Disable(s64 timeout)
Result InputRedirection_DoOrUndoPatches(void) Result InputRedirection_DoOrUndoPatches(void)
{ {
s64 startAddress, textTotalRoundedSize, rodataTotalRoundedSize, dataTotalRoundedSize;
u32 totalSize;
Handle processHandle;
Result res = OpenProcessByName("hid", &processHandle);
static bool hidPatched = false; static bool hidPatched = false;
static bool irPatched = false; static bool irPatched = false;
Handle hidProcHandle = 0, irProcHandle = 0;
// Prevent hid and ir from running, in any case
svcKernelSetState(0x10000, 4);
Result res = OpenProcessByName("hid", &hidProcHandle);
if (R_FAILED(res))
goto cleanup;
res = OpenProcessByName("ir", &irProcHandle);
if (R_FAILED(res))
goto cleanup;
if(R_SUCCEEDED(res)) if(R_SUCCEEDED(res))
{ {
svcGetProcessInfo(&textTotalRoundedSize, processHandle, 0x10002); // only patch .text + .data res = InputRedirection_DoUndoHidPatches(hidProcHandle, !hidPatched);
svcGetProcessInfo(&rodataTotalRoundedSize, processHandle, 0x10003); if (R_SUCCEEDED(res))
svcGetProcessInfo(&dataTotalRoundedSize, processHandle, 0x10004); hidPatched = !hidPatched;
totalSize = (u32)(textTotalRoundedSize + rodataTotalRoundedSize + dataTotalRoundedSize);
svcGetProcessInfo(&startAddress, processHandle, 0x10005);
res = svcMapProcessMemoryEx(CUR_PROCESS_HANDLE, 0x00100000, processHandle, (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(hidPatched)
{
memcpy(hidRegPatchOffsets[0], &hidOrigRegisterAndValue, sizeof(hidOrigRegisterAndValue));
memcpy(hidRegPatchOffsets[1], &hidOrigRegisterAndValue, sizeof(hidOrigRegisterAndValue));
memcpy(hidPatchJumpLoc, &hidOrigCode, sizeof(hidOrigCode));
hidPatched = false;
}
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(CUR_PROCESS_HANDLE, 0x00100000, totalSize);
return -1;
}
u32 *off2 = (u32 *)memsearch((u8 *)off + sizeof(hidOrigRegisterAndValue), &hidOrigRegisterAndValue, totalSize - ((u32)off - 0x00100000), sizeof(hidOrigRegisterAndValue));
if(off2 == NULL)
{
svcUnmapProcessMemoryEx(CUR_PROCESS_HANDLE, 0x00100000, totalSize);
return -2;
}
u32 *off3 = (u32 *)memsearch((u8 *)0x00100000, &hidOrigCode, totalSize, sizeof(hidOrigCode));
if(off3 == NULL)
{
svcUnmapProcessMemoryEx(CUR_PROCESS_HANDLE, 0x00100000, totalSize);
return -3;
}
hidRegPatchOffsets[0] = off;
hidRegPatchOffsets[1] = off2;
hidPatchJumpLoc = off3;
*off = *off2 = hidDataPhys;
memcpy(off3, &hidHook, sizeof(hidHook));
hidPatched = true;
}
}
res = svcUnmapProcessMemoryEx(CUR_PROCESS_HANDLE, 0x00100000, totalSize);
} }
svcCloseHandle(processHandle);
res = OpenProcessByName("ir", &processHandle);
if(R_SUCCEEDED(res) && GET_VERSION_MINOR(osGetKernelVersion()) >= 44) if(R_SUCCEEDED(res) && GET_VERSION_MINOR(osGetKernelVersion()) >= 44)
{ {
svcGetProcessInfo(&textTotalRoundedSize, processHandle, 0x10002); // only patch .text + .data res = InputRedirection_DoUndoIrPatches(irProcHandle, !irPatched);
svcGetProcessInfo(&rodataTotalRoundedSize, processHandle, 0x10003); if (R_SUCCEEDED(res))
svcGetProcessInfo(&dataTotalRoundedSize, processHandle, 0x10004); irPatched = !irPatched;
else if (!irPatched)
totalSize = (u32)(textTotalRoundedSize + rodataTotalRoundedSize + dataTotalRoundedSize);
svcGetProcessInfo(&startAddress, processHandle, 0x10005);
res = svcMapProcessMemoryEx(CUR_PROCESS_HANDLE, 0x00100000, processHandle, (u32) startAddress, totalSize);
if(R_SUCCEEDED(res))
{ {
static bool useOldSyncCode; InputRedirection_DoUndoHidPatches(hidProcHandle, false);
static u32 irOrigReadingCode[5] = { hidPatched = false;
0xE5940000, // ldr r0, [r4]
0xE1A01005, // mov r1, r5
0xE3A03005, // mov r3, #5
0xE3A02011, // mov r2, #17
0x00000000 // (bl i2c_read_raw goes here)
};
static const u32 irOrigWaitSyncCode[] = {
0xEF000024, // svc 0x24 (WaitSynchronization)
0xE1B01FA0, // movs r1, r0, lsr#31
0xE1A0A000, // mov r10, r0
}, irOrigWaitSyncCodeOld[] = {
0xE0AC6000, // adc r6, r12, r0
0xE5D70000, // ldrb r0, [r7]
}; // pattern for 8.1
static const u32 irOrigCppFlagCode[] = {
0xE3550000, // cmp r5, #0
0xE3A0B080, // mov r11, #0x80
};
static u32 *irHookLoc, *irWaitSyncLoc, *irCppFlagLoc;
if(irPatched)
{
memcpy(irHookLoc, &irOrigReadingCode, sizeof(irOrigReadingCode));
if(useOldSyncCode)
memcpy(irWaitSyncLoc, &irOrigWaitSyncCodeOld, sizeof(irOrigWaitSyncCodeOld));
else
memcpy(irWaitSyncLoc, &irOrigWaitSyncCode, sizeof(irOrigWaitSyncCode));
memcpy(irCppFlagLoc, &irOrigCppFlagCode, sizeof(irOrigCppFlagCode));
irPatched = false;
}
else
{
u32 irDataPhys = (u32)PA_FROM_VA_PTR(irData);
u32 irCodePhys = (u32)PA_FROM_VA_PTR(&irCodePatchFunc);
u32 irHook[] = {
0xE5940000, // ldr r0, [r4]
0xE1A01005, // mov r1, r5
0xE59FC000, // ldr r12, [pc] (actually +8)
0xE12FFF3C, // blx r12
irCodePhys,
};
u32 *off = (u32 *)memsearch((u8 *)0x00100000, &irOrigReadingCode, totalSize, sizeof(irOrigReadingCode) - 4);
if(off == NULL)
{
svcUnmapProcessMemoryEx(CUR_PROCESS_HANDLE, 0x00100000, totalSize);
return -4;
}
u32 *off2 = (u32 *)memsearch((u8 *)0x00100000, &irOrigWaitSyncCode, totalSize, sizeof(irOrigWaitSyncCode));
if(off2 == NULL)
{
off2 = (u32 *)memsearch((u8 *)0x00100000, &irOrigWaitSyncCodeOld, totalSize, sizeof(irOrigWaitSyncCodeOld));
if(off2 == NULL)
{
svcUnmapProcessMemoryEx(CUR_PROCESS_HANDLE, 0x00100000, totalSize);
return -5;
}
useOldSyncCode = true;
}
else
useOldSyncCode = false;
u32 *off3 = (u32 *)memsearch((u8 *)0x00100000, &irOrigCppFlagCode, totalSize, sizeof(irOrigCppFlagCode));
if(off3 == NULL)
{
svcUnmapProcessMemoryEx(CUR_PROCESS_HANDLE, 0x00100000, totalSize);
return -6;
}
*(void **)(irCodePhys + 8) = decodeArmBranch(off + 4);
*(void **)(irCodePhys + 12) = (void*)irDataPhys;
irHookLoc = off;
irWaitSyncLoc = off2;
irCppFlagLoc = off3;
irOrigReadingCode[4] = off[4]; // Copy the branch.
memcpy(irHookLoc, &irHook, sizeof(irHook));
// This "NOP"s out a WaitSynchronisation1 (on the event bound to the 'IR' interrupt) or the check of a previous one
*irWaitSyncLoc = 0xE3A00000; // mov r0, #0
// This NOPs out a flag check in ir:user's CPP emulation
*irCppFlagLoc = 0xE3150000; // tst r5, #0
irPatched = true;
}
} }
res = svcUnmapProcessMemoryEx(CUR_PROCESS_HANDLE, 0x00100000, totalSize);
} }
svcCloseHandle(processHandle);
cleanup:
svcKernelSetState(0x10000, 4);
svcCloseHandle(hidProcHandle);
svcCloseHandle(irProcHandle);
return res; return res;
} }

View File

@@ -0,0 +1,122 @@
/*
* This file is part of Luma3DS
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
* * Requiring preservation of specified reasonable legal notices or
* author attributions in that material or in the Appropriate Legal
* Notices displayed by works containing it.
* * Prohibiting misrepresentation of the origin of that material,
* or requiring that modified versions of such material be marked in
* reasonable ways as different from the original version.
*/
#include <3ds.h>
#include <math.h>
#include "luminance.h"
#include "utils.h"
extern bool isN3DS;
typedef struct BlPwmData
{
float coeffs[3][3];
u8 numLevels;
u8 unk;
u16 luminanceLevels[7];
u16 brightnessMax;
u16 brightnessMin;
} BlPwmData;
// Calibration, with (dubious) default values as fallback
static BlPwmData s_blPwmData = {
.coeffs = {
{ 0.00111639f, 1.41412f, 0.07178809f },
{ 0.000418169f, 0.66567f, 0.06098654f },
{ 0.00208543f, 1.55639f, 0.0385939f }
},
.numLevels = 5,
.unk = 0,
.luminanceLevels = { 20, 43, 73, 95, 117, 172, 172 },
.brightnessMax = 512,
.brightnessMin = 13,
};
static inline float getPwmRatio(u32 brightnessMax, u32 pwmCnt)
{
u32 val = (pwmCnt & 0x10000) ? pwmCnt & 0x3FF : 511; // check pwm enabled flag
return (float)brightnessMax / (val + 1);
}
// nn's asm has rounding errors (originally at 10^-3)
static inline u32 luminanceToBrightness(u32 luminance, const float coeffs[3], u32 minLuminance, float pwmRatio)
{
float x = (float)luminance;
float y = coeffs[0]*x*x + coeffs[1]*x + coeffs[2];
y = (y <= minLuminance ? (float)minLuminance : y) / pwmRatio;
return (u32)(y + 0.5f);
}
static inline u32 brightnessToLuminance(u32 brightness, const float coeffs[3], float pwmRatio)
{
// Find polynomial root of ax^2 + bx + c = y
float y = (float)brightness * pwmRatio;
float a = coeffs[0];
float b = coeffs[1];
float c = coeffs[2] - y;
float x0 = (-b + sqrtf(b*b - 4.0f*a*c)) / (a + a);
return (u32)(x0 + 0.5f);
}
static void readCalibration(void)
{
static bool calibRead = false;
if (!calibRead) {
cfguInit();
calibRead = R_SUCCEEDED(CFG_GetConfigInfoBlk8(sizeof(BlPwmData), 0x50002, &s_blPwmData));
cfguExit();
}
}
u32 getMinLuminancePreset(void)
{
readCalibration();
return s_blPwmData.luminanceLevels[0];
}
u32 getMaxLuminancePreset(void)
{
readCalibration();
return s_blPwmData.luminanceLevels[s_blPwmData.numLevels - 1];
}
u32 getCurrentLuminance(bool top)
{
u32 regbase = top ? 0x10202200 : 0x10202A00;
readCalibration();
const float *coeffs = s_blPwmData.coeffs[top ? (isN3DS ? 2 : 1) : 0];
u32 brightness = REG32(regbase + 0x40);
float ratio = getPwmRatio(s_blPwmData.brightnessMax, REG32(regbase + 0x44));
return brightnessToLuminance(brightness, coeffs, ratio);
}

View File

@@ -34,7 +34,6 @@
#include "utils.h" #include "utils.h"
#include "MyThread.h" #include "MyThread.h"
#include "menus/miscellaneous.h" #include "menus/miscellaneous.h"
#include "plgloader.h"
#include "menus/debugger.h" #include "menus/debugger.h"
#include "menus/screen_filters.h" #include "menus/screen_filters.h"
#include "menus/cheats.h" #include "menus/cheats.h"
@@ -83,13 +82,15 @@ void initSystem(void)
isN3DS = svcGetSystemInfo(&out, 0x10001, 0) == 0; isN3DS = svcGetSystemInfo(&out, 0x10001, 0) == 0;
svcGetSystemInfo(&out, 0x10000, 0x100); svcGetSystemInfo(&out, 0x10000, 0x100);
HBLDR_3DSX_TID = out == 0 ? HBLDR_DEFAULT_3DSX_TID : (u64)out; Luma_SharedConfig->hbldr_3dsx_tid = out == 0 ? HBLDR_DEFAULT_3DSX_TID : (u64)out;
Luma_SharedConfig->use_hbldr = true;
svcGetSystemInfo(&out, 0x10000, 0x101); svcGetSystemInfo(&out, 0x10000, 0x101);
menuCombo = out == 0 ? DEFAULT_MENU_COMBO : (u32)out; menuCombo = out == 0 ? DEFAULT_MENU_COMBO : (u32)out;
miscellaneousMenu.items[0].title = HBLDR_3DSX_TID == HBLDR_DEFAULT_3DSX_TID ? "Switch the hb. title to the current app." : miscellaneousMenu.items[0].title = Luma_SharedConfig->hbldr_3dsx_tid == HBLDR_DEFAULT_3DSX_TID ?
"Switch the hb. title to hblauncher_loader"; "Switch the hb. title to the current app." :
"Switch the hb. title to hblauncher_loader";
for(res = 0xD88007FA; res == (Result)0xD88007FA; svcSleepThread(500 * 1000LL)) for(res = 0xD88007FA; res == (Result)0xD88007FA; svcSleepThread(500 * 1000LL))
{ {
@@ -104,6 +105,9 @@ void initSystem(void)
if (R_FAILED(fsInit())) if (R_FAILED(fsInit()))
svcBreak(USERBREAK_PANIC); svcBreak(USERBREAK_PANIC);
if (R_FAILED(FSUSER_SetPriority(-16)))
svcBreak(USERBREAK_PANIC);
// **** DO NOT init services that don't come from KIPs here **** // **** DO NOT init services that don't come from KIPs here ****
// Instead, init the service only where it's actually init (then deinit it). // Instead, init the service only where it's actually init (then deinit it).
@@ -131,11 +135,53 @@ static void handleTermNotification(u32 notificationId)
(void)notificationId; (void)notificationId;
} }
static void handleSleepNotification(u32 notificationId)
{
ptmSysmInit();
s32 ackValue = ptmSysmGetNotificationAckValue(notificationId);
switch (notificationId)
{
case PTMNOTIFID_SLEEP_REQUESTED:
menuShouldExit = true;
PTMSYSM_ReplyToSleepQuery(miniSocEnabled); // deny sleep request if we have network stuff running
break;
case PTMNOTIFID_GOING_TO_SLEEP:
case PTMNOTIFID_SLEEP_ALLOWED:
case PTMNOTIFID_FULLY_WAKING_UP:
case PTMNOTIFID_HALF_AWAKE:
PTMSYSM_NotifySleepPreparationComplete(ackValue);
break;
case PTMNOTIFID_SLEEP_DENIED:
case PTMNOTIFID_FULLY_AWAKE:
menuShouldExit = false;
break;
default:
break;
}
ptmSysmExit();
}
static void handleShellNotification(u32 notificationId)
{
if (notificationId == 0x213) {
// Shell opened
// Note that this notification is fired on system init
ScreenFiltersMenu_RestoreCct();
menuShouldExit = false;
} else {
// Shell closed
menuShouldExit = true;
}
}
static void handlePreTermNotification(u32 notificationId) static void handlePreTermNotification(u32 notificationId)
{ {
(void)notificationId; (void)notificationId;
// Might be subject to a race condition, but heh. // Might be subject to a race condition, but heh.
miniSocUnlockState(true);
// Disable input redirection // Disable input redirection
InputRedirection_Disable(100 * 1000 * 1000LL); InputRedirection_Disable(100 * 1000 * 1000LL);
@@ -180,11 +226,19 @@ static const ServiceManagerServiceEntry services[] = {
}; };
static const ServiceManagerNotificationEntry notifications[] = { static const ServiceManagerNotificationEntry notifications[] = {
{ 0x100 , handleTermNotification }, { 0x100 , handleTermNotification },
//{ 0x103 , handlePreTermNotification }, // Sleep mode entry <=== causes issues { PTMNOTIFID_SLEEP_REQUESTED, handleSleepNotification },
{ 0x1000, handleNextApplicationDebuggedByForce }, { PTMNOTIFID_SLEEP_DENIED, handleSleepNotification },
{ 0x2000, handlePreTermNotification }, { PTMNOTIFID_SLEEP_ALLOWED, handleSleepNotification },
{ 0x3000, handleRestartHbAppNotification }, { PTMNOTIFID_GOING_TO_SLEEP, handleSleepNotification },
{ PTMNOTIFID_FULLY_WAKING_UP, handleSleepNotification },
{ PTMNOTIFID_FULLY_AWAKE, handleSleepNotification },
{ PTMNOTIFID_HALF_AWAKE, handleSleepNotification },
{ 0x213, handleShellNotification },
{ 0x214, handleShellNotification },
{ 0x1000, handleNextApplicationDebuggedByForce },
{ 0x2000, handlePreTermNotification },
{ 0x3000, handleRestartHbAppNotification },
{ 0x000, NULL }, { 0x000, NULL },
}; };
@@ -208,14 +262,17 @@ int main(void)
MyThread *menuThread = menuCreateThread(); MyThread *menuThread = menuCreateThread();
MyThread *taskRunnerThread = taskRunnerCreateThread(); MyThread *taskRunnerThread = taskRunnerCreateThread();
MyThread *plgloaderThread = PluginLoader__CreateThread(); MyThread *errDispThread = errDispCreateThread();
if (R_FAILED(ServiceManager_Run(services, notifications, NULL))) if (R_FAILED(ServiceManager_Run(services, notifications, NULL)))
svcBreak(USERBREAK_PANIC); svcBreak(USERBREAK_PANIC);
TaskRunner_Terminate();
MyThread_Join(menuThread, -1LL); MyThread_Join(menuThread, -1LL);
MyThread_Join(taskRunnerThread, -1LL); MyThread_Join(taskRunnerThread, -1LL);
MyThread_Join(plgloaderThread, -1LL); MyThread_Join(errDispThread, -1LL);
return 0; return 0;
} }

View File

@@ -51,15 +51,6 @@ u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSize)
return NULL; return NULL;
} }
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;
}
void hexItoa(u64 number, char *out, u32 digits, bool uppercase) void hexItoa(u64 number, char *out, u32 digits, bool uppercase)
{ {
const char hexDigits[] = "0123456789ABCDEF"; const char hexDigits[] = "0123456789ABCDEF";

View File

@@ -32,7 +32,6 @@
#include "ifile.h" #include "ifile.h"
#include "menus.h" #include "menus.h"
#include "utils.h" #include "utils.h"
#include "plgloader.h"
#include "menus/n3ds.h" #include "menus/n3ds.h"
#include "menus/cheats.h" #include "menus/cheats.h"
#include "minisoc.h" #include "minisoc.h"
@@ -144,7 +143,6 @@ u32 waitCombo(void)
static MyThread menuThread; static MyThread menuThread;
static u8 ALIGN(8) menuThreadStack[0x1000]; static u8 ALIGN(8) menuThreadStack[0x1000];
static u8 batteryLevel = 255; static u8 batteryLevel = 255;
static u32 homeBtnPressed = 0;
static inline u32 menuAdvanceCursor(u32 pos, u32 numItems, s32 displ) static inline u32 menuAdvanceCursor(u32 pos, u32 numItems, s32 displ)
{ {
@@ -170,17 +168,14 @@ u32 menuCountItems(const Menu *menu)
MyThread *menuCreateThread(void) MyThread *menuCreateThread(void)
{ {
svcKernelSetState(0x10007, &homeBtnPressed); if(R_FAILED(MyThread_Create(&menuThread, menuThreadMain, menuThreadStack, 0x1000, 52, CORE_SYSTEM)))
if(R_FAILED(MyThread_Create(&menuThread, menuThreadMain, menuThreadStack, 0x3000, 52, CORE_SYSTEM)))
svcBreak(USERBREAK_PANIC); svcBreak(USERBREAK_PANIC);
return &menuThread; return &menuThread;
} }
u32 menuCombo; u32 menuCombo;
u32 DispWarningOnHome(void); void menuThreadMain(void)
void menuThreadMain(void)
{ {
if(isN3DS) if(isN3DS)
N3DSMenu_UpdateStatus(); N3DSMenu_UpdateStatus();
@@ -193,29 +188,19 @@ void menuThreadMain(void)
while(!preTerminationRequested) while(!preTerminationRequested)
{ {
svcSleepThread(50 * 1000 * 1000LL);
if (menuShouldExit) if (menuShouldExit)
continue; continue;
if ((scanHeldKeys() & menuCombo) == menuCombo) Cheat_ApplyCheats();
if((scanHeldKeys() & menuCombo) == menuCombo)
{ {
menuEnter(); menuEnter();
if(isN3DS) N3DSMenu_UpdateStatus(); if(isN3DS) N3DSMenu_UpdateStatus();
PluginLoader__UpdateMenu();
menuShow(&rosalinaMenu); menuShow(&rosalinaMenu);
menuLeave(); menuLeave();
} }
// Check for home button on O3DS Mode3 with plugin loaded
if (homeBtnPressed != 0)
{
if (DispWarningOnHome())
svcKernelSetState(7); ///< reboot is fine since exiting a mode3 game reboot anyway
homeBtnPressed = 0;
}
svcSleepThread(50 * 1000 * 1000LL);
} }
} }
@@ -226,17 +211,17 @@ void menuEnter(void)
if(!menuShouldExit && menuRefCount == 0) if(!menuShouldExit && menuRefCount == 0)
{ {
menuRefCount++; menuRefCount++;
svcKernelSetState(0x10000, 1); svcKernelSetState(0x10000, 2 | 1);
svcSleepThread(5 * 1000 * 100LL); svcSleepThread(5 * 1000 * 100LL);
if (Draw_AllocateFramebufferCache() == 0) if (R_FAILED(Draw_AllocateFramebufferCache(FB_BOTTOM_SIZE)))
{ {
// Oops // Oops
menuRefCount = 0; menuRefCount = 0;
svcKernelSetState(0x10000, 1); svcKernelSetState(0x10000, 2 | 1);
svcSleepThread(5 * 1000 * 100LL); svcSleepThread(5 * 1000 * 100LL);
} }
else
Draw_SetupFramebuffer(); Draw_SetupFramebuffer();
} }
Draw_Unlock(); Draw_Unlock();
} }
@@ -250,7 +235,7 @@ void menuLeave(void)
{ {
Draw_RestoreFramebuffer(); Draw_RestoreFramebuffer();
Draw_FreeFramebufferCache(); Draw_FreeFramebufferCache();
svcKernelSetState(0x10000, 1); svcKernelSetState(0x10000, 2 | 1);
} }
Draw_Unlock(); Draw_Unlock();
} }
@@ -421,158 +406,3 @@ void menuShow(Menu *root)
} }
while(!menuShouldExit); while(!menuShouldExit);
} }
static const char *__press_b_to_close = "Press [B] to close";
void DispMessage(const char *title, const char *message)
{
menuEnter();
Draw_Lock();
Draw_ClearFramebuffer();
Draw_FlushFramebuffer();
Draw_DrawString(10, 10, COLOR_TITLE, title);
Draw_DrawString(30, 30, COLOR_WHITE, message);
Draw_DrawString(200, 220, COLOR_TITLE, __press_b_to_close);
u32 keys = 0;
do
{
keys = waitComboWithTimeout(1000);
}while (!preTerminationRequested && !(keys & KEY_B));
Draw_Unlock(); ///< Keep it locked until we exit the message
menuLeave();
}
u32 DispErrMessage(const char *title, const char *message, const Result error)
{
char buf[100];
sprintf(buf, "Error code: 0x%08X", (unsigned int)error);
menuEnter();
Draw_Lock();
Draw_ClearFramebuffer();
Draw_FlushFramebuffer();
Draw_DrawString(10, 10, COLOR_TITLE, title);
u32 posY = Draw_DrawString(30, 30, COLOR_WHITE, message);
Draw_DrawString(30, posY + 20, COLOR_RED, buf);
Draw_DrawString(200, 220, COLOR_TITLE, __press_b_to_close);
u32 keys = 0;
do
{
keys = waitComboWithTimeout(1000);
}while (!preTerminationRequested && !(keys & KEY_B));
Draw_Unlock(); ///< Keep it locked until we exit the message
menuLeave();
return error;
}
u32 DispWarningOnHome(void)
{
menuEnter();
Draw_Lock();
Draw_ClearFramebuffer();
Draw_FlushFramebuffer();
Draw_DrawString(10, 10, COLOR_TITLE, "Warning");
u32 posY = Draw_DrawString(30, 40, COLOR_WHITE, "Due to memory shortage the home button\nis disabled.");
Draw_DrawString(30, posY + 20, COLOR_WHITE, "Press [DPAD UP + B] to exit the application.");
Draw_DrawString(200, 220, COLOR_TITLE, __press_b_to_close);
u32 keys = 0;
do
{
keys = waitComboWithTimeout(1000);
}while (!preTerminationRequested && !(keys & KEY_B));
Draw_Unlock(); ///< Keep it locked until we exit the message
menuLeave();
return (keys & KEY_UP) > 0;
}
typedef char string[50];
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
void DisplayPluginMenu(u32 *cmdbuf)
{
u32 cursor = 0;
u32 nbItems = cmdbuf[1];
u8 *states = (u8 *)cmdbuf[3];
char buffer[60];
const char *title = (const char *)cmdbuf[5];
const string *items = (const string *)cmdbuf[7];
const string *hints = (const string *)cmdbuf[9];
menuEnter();
Draw_Lock();
do
{
// Draw the menu
{
// Clear screen
Draw_ClearFramebuffer();
Draw_FlushFramebuffer();
// Draw title
Draw_DrawString(10, 10, COLOR_TITLE, title);
// Draw items
u32 i = MAX(0, (int)cursor - 7);
u32 end = MIN(nbItems, i + 16);
u32 posY = 30;
for (; i < end; ++i, posY += 10)
{
sprintf(buffer, "[ ] %s", items[i]);
Draw_DrawString(30, posY, COLOR_WHITE, buffer);
if (i == cursor) Draw_DrawCharacter(10, posY, COLOR_TITLE, '>');
if (states[i]) Draw_DrawCharacter(36, posY, COLOR_LIME, 'x');
}
// Draw hint
if (hints[cursor])
Draw_DrawString(10, 200, COLOR_TITLE, hints[cursor]);
}
// Wait for input
u32 pressed = waitInput();
if (pressed & KEY_A)
states[cursor] = !states[cursor];
if (pressed & KEY_B)
break;
if (pressed & KEY_DOWN)
if (++cursor >= nbItems)
cursor = 0;
if (pressed & KEY_UP)
if (--cursor >= nbItems)
cursor = nbItems - 1;
} while (true);
Draw_Unlock();
menuLeave();
}

View File

@@ -35,18 +35,17 @@
#include "menus/miscellaneous.h" #include "menus/miscellaneous.h"
#include "menus/sysconfig.h" #include "menus/sysconfig.h"
#include "menus/screen_filters.h" #include "menus/screen_filters.h"
#include "plgloader.h"
#include "ifile.h" #include "ifile.h"
#include "memory.h" #include "memory.h"
#include "fmt.h" #include "fmt.h"
#include "process_patches.h" #include "process_patches.h"
#include "luminance.h"
Menu rosalinaMenu = { Menu rosalinaMenu = {
"Rosalina menu", "Rosalina menu",
{ {
{ "Take screenshot", METHOD, .method = &RosalinaMenu_TakeScreenshot }, { "Take screenshot", METHOD, .method = &RosalinaMenu_TakeScreenshot },
{ "Change screen brightness", METHOD, .method = &RosalinaMenu_ChangeScreenBrightness }, { "Change screen brightness", METHOD, .method = &RosalinaMenu_ChangeScreenBrightness },
{ "", METHOD, .method = PluginLoader__MenuCallback},
{ "Cheats...", METHOD, .method = &RosalinaMenu_Cheats }, { "Cheats...", METHOD, .method = &RosalinaMenu_Cheats },
{ "Process list", METHOD, .method = &RosalinaMenu_ProcessList }, { "Process list", METHOD, .method = &RosalinaMenu_ProcessList },
{ "Debugger options...", MENU, .menu = &debuggerMenu }, { "Debugger options...", MENU, .menu = &debuggerMenu },
@@ -64,7 +63,11 @@ Menu rosalinaMenu = {
bool rosalinaMenuShouldShowDebugInfo(void) bool rosalinaMenuShouldShowDebugInfo(void)
{ {
return true; // Don't show on release builds
s64 out;
svcGetSystemInfo(&out, 0x10000, 0x200);
return out == 0;
} }
void RosalinaMenu_ShowDebugInfo(void) void RosalinaMenu_ShowDebugInfo(void)
@@ -109,7 +112,6 @@ void RosalinaMenu_ShowCredits(void)
u32 posY = Draw_DrawString(10, 30, COLOR_WHITE, "Luma3DS (c) 2016-2020 AuroraWright, TuxSH") + SPACING_Y; u32 posY = Draw_DrawString(10, 30, COLOR_WHITE, "Luma3DS (c) 2016-2020 AuroraWright, TuxSH") + SPACING_Y;
posY = Draw_DrawString(10, posY + SPACING_Y, COLOR_WHITE, "3gx implementation update by mind_overflow");
posY = Draw_DrawString(10, posY + SPACING_Y, COLOR_WHITE, "3DSX loading code by fincs"); 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, "Networking code & basic GDB functionality by Stary");
posY = Draw_DrawString(10, posY + SPACING_Y, COLOR_WHITE, "InputRedirection by Stary (PoC by ShinyQuagsire)"); posY = Draw_DrawString(10, posY + SPACING_Y, COLOR_WHITE, "InputRedirection by Stary (PoC by ShinyQuagsire)");
@@ -119,8 +121,8 @@ void RosalinaMenu_ShowCredits(void)
Draw_DrawString(10, posY, COLOR_WHITE, Draw_DrawString(10, posY, COLOR_WHITE,
( (
"Special thanks to:\n" "Special thanks to:\n"
" Bond697, WinterMute, piepie62, yifanlu\n" " fincs, WinterMute, mtheall, piepie62,\n"
" Luma3DS contributors, ctrulib contributors,\n" " Luma3DS contributors, libctru contributors,\n"
" other people" " other people"
)); ));
@@ -140,7 +142,7 @@ void RosalinaMenu_Reboot(void)
do do
{ {
Draw_Lock(); Draw_Lock();
Draw_DrawString(10, 10, COLOR_TITLE, "Rosalina menu"); Draw_DrawString(10, 10, COLOR_TITLE, "Reboot");
Draw_DrawString(10, 30, COLOR_WHITE, "Press A to reboot, press B to go back."); Draw_DrawString(10, 30, COLOR_WHITE, "Press A to reboot, press B to go back.");
Draw_FlushFramebuffer(); Draw_FlushFramebuffer();
Draw_Unlock(); Draw_Unlock();
@@ -158,107 +160,102 @@ void RosalinaMenu_Reboot(void)
while(!menuShouldExit); while(!menuShouldExit);
} }
static u32 gspPatchAddrN3ds, gspPatchValuesN3ds[2];
static bool gspPatchDoneN3ds;
static Result RosalinaMenu_PatchN3dsGspForBrightness(u32 size)
{
u32 *off = (u32 *)0x00100000;
u32 *end = (u32 *)(0x00100000 + size);
for (; off < end && (off[0] != 0xE92D4030 || off[1] != 0xE1A04000 || off[2] != 0xE2805C01 || off[3] != 0xE5D0018C); off++);
if (off >= end) {
return -1;
}
gspPatchAddrN3ds = (u32)off;
gspPatchValuesN3ds[0] = off[26];
gspPatchValuesN3ds[1] = off[50];
// NOP brightness changing in GSP
off[26] = 0xE1A00000;
off[50] = 0xE1A00000;
return 0;
}
static Result RosalinaMenu_RevertN3dsGspPatch(u32 size)
{
(void)size;
u32 *off = (u32 *)gspPatchAddrN3ds;
off[26] = gspPatchValuesN3ds[0];
off[50] = gspPatchValuesN3ds[1];
return 0;
}
void RosalinaMenu_ChangeScreenBrightness(void) void RosalinaMenu_ChangeScreenBrightness(void)
{ {
Result patchResult = 0;
if (isN3DS && !gspPatchDoneN3ds)
{
patchResult = PatchProcessByName("gsp", RosalinaMenu_PatchN3dsGspForBrightness);
gspPatchDoneN3ds = R_SUCCEEDED(patchResult);
}
Draw_Lock(); Draw_Lock();
Draw_ClearFramebuffer(); Draw_ClearFramebuffer();
Draw_FlushFramebuffer(); Draw_FlushFramebuffer();
Draw_Unlock(); Draw_Unlock();
// gsp:LCD GetLuminance is stubbed on O3DS so we have to implement it ourselves... damn it.
// Assume top and bottom screen luminances are the same (should be; if not, we'll set them to the same values).
u32 luminance = getCurrentLuminance(false);
u32 minLum = getMinLuminancePreset();
u32 maxLum = getMaxLuminancePreset();
do do
{ {
// Assume the current brightness for both screens are the same.
s32 brightness = (s32)(LCD_TOP_BRIGHTNESS & 0xFF);
Draw_Lock(); Draw_Lock();
Draw_DrawString(10, 10, COLOR_TITLE, "Rosalina menu"); Draw_DrawString(10, 10, COLOR_TITLE, "Screen brightness");
u32 posY = 30; u32 posY = 30;
posY = Draw_DrawFormattedString(10, posY, COLOR_WHITE, "Current brightness (0..255): %3lu\n\n", brightness); posY = Draw_DrawFormattedString(
if (R_SUCCEEDED(patchResult)) 10,
{ posY,
posY = Draw_DrawString(10, posY, COLOR_WHITE, "Press Up/Down for +-1, Right/Left for +-10.\n"); COLOR_WHITE,
posY = Draw_DrawString(10, posY, COLOR_WHITE, "Press Y to revert the GSP patch and exit.\n\n"); "Current luminance: %lu (min. %lu, max. %lu)\n\n",
luminance,
posY = Draw_DrawString(10, posY, COLOR_RED, "WARNING: \n"); minLum,
posY = Draw_DrawString(10, posY, COLOR_WHITE, " * avoid using values far higher than the presets.\n"); maxLum
posY = Draw_DrawString(10, posY, COLOR_WHITE, " * normal brightness mngmt. is now broken on N3DS.\nYou'll need to press Y to revert"); );
} posY = Draw_DrawString(10, posY, COLOR_WHITE, "Controls: Up/Down for +-1, Right/Left for +-10.\n");
else posY = Draw_DrawString(10, posY, COLOR_WHITE, "Press A to start, B to exit.\n\n");
Draw_DrawFormattedString(10, posY, COLOR_WHITE, "Failed to patch GSP (0x%08lx).", (u32)patchResult);
posY = Draw_DrawString(10, posY, COLOR_RED, "WARNING: \n");
posY = Draw_DrawString(10, posY, COLOR_WHITE, " * value will be limited by the presets.\n");
posY = Draw_DrawString(10, posY, COLOR_WHITE, " * bottom framebuffer will be restored until\nyou exit.");
Draw_FlushFramebuffer(); Draw_FlushFramebuffer();
Draw_Unlock(); Draw_Unlock();
u32 pressed = waitInputWithTimeout(1000); u32 pressed = waitInputWithTimeout(1000);
if ((pressed & DIRECTIONAL_KEYS) && R_SUCCEEDED(patchResult)) if (pressed & KEY_A)
{ break;
if (pressed & KEY_UP)
brightness += 1;
else if (pressed & KEY_DOWN)
brightness -= 1;
else if (pressed & KEY_RIGHT)
brightness += 10;
else if (pressed & KEY_LEFT)
brightness -= 10;
brightness = brightness < 0 ? 0 : brightness; if (pressed & KEY_B)
brightness = brightness > 255 ? 255 : brightness;
LCD_TOP_BRIGHTNESS = (u32)brightness;
LCD_BOT_BRIGHTNESS = (u32)brightness;
}
else if ((pressed & KEY_Y) && gspPatchDoneN3ds)
{
patchResult = PatchProcessByName("gsp", RosalinaMenu_RevertN3dsGspPatch);
gspPatchDoneN3ds = !R_SUCCEEDED(patchResult);
return;
}
else if (pressed & KEY_B)
return; return;
} }
while (!menuShouldExit); while (!menuShouldExit);
Draw_Lock();
Draw_RestoreFramebuffer();
Draw_FreeFramebufferCache();
svcKernelSetState(0x10000, 2); // unblock gsp
gspLcdInit(); // assume it doesn't fail. If it does, brightness won't change, anyway.
// gsp:LCD will normalize the brightness between top/bottom screen, handle PWM, etc.
s32 lum = (s32)luminance;
do
{
u32 pressed = waitInputWithTimeout(1000);
if (pressed & DIRECTIONAL_KEYS)
{
if (pressed & KEY_UP)
lum += 1;
else if (pressed & KEY_DOWN)
lum -= 1;
else if (pressed & KEY_RIGHT)
lum += 10;
else if (pressed & KEY_LEFT)
lum -= 10;
lum = lum < 0 ? 0 : lum;
// We need to call gsp here because updating the active duty LUT is a bit tedious (plus, GSP has internal state).
// This is actually SetLuminance:
GSPLCD_SetBrightnessRaw(BIT(GSP_SCREEN_TOP) | BIT(GSP_SCREEN_BOTTOM), lum);
}
if (pressed & KEY_B)
break;
}
while (!menuShouldExit);
gspLcdExit();
svcKernelSetState(0x10000, 2); // block gsp again
if (R_FAILED(Draw_AllocateFramebufferCache(FB_BOTTOM_SIZE)))
{
// Shouldn't happen
__builtin_trap();
}
else
Draw_SetupFramebuffer();
Draw_Unlock();
} }
void RosalinaMenu_PowerOff(void) // Soft shutdown. void RosalinaMenu_PowerOff(void) // Soft shutdown.
@@ -271,7 +268,7 @@ void RosalinaMenu_PowerOff(void) // Soft shutdown.
do do
{ {
Draw_Lock(); Draw_Lock();
Draw_DrawString(10, 10, COLOR_TITLE, "Rosalina menu"); Draw_DrawString(10, 10, COLOR_TITLE, "Power off");
Draw_DrawString(10, 30, COLOR_WHITE, "Press A to power off, press B to go back."); Draw_DrawString(10, 30, COLOR_WHITE, "Press A to power off, press B to go back.");
Draw_FlushFramebuffer(); Draw_FlushFramebuffer();
Draw_Unlock(); Draw_Unlock();
@@ -296,18 +293,20 @@ void RosalinaMenu_PowerOff(void) // Soft shutdown.
static s64 timeSpentConvertingScreenshot = 0; static s64 timeSpentConvertingScreenshot = 0;
static s64 timeSpentWritingScreenshot = 0; static s64 timeSpentWritingScreenshot = 0;
static Result RosalinaMenu_WriteScreenshot(IFile *file, bool top, bool left) static Result RosalinaMenu_WriteScreenshot(IFile *file, u32 width, bool top, bool left)
{ {
u64 total; u64 total;
Result res = 0; Result res = 0;
u32 dimX = top ? 400 : 320; u32 lineSize = 3 * width;
u32 lineSize = 3 * dimX;
u32 remaining = lineSize * 240; u32 remaining = lineSize * 240;
TRY(Draw_AllocateFramebufferCacheForScreenshot(remaining));
u8 *framebufferCache = (u8 *)Draw_GetFramebufferCache(); u8 *framebufferCache = (u8 *)Draw_GetFramebufferCache();
u8 *framebufferCacheEnd = framebufferCache + Draw_GetFramebufferCacheSize(); u8 *framebufferCacheEnd = framebufferCache + Draw_GetFramebufferCacheSize();
u8 *buf = framebufferCache; u8 *buf = framebufferCache;
Draw_CreateBitmapHeader(framebufferCache, dimX, 240); Draw_CreateBitmapHeader(framebufferCache, width, 240);
buf += 54; buf += 54;
u32 y = 0; u32 y = 0;
@@ -318,7 +317,7 @@ static Result RosalinaMenu_WriteScreenshot(IFile *file, bool top, bool left)
u32 available = (u32)(framebufferCacheEnd - buf); u32 available = (u32)(framebufferCacheEnd - buf);
u32 size = available < remaining ? available : remaining; u32 size = available < remaining ? available : remaining;
u32 nlines = size / lineSize; u32 nlines = size / lineSize;
Draw_ConvertFrameBufferLines(buf, y, nlines, top, left); Draw_ConvertFrameBufferLines(buf, width, y, nlines, top, left);
s64 t1 = svcGetSystemTick(); s64 t1 = svcGetSystemTick();
timeSpentConvertingScreenshot += t1 - t0; timeSpentConvertingScreenshot += t1 - t0;
@@ -329,7 +328,10 @@ static Result RosalinaMenu_WriteScreenshot(IFile *file, bool top, bool left)
remaining -= lineSize * nlines; remaining -= lineSize * nlines;
buf = framebufferCache; buf = framebufferCache;
} }
end: return res; end:
Draw_FreeFramebufferCache();
return res;
} }
void RosalinaMenu_TakeScreenshot(void) void RosalinaMenu_TakeScreenshot(void)
@@ -353,9 +355,16 @@ void RosalinaMenu_TakeScreenshot(void)
archiveId = isSdMode ? ARCHIVE_SDMC : ARCHIVE_NAND_RW; archiveId = isSdMode ? ARCHIVE_SDMC : ARCHIVE_NAND_RW;
Draw_Lock(); Draw_Lock();
Draw_RestoreFramebuffer(); Draw_RestoreFramebuffer();
Draw_FreeFramebufferCache();
svcFlushEntireDataCache(); svcFlushEntireDataCache();
bool is3d;
u32 topWidth, bottomWidth; // actually Y-dim
Draw_GetCurrentScreenInfo(&bottomWidth, &is3d, false);
Draw_GetCurrentScreenInfo(&topWidth, &is3d, true);
res = FSUSER_OpenArchive(&archive, archiveId, fsMakePath(PATH_EMPTY, "")); res = FSUSER_OpenArchive(&archive, archiveId, fsMakePath(PATH_EMPTY, ""));
if(R_SUCCEEDED(res)) if(R_SUCCEEDED(res))
{ {
@@ -410,24 +419,28 @@ void RosalinaMenu_TakeScreenshot(void)
sprintf(filename, "/luma/screenshots/%04lu-%02lu-%02lu_%02lu-%02lu-%02lu.%03llu_top.bmp", year, month, days, hours, minutes, seconds, milliseconds); sprintf(filename, "/luma/screenshots/%04lu-%02lu-%02lu_%02lu-%02lu-%02lu.%03llu_top.bmp", year, month, days, hours, minutes, seconds, milliseconds);
TRY(IFile_Open(&file, archiveId, fsMakePath(PATH_EMPTY, ""), fsMakePath(PATH_ASCII, filename), FS_OPEN_CREATE | FS_OPEN_WRITE)); TRY(IFile_Open(&file, archiveId, fsMakePath(PATH_EMPTY, ""), fsMakePath(PATH_ASCII, filename), FS_OPEN_CREATE | FS_OPEN_WRITE));
TRY(RosalinaMenu_WriteScreenshot(&file, true, true)); TRY(RosalinaMenu_WriteScreenshot(&file, topWidth, true, true));
TRY(IFile_Close(&file)); TRY(IFile_Close(&file));
sprintf(filename, "/luma/screenshots/%04lu-%02lu-%02lu_%02lu-%02lu-%02lu.%03llu_bot.bmp", year, month, days, hours, minutes, seconds, milliseconds); sprintf(filename, "/luma/screenshots/%04lu-%02lu-%02lu_%02lu-%02lu-%02lu.%03llu_bot.bmp", year, month, days, hours, minutes, seconds, milliseconds);
TRY(IFile_Open(&file, archiveId, fsMakePath(PATH_EMPTY, ""), fsMakePath(PATH_ASCII, filename), FS_OPEN_CREATE | FS_OPEN_WRITE)); TRY(IFile_Open(&file, archiveId, fsMakePath(PATH_EMPTY, ""), fsMakePath(PATH_ASCII, filename), FS_OPEN_CREATE | FS_OPEN_WRITE));
TRY(RosalinaMenu_WriteScreenshot(&file, false, true)); TRY(RosalinaMenu_WriteScreenshot(&file, bottomWidth, false, true));
TRY(IFile_Close(&file)); TRY(IFile_Close(&file));
if((GPU_FB_TOP_FMT & 0x20) && (Draw_GetCurrentFramebufferAddress(true, true) != Draw_GetCurrentFramebufferAddress(true, false))) if(is3d && (Draw_GetCurrentFramebufferAddress(true, true) != Draw_GetCurrentFramebufferAddress(true, false)))
{ {
sprintf(filename, "/luma/screenshots/%04lu-%02lu-%02lu_%02lu-%02lu-%02lu.%03llu_top_right.bmp", year, month, days, hours, minutes, seconds, milliseconds); sprintf(filename, "/luma/screenshots/%04lu-%02lu-%02lu_%02lu-%02lu-%02lu.%03llu_top_right.bmp", year, month, days, hours, minutes, seconds, milliseconds);
TRY(IFile_Open(&file, archiveId, fsMakePath(PATH_EMPTY, ""), fsMakePath(PATH_ASCII, filename), FS_OPEN_CREATE | FS_OPEN_WRITE)); TRY(IFile_Open(&file, archiveId, fsMakePath(PATH_EMPTY, ""), fsMakePath(PATH_ASCII, filename), FS_OPEN_CREATE | FS_OPEN_WRITE));
TRY(RosalinaMenu_WriteScreenshot(&file, true, false)); TRY(RosalinaMenu_WriteScreenshot(&file, topWidth, true, false));
TRY(IFile_Close(&file)); TRY(IFile_Close(&file));
} }
end: end:
IFile_Close(&file); IFile_Close(&file);
if (R_FAILED(Draw_AllocateFramebufferCache(FB_BOTTOM_SIZE)))
__builtin_trap(); // We're f***ed if this happens
svcFlushEntireDataCache(); svcFlushEntireDataCache();
Draw_SetupFramebuffer(); Draw_SetupFramebuffer();
Draw_Unlock(); Draw_Unlock();

View File

@@ -102,7 +102,6 @@ Result debuggerDisable(s64 timeout)
svcCloseHandle(dummy); svcCloseHandle(dummy);
PMDBG_DebugNextApplicationByForce(false); PMDBG_DebugNextApplicationByForce(false);
nextApplicationGdbCtx = NULL; nextApplicationGdbCtx = NULL;
svcKernelSetState(0x10000, 2);
} }
return res; return res;

View File

@@ -31,7 +31,6 @@
#include "memory.h" #include "memory.h"
#include "draw.h" #include "draw.h"
#include "hbloader.h" #include "hbloader.h"
#include "plgloader.h"
#include "fmt.h" #include "fmt.h"
#include "utils.h" // for makeArmBranch #include "utils.h" // for makeArmBranch
#include "minisoc.h" #include "minisoc.h"
@@ -55,7 +54,7 @@ void MiscellaneousMenu_SwitchBoot3dsxTargetTitle(void)
Result res; Result res;
char failureReason[64]; char failureReason[64];
if(HBLDR_3DSX_TID == HBLDR_DEFAULT_3DSX_TID) if(Luma_SharedConfig->hbldr_3dsx_tid == HBLDR_DEFAULT_3DSX_TID)
{ {
FS_ProgramInfo progInfo; FS_ProgramInfo progInfo;
u32 pid; u32 pid;
@@ -63,7 +62,7 @@ void MiscellaneousMenu_SwitchBoot3dsxTargetTitle(void)
res = PMDBG_GetCurrentAppInfo(&progInfo, &pid, &launchFlags); res = PMDBG_GetCurrentAppInfo(&progInfo, &pid, &launchFlags);
if(R_SUCCEEDED(res)) if(R_SUCCEEDED(res))
{ {
HBLDR_3DSX_TID = progInfo.programId; Luma_SharedConfig->hbldr_3dsx_tid = progInfo.programId;
miscellaneousMenu.items[0].title = "Switch the hb. title to hblauncher_loader"; miscellaneousMenu.items[0].title = "Switch the hb. title to hblauncher_loader";
} }
else else
@@ -75,7 +74,7 @@ void MiscellaneousMenu_SwitchBoot3dsxTargetTitle(void)
else else
{ {
res = 0; res = 0;
HBLDR_3DSX_TID = HBLDR_DEFAULT_3DSX_TID; Luma_SharedConfig->hbldr_3dsx_tid = HBLDR_DEFAULT_3DSX_TID;
miscellaneousMenu.items[0].title = "Switch the hb. title to the current app."; miscellaneousMenu.items[0].title = "Switch the hb. title to the current app.";
} }
@@ -165,7 +164,7 @@ void MiscellaneousMenu_ChangeMenuCombo(void)
while(!(waitInput() & KEY_B) && !menuShouldExit); while(!(waitInput() & KEY_B) && !menuShouldExit);
} }
Result SaveSettings(void) void MiscellaneousMenu_SaveSettings(void)
{ {
Result res; Result res;
@@ -180,14 +179,12 @@ Result SaveSettings(void)
u32 config, multiConfig, bootConfig; u32 config, multiConfig, bootConfig;
u64 hbldr3dsxTitleId; u64 hbldr3dsxTitleId;
u32 rosalinaMenuCombo; u32 rosalinaMenuCombo;
u32 rosalinaFlags;
} configData; } configData;
u32 formatVersion; u32 formatVersion;
u32 config, multiConfig, bootConfig; u32 config, multiConfig, bootConfig;
s64 out; s64 out;
bool isSdMode; bool isSdMode;
if(R_FAILED(svcGetSystemInfo(&out, 0x10000, 2))) svcBreak(USERBREAK_ASSERT); if(R_FAILED(svcGetSystemInfo(&out, 0x10000, 2))) svcBreak(USERBREAK_ASSERT);
formatVersion = (u32)out; formatVersion = (u32)out;
if(R_FAILED(svcGetSystemInfo(&out, 0x10000, 3))) svcBreak(USERBREAK_ASSERT); if(R_FAILED(svcGetSystemInfo(&out, 0x10000, 3))) svcBreak(USERBREAK_ASSERT);
@@ -205,9 +202,8 @@ Result SaveSettings(void)
configData.config = config; configData.config = config;
configData.multiConfig = multiConfig; configData.multiConfig = multiConfig;
configData.bootConfig = bootConfig; configData.bootConfig = bootConfig;
configData.hbldr3dsxTitleId = HBLDR_3DSX_TID; configData.hbldr3dsxTitleId = Luma_SharedConfig->hbldr_3dsx_tid;
configData.rosalinaMenuCombo = menuCombo; configData.rosalinaMenuCombo = menuCombo;
configData.rosalinaFlags = PluginLoader__IsEnabled();
FS_ArchiveID archiveId = isSdMode ? ARCHIVE_SDMC : ARCHIVE_NAND_RW; FS_ArchiveID archiveId = isSdMode ? ARCHIVE_SDMC : ARCHIVE_NAND_RW;
res = IFile_Open(&file, archiveId, fsMakePath(PATH_EMPTY, ""), fsMakePath(PATH_ASCII, "/luma/config.bin"), FS_OPEN_CREATE | FS_OPEN_WRITE); res = IFile_Open(&file, archiveId, fsMakePath(PATH_EMPTY, ""), fsMakePath(PATH_ASCII, "/luma/config.bin"), FS_OPEN_CREATE | FS_OPEN_WRITE);
@@ -215,14 +211,6 @@ Result SaveSettings(void)
if(R_SUCCEEDED(res)) if(R_SUCCEEDED(res))
res = IFile_Write(&file, &total, &configData, sizeof(configData), 0); res = IFile_Write(&file, &total, &configData, sizeof(configData), 0);
IFile_Close(&file);
return res;
}
void MiscellaneousMenu_SaveSettings(void)
{
Result res = SaveSettings();
Draw_Lock(); Draw_Lock();
Draw_ClearFramebuffer(); Draw_ClearFramebuffer();
Draw_FlushFramebuffer(); Draw_FlushFramebuffer();
@@ -331,7 +319,21 @@ void MiscellaneousMenu_InputRedirection(void)
else else
{ {
if(res == 0) if(res == 0)
Draw_DrawString(10, 30, COLOR_WHITE, "InputRedirection stopped successfully."); {
u32 posY = 30;
posY = Draw_DrawString(10, posY, COLOR_WHITE, "InputRedirection stopped successfully.\n\n");
if (isN3DS)
{
posY = Draw_DrawString(
10,
posY,
COLOR_WHITE,
"This might cause a key press to be repeated in\n"
"Home Menu for no reason.\n\n"
"Just pressing ZL/ZR on the console is enough to fix\nthis.\n"
);
}
}
else else
Draw_DrawString(10, 30, COLOR_WHITE, buf); Draw_DrawString(10, 30, COLOR_WHITE, buf);
} }

View File

@@ -233,8 +233,8 @@ static void ProcessListMenu_MemoryViewer(const ProcessInfo *info)
svcQueryProcessMemory(&mem, &out, processHandle, heapStartAddress); svcQueryProcessMemory(&mem, &out, processHandle, heapStartAddress);
heapTotalSize = mem.size; heapTotalSize = mem.size;
Result codeRes = svcMapProcessMemoryEx(CUR_PROCESS_HANDLE, codeDestAddress, processHandle, codeStartAddress, codeTotalSize); Result codeRes = svcMapProcessMemoryEx(processHandle, codeDestAddress, codeStartAddress, codeTotalSize);
Result heapRes = svcMapProcessMemoryEx(CUR_PROCESS_HANDLE, heapDestAddress, processHandle, heapStartAddress, heapTotalSize); Result heapRes = svcMapProcessMemoryEx(processHandle, heapDestAddress, heapStartAddress, heapTotalSize);
bool codeAvailable = R_SUCCEEDED(codeRes); bool codeAvailable = R_SUCCEEDED(codeRes);
bool heapAvailable = R_SUCCEEDED(heapRes); bool heapAvailable = R_SUCCEEDED(heapRes);
@@ -575,9 +575,9 @@ static void ProcessListMenu_MemoryViewer(const ProcessInfo *info)
} }
if(codeAvailable) if(codeAvailable)
svcUnmapProcessMemoryEx(CUR_PROCESS_HANDLE, codeDestAddress, codeTotalSize); svcUnmapProcessMemoryEx(processHandle, codeDestAddress, codeTotalSize);
if(heapAvailable) if(heapAvailable)
svcUnmapProcessMemoryEx(CUR_PROCESS_HANDLE, heapDestAddress, heapTotalSize); svcUnmapProcessMemoryEx(processHandle, heapDestAddress, heapTotalSize);
svcCloseHandle(processHandle); svcCloseHandle(processHandle);
} }

View File

@@ -32,33 +32,34 @@
#include "redshift/redshift.h" #include "redshift/redshift.h"
#include "redshift/colorramp.h" #include "redshift/colorramp.h"
#define TEMP_DEFAULT NEUTRAL_TEMP typedef union {
struct {
int screenFiltersCurrentTemperature = TEMP_DEFAULT; u8 r;
u8 g;
void writeLut(u32* lut) u8 b;
{ u8 z;
GPU_FB_TOP_COL_LUT_INDEX = 0; };
GPU_FB_BOTTOM_COL_LUT_INDEX = 0; u32 raw;
for (int i = 0; i <= 255; i++) {
GPU_FB_TOP_COL_LUT_ELEM = *lut;
GPU_FB_BOTTOM_COL_LUT_ELEM = *lut;
lut++;
}
}
typedef struct {
u8 r;
u8 g;
u8 b;
u8 z;
} Pixel; } Pixel;
static u16 g_c[0x600]; static u16 g_c[0x600];
static Pixel g_px[0x400]; static Pixel g_px[0x400];
void applyColorSettings(color_setting_t* cs) int screenFiltersCurrentTemperature = -1;
static void ScreenFiltersMenu_WriteLut(const Pixel* lut)
{
GPU_FB_TOP_COL_LUT_INDEX = 0;
GPU_FB_BOTTOM_COL_LUT_INDEX = 0;
for (int i = 0; i <= 255; i++) {
GPU_FB_TOP_COL_LUT_ELEM = lut->raw;
GPU_FB_BOTTOM_COL_LUT_ELEM = lut->raw;
lut++;
}
}
static void ScreenFiltersMenu_ApplyColorSettings(color_setting_t* cs)
{ {
u8 i = 0; u8 i = 0;
@@ -86,68 +87,69 @@ void applyColorSettings(color_setting_t* cs)
g_px[i].b = *(g_c + i + 0x200) >> 8; g_px[i].b = *(g_c + i + 0x200) >> 8;
} while(++i); } while(++i);
writeLut((u32*)g_px); ScreenFiltersMenu_WriteLut(g_px);
} }
Menu screenFiltersMenu = { static void ScreenFiltersMenu_SetCct(int cct)
"Screen filters menu",
{
{ "Disable", METHOD, .method = &screenFiltersSetDisabled },
{ "Reduce blue light (level 1)", METHOD, .method = &screenFiltersReduceBlueLevel1 },
{ "Reduce blue light (level 2)", METHOD, .method = &screenFiltersReduceBlueLevel2 },
{ "Reduce blue light (level 3)", METHOD, .method = &screenFiltersReduceBlueLevel3 },
{ "Reduce blue light (level 4)", METHOD, .method = &screenFiltersReduceBlueLevel4 },
{ "Reduce blue light (level 5)", METHOD, .method = &screenFiltersReduceBlueLevel5 },
{},
}
};
void screenFiltersSetDisabled(void)
{
screenFiltersCurrentTemperature = TEMP_DEFAULT;
screenFiltersSetTemperature(screenFiltersCurrentTemperature);
}
void screenFiltersReduceBlueLevel1(void)
{
screenFiltersCurrentTemperature = 4300;
screenFiltersSetTemperature(screenFiltersCurrentTemperature);
}
void screenFiltersReduceBlueLevel2(void)
{
screenFiltersCurrentTemperature = 3200;
screenFiltersSetTemperature(screenFiltersCurrentTemperature);
}
void screenFiltersReduceBlueLevel3(void)
{
screenFiltersCurrentTemperature = 2100;
screenFiltersSetTemperature(screenFiltersCurrentTemperature);
}
void screenFiltersReduceBlueLevel4(void)
{
screenFiltersCurrentTemperature = 1550;
screenFiltersSetTemperature(screenFiltersCurrentTemperature);
}
void screenFiltersReduceBlueLevel5(void)
{
screenFiltersCurrentTemperature = 1000;
screenFiltersSetTemperature(screenFiltersCurrentTemperature);
}
void screenFiltersSetTemperature(int temperature)
{ {
color_setting_t cs; color_setting_t cs;
memset(&cs, 0, sizeof(cs)); memset(&cs, 0, sizeof(cs));
cs.temperature = temperature; cs.temperature = cct;
/*cs.gamma[0] = 1.0F; /*cs.gamma[0] = 1.0F;
cs.gamma[1] = 1.0F; cs.gamma[1] = 1.0F;
cs.gamma[2] = 1.0F; cs.gamma[2] = 1.0F;
cs.brightness = 1.0F;*/ cs.brightness = 1.0F;*/
applyColorSettings(&cs); ScreenFiltersMenu_ApplyColorSettings(&cs);
} }
Menu screenFiltersMenu = {
"Screen filters menu",
{
{ "[6500K] Default", METHOD, .method = &ScreenFiltersMenu_SetDefault },
{ "[10000K] Aquarium", METHOD, .method = &ScreenFiltersMenu_SetAquarium },
{ "[7500K] Overcast Sky", METHOD, .method = &ScreenFiltersMenu_SetOvercastSky },
{ "[5500K] Daylight", METHOD, .method = &ScreenFiltersMenu_SetDaylight },
{ "[4200K] Fluorescent", METHOD, .method = &ScreenFiltersMenu_SetFluorescent },
{ "[3400K] Halogen", METHOD, .method = &ScreenFiltersMenu_SetHalogen },
{ "[2700K] Incandescent", METHOD, .method = &ScreenFiltersMenu_SetIncandescent },
{ "[2300K] Warm Incandescent", METHOD, .method = &ScreenFiltersMenu_SetWarmIncandescent },
{ "[1900K] Candle", METHOD, .method = &ScreenFiltersMenu_SetCandle },
{ "[2700K] Ember", METHOD, .method = &ScreenFiltersMenu_SetEmber },
{},
}
};
#define DEF_CCT_SETTER(temp, name)\
void ScreenFiltersMenu_Set##name(void)\
{\
screenFiltersCurrentTemperature = temp;\
ScreenFiltersMenu_SetCct(temp);\
}
void ScreenFiltersMenu_RestoreCct(void)
{
// Not initialized: return
if (screenFiltersCurrentTemperature == -1)
return;
// Wait for GSP to restore the CCT table
while (GPU_FB_TOP_COL_LUT_ELEM != g_px[0].raw)
svcSleepThread(10 * 1000 * 1000LL);
svcSleepThread(10 * 1000 * 1000LL);
ScreenFiltersMenu_WriteLut(g_px);
}
DEF_CCT_SETTER(6500, Default)
DEF_CCT_SETTER(10000, Aquarium)
DEF_CCT_SETTER(7500, OvercastSky)
DEF_CCT_SETTER(5500, Daylight)
DEF_CCT_SETTER(4200, Fluorescent)
DEF_CCT_SETTER(3400, Halogen)
DEF_CCT_SETTER(2700, Incandescent)
DEF_CCT_SETTER(2300, WarmIncandescent)
DEF_CCT_SETTER(1900, Candle)
DEF_CCT_SETTER(1200, Ember)

View File

@@ -35,10 +35,10 @@
Menu sysconfigMenu = { Menu sysconfigMenu = {
"System configuration menu", "System configuration menu",
{ {
{ "Control Wireless connection", METHOD, .method = &SysConfigMenu_ControlWifi },
{ "Toggle LEDs", METHOD, .method = &SysConfigMenu_ToggleLEDs }, { "Toggle LEDs", METHOD, .method = &SysConfigMenu_ToggleLEDs },
{ "Toggle Wireless", METHOD, .method = &SysConfigMenu_ToggleWireless }, { "Toggle Wireless", METHOD, .method = &SysConfigMenu_ToggleWireless },
{ "Toggle Power Button", METHOD, .method=&SysConfigMenu_TogglePowerButton }, { "Toggle Power Button", METHOD, .method=&SysConfigMenu_TogglePowerButton },
{ "Control Wireless connection", METHOD, .method = &SysConfigMenu_ControlWifi },
{}, {},
} }
}; };

View File

@@ -1,3 +1,4 @@
/* /*
* This file is part of Luma3DS. * This file is part of Luma3DS.
* Copyright (C) 2016-2020 Aurora Wright, TuxSH * Copyright (C) 2016-2020 Aurora Wright, TuxSH
@@ -7,18 +8,16 @@
#include "minisoc.h" #include "minisoc.h"
#include <sys/socket.h> #include <sys/socket.h>
#include <3ds/ipc.h> #include <3ds.h>
#include <3ds/os.h>
#include <3ds/synchronization.h>
#include <3ds/result.h>
#include <string.h> #include <string.h>
#include "csvc.h" #include "utils.h"
s32 miniSocRefCount = 0; s32 miniSocRefCount = 0;
static u32 socContextAddr = 0x08000000; static u32 socContextAddr = 0x08000000;
static u32 socContextSize = 0x60000; static u32 socContextSize = 0x60000;
static Handle miniSocHandle; static Handle miniSocHandle;
static Handle miniSocMemHandle; static Handle miniSocMemHandle;
static bool exclusiveStateEntered = false;
bool miniSocEnabled = false; bool miniSocEnabled = false;
@@ -56,6 +55,41 @@ static Result SOCU_Shutdown(void)
return cmdbuf[1]; return cmdbuf[1];
} }
// unsafe but what can I do?
void miniSocLockState(void)
{
Result res = 0;
__dmb();
if (!exclusiveStateEntered && isServiceUsable("ndm:u"))
{
ndmuInit();
res = NDMU_EnterExclusiveState(NDM_EXCLUSIVE_STATE_INFRASTRUCTURE);
if (R_SUCCEEDED(res))
res = NDMU_LockState(); // prevents ndm from switching to StreetPass when the lid is closed
exclusiveStateEntered = R_SUCCEEDED(res);
__dmb();
}
}
void miniSocUnlockState(bool force)
{
Result res = 0;
__dmb();
if (exclusiveStateEntered)
{
if (!force)
{
res = NDMU_UnlockState();
if (R_SUCCEEDED(res))
res = NDMU_LeaveExclusiveState();
}
ndmuExit();
exclusiveStateEntered = R_FAILED(res);
__dmb();
}
}
Result miniSocInit(void) Result miniSocInit(void)
{ {
if(AtomicPostIncrement(&miniSocRefCount)) if(AtomicPostIncrement(&miniSocRefCount))
@@ -89,8 +123,11 @@ Result miniSocInit(void)
ret = SOCU_Initialize(miniSocMemHandle, socContextSize); ret = SOCU_Initialize(miniSocMemHandle, socContextSize);
if(ret != 0) goto cleanup; if(ret != 0) goto cleanup;
svcKernelSetState(0x10000, 2); miniSocLockState();
svcKernelSetState(0x10000, 0x10);
miniSocEnabled = true; miniSocEnabled = true;
return 0; return 0;
cleanup: cleanup:
@@ -117,7 +154,6 @@ cleanup:
Result miniSocExitDirect(void) Result miniSocExitDirect(void)
{ {
//if (miniSocRefCount != 0) __builtin_trap();
Result ret = 0; Result ret = 0;
u32 tmp; u32 tmp;
@@ -132,8 +168,10 @@ Result miniSocExitDirect(void)
svcControlMemory(&tmp, socContextAddr, socContextAddr, socContextSize, MEMOP_FREE, MEMPERM_DONTCARE); svcControlMemory(&tmp, socContextAddr, socContextAddr, socContextSize, MEMOP_FREE, MEMPERM_DONTCARE);
if(ret == 0) if(ret == 0)
{ {
svcKernelSetState(0x10000, 2); miniSocUnlockState(false);
miniSocEnabled = false; miniSocEnabled = false;
svcKernelSetState(0x10000, 0x10);
} }
return ret; return ret;
} }

View File

@@ -1,143 +0,0 @@
#include <3ds.h>
#include "plgldr.h"
#include <string.h>
static Handle plgLdrHandle;
static int plgLdrRefCount;
Result plgLdrInit(void)
{
Result res = 0;
if (AtomicPostIncrement(&plgLdrRefCount) == 0)
res = svcConnectToPort(&plgLdrHandle, "plg:ldr");
if (R_FAILED(res))
AtomicDecrement(&plgLdrRefCount);
return res;
}
void plgLdrExit(void)
{
if (AtomicDecrement(&plgLdrRefCount))
return;
svcCloseHandle(plgLdrHandle);
}
Result PLGLDR__IsPluginLoaderEnabled(bool *isEnabled)
{
Result res = 0;
u32 *cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(2, 0, 0);
if (R_SUCCEEDED((res = svcSendSyncRequest(plgLdrHandle))))
{
res = cmdbuf[1];
*isEnabled = cmdbuf[2];
}
return res;
}
Result PLGLDR__SetPluginLoaderState(bool enabled)
{
Result res = 0;
u32 *cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(3, 1, 0);
cmdbuf[1] = (u32)enabled;
if (R_SUCCEEDED((res = svcSendSyncRequest(plgLdrHandle))))
{
res = cmdbuf[1];
}
return res;
}
Result PLGLDR__SetPluginLoadParameters(PluginLoadParameters *parameters)
{
Result res = 0;
u32 *cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(4, 2, 4);
cmdbuf[1] = (u32)parameters->noFlash;
cmdbuf[2] = parameters->lowTitleId;
cmdbuf[3] = IPC_Desc_Buffer(256, IPC_BUFFER_R);
cmdbuf[4] = (u32)parameters->path;
cmdbuf[5] = IPC_Desc_Buffer(32 * sizeof(u32), IPC_BUFFER_R);
cmdbuf[6] = (u32)parameters->config;
if (R_SUCCEEDED((res = svcSendSyncRequest(plgLdrHandle))))
{
res = cmdbuf[1];
}
return res;
}
Result PLGLDR__DisplayMenu(PluginMenu *menu)
{
Result res = 0;
u32 nbItems = menu->nbItems;
u32 *cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(5, 1, 8);
cmdbuf[1] = nbItems;
cmdbuf[2] = IPC_Desc_Buffer(nbItems, IPC_BUFFER_RW);
cmdbuf[3] = (u32)menu->states;
cmdbuf[4] = IPC_Desc_Buffer(MAX_BUFFER, IPC_BUFFER_R);
cmdbuf[5] = (u32)menu->title;
cmdbuf[6] = IPC_Desc_Buffer(MAX_BUFFER * nbItems, IPC_BUFFER_R);
cmdbuf[7] = (u32)menu->items;
cmdbuf[8] = IPC_Desc_Buffer(MAX_BUFFER * nbItems, IPC_BUFFER_R);
cmdbuf[9] = (u32)menu->hints;
if (R_SUCCEEDED((res = svcSendSyncRequest(plgLdrHandle))))
{
res = cmdbuf[1];
}
return res;
}
Result PLGLDR__DisplayMessage(const char *title, const char *body)
{
Result res = 0;
u32 *cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(6, 0, 4);
cmdbuf[1] = IPC_Desc_Buffer(strlen(title), IPC_BUFFER_R);
cmdbuf[2] = (u32)title;
cmdbuf[3] = IPC_Desc_Buffer(strlen(body), IPC_BUFFER_R);
cmdbuf[4] = (u32)body;
if (R_SUCCEEDED((res = svcSendSyncRequest(plgLdrHandle))))
{
res = cmdbuf[1];
}
return res;
}
Result PLGLDR__DisplayErrMessage(const char *title, const char *body, u32 error)
{
Result res = 0;
u32 *cmdbuf = getThreadCommandBuffer();
cmdbuf[0] = IPC_MakeHeader(7, 1, 4);
cmdbuf[1] = error;
cmdbuf[2] = IPC_Desc_Buffer(strlen(title), IPC_BUFFER_R);
cmdbuf[3] = (u32)title;
cmdbuf[4] = IPC_Desc_Buffer(strlen(body), IPC_BUFFER_R);
cmdbuf[5] = (u32)body;
if (R_SUCCEEDED((res = svcSendSyncRequest(plgLdrHandle))))
{
res = cmdbuf[1];
}
return res;
}

View File

@@ -1,599 +0,0 @@
#include <3ds.h>
#include "3gx.h"
#include "ifile.h"
#include "utils.h" // for makeARMBranch
#include "plgloader.h"
#include "fmt.h"
#include "menu.h"
#include "menus.h"
#include "memory.h"
#include "sleep.h"
#define MEMPERM_RW (MEMPERM_READ | MEMPERM_WRITE)
#define MemBlockSize (5*1024*1024) /* 5 MiB */
typedef struct
{
Result code;
const char * message;
} Error;
typedef struct
{
bool isEnabled;
bool noFlash;
u32 titleid;
char path[256];
u32 config[32];
} PluginLoadParameters;
#define HeaderMagic (0x24584733) /* "3GX$" */
typedef struct
{
u32 magic;
u32 version;
u32 heapVA;
u32 heapSize;
u32 pluginSize;
const char* pluginPathPA;
u32 isDefaultPlugin;
u32 reserved[25];
u32 config[32];
} PluginHeader;
static bool g_isEnabled;
static u8 * g_memBlock;
static char g_path[256];
static Handle g_process = 0;
static u32 g_codeSize;
static u32 g_heapSize;
static Error g_error;
static PluginLoadParameters g_userDefinedLoadParameters;
static MyThread g_pluginLoaderThread;
static u8 ALIGN(8) g_pluginLoaderThreadStack[0x4000];
// pluginLoader.s
void gamePatchFunc(void);
void PluginLoader__ThreadMain(void);
MyThread * PluginLoader__CreateThread(void)
{
s64 out;
svcGetSystemInfo(&out, 0x10000, 0x102);
g_isEnabled = out & 1;
g_userDefinedLoadParameters.isEnabled = false;
if(R_FAILED(MyThread_Create(&g_pluginLoaderThread, PluginLoader__ThreadMain, g_pluginLoaderThreadStack, 0x4000, 20, CORE_SYSTEM)))
svcBreak(USERBREAK_PANIC);
return &g_pluginLoaderThread;
}
bool PluginLoader__IsEnabled(void)
{
return g_isEnabled;
}
void PluginLoader__MenuCallback(void)
{
g_isEnabled = !g_isEnabled;
SaveSettings();
PluginLoader__UpdateMenu();
}
void PluginLoader__UpdateMenu(void)
{
static const char *status[2] =
{
"Plugin Loader: [Disabled]",
"Plugin Loader: [Enabled]"
};
rosalinaMenu.items[isN3DS + 1].title = status[g_isEnabled];
}
static Result MapPluginInProcess(Handle proc, u32 size)
{
u32 heapsize = MemBlockSize - size;
Result res;
PluginHeader *header = (PluginHeader *)g_memBlock;
header->heapVA = 0x06000000;
g_heapSize = header->heapSize = heapsize;
g_codeSize = size;
// From now on, all memory page mapped to the process should be rwx
svcControlProcess(proc, PROCESSOP_SET_MMU_TO_RWX, 0, 0);
// Plugin
if (R_FAILED((res = svcMapProcessMemoryEx(proc, 0x07000000, CUR_PROCESS_HANDLE, (u32)g_memBlock, size))))
{
g_error.message = "Couldn't map plugin memory block";
g_error.code = res;
return res;
}
// Heap (to be used by the plugin)
if (R_FAILED((res = svcMapProcessMemoryEx(proc, 0x06000000, CUR_PROCESS_HANDLE, (u32)g_memBlock + size, heapsize))))
{
g_error.message = "Couldn't map heap memory block";
g_error.code = res;
goto exit;
}
// Clear heap section
memset32(g_memBlock + size, 0, heapsize);
exit:
return res;
}
static u32 strlen16(const u16 *str)
{
u32 size = 0;
while (str && *str++) ++size;
return size;
}
static Result FindPluginFile(u64 tid)
{
char filename[256];
u32 entriesNb = 0;
bool found = false;
Handle dir = 0;
Result res;
FS_Archive sdmcArchive = 0;
FS_DirectoryEntry entries[10];
sprintf(g_path, "/luma/plugins/%016llX", tid);
if (R_FAILED((res =FSUSER_OpenArchive(&sdmcArchive, ARCHIVE_SDMC, fsMakePath(PATH_EMPTY, "")))))
goto exit;
if (R_FAILED((res = FSUSER_OpenDirectory(&dir, sdmcArchive, fsMakePath(PATH_ASCII, g_path)))))
goto exit;
strcat(g_path, "/");
while (!found && R_SUCCEEDED(FSDIR_Read(dir, &entriesNb, 10, entries)))
{
if (entriesNb == 0)
break;
static const u16 * validExtension = u"3gx";
for (u32 i = 0; i < entriesNb; ++i)
{
FS_DirectoryEntry *entry = &entries[i];
// If entry is a folder, skip it
if (entry->attributes & 1)
continue;
// Check extension
u32 size = strlen16(entry->name);
if (size <= 5)
continue;
u16 *fileExt = entry->name + size - 3;
if (memcmp(fileExt, validExtension, 3 * sizeof(u16)))
continue;
// Convert name from utf16 to utf8
int units = utf16_to_utf8((u8 *)filename, entry->name, 100);
if (units == -1)
continue;
filename[units] = 0;
found = true;
break;
}
}
if (!found)
res = MAKERESULT(28, 4, 0, 1018);
else
{
u32 len = strlen(g_path);
filename[256 - len] = 0;
strcat(g_path, filename);
}
((PluginHeader *)g_memBlock)->pluginPathPA = PA_FROM_VA_PTR(g_path);
exit:
FSDIR_Close(dir);
FSUSER_CloseArchive(sdmcArchive);
return res;
}
static Result OpenFile(IFile *file, const char *path)
{
return IFile_Open(file, ARCHIVE_SDMC, fsMakePath(PATH_EMPTY, ""), fsMakePath(PATH_ASCII, path), FS_OPEN_READ);
}
static Result CheckPluginCompatibility(_3gx_Header *header, u32 processTitle)
{
static char errorBuf[0x100];
if (header->targets.count == 0)
return 0;
for (u32 i = 0; i < header->targets.count; ++i)
{
if (header->targets.titles[i] == processTitle)
return 0;
}
sprintf(errorBuf, "The plugin - %s -\nis not compatible with this game.\n" \
"Contact \"%s\" for more infos.", header->infos.titleMsg, header->infos.authorMsg);
g_error.message = errorBuf;
return -1;
}
static bool TryToLoadPlugin(Handle process)
{
u64 fileSize;
u64 tid;
u32 procStart = 0x00100000;
IFile plugin;
PluginHeader *hdr = (PluginHeader *)g_memBlock;
_3gx_Header *header;
Result res;
// Clear the memblock
memset32(g_memBlock, 0, MemBlockSize);
hdr->magic = HeaderMagic;
// Get title id
svcGetProcessInfo((s64 *)&tid, process, 0x10001);
if (R_FAILED((res = svcMapProcessMemoryEx(CUR_PROCESS_HANDLE, procStart, process, procStart, 0x1000))))
{
g_error.message = "Couldn't map process";
g_error.code = res;
return false;
}
// Try to open plugin file
if (g_userDefinedLoadParameters.isEnabled && (u32)tid == g_userDefinedLoadParameters.titleid)
{
g_userDefinedLoadParameters.isEnabled = false;
if (OpenFile(&plugin, g_userDefinedLoadParameters.path))
goto exitFail;
hdr->pluginPathPA = PA_FROM_VA_PTR(g_userDefinedLoadParameters.path);
memcpy(hdr->config, g_userDefinedLoadParameters.config, 32 * sizeof(u32));
}
else
{
if (R_FAILED(FindPluginFile(tid)) || OpenFile(&plugin, g_path))
{
// Try to open default plugin
const char *defaultPath = "/luma/plugins/default.3gx";
if (OpenFile(&plugin, defaultPath))
goto exitFail;
hdr->isDefaultPlugin = 1;
hdr->pluginPathPA = PA_FROM_VA_PTR(defaultPath);
}
}
if (R_FAILED((res = IFile_GetSize(&plugin, &fileSize))))
g_error.message = "Couldn't get file size";
// Plugins will rarely exceed 1MB so this is fine
header = (_3gx_Header *)(g_memBlock + MemBlockSize - (u32)fileSize);
// Read header
if (!res && R_FAILED((res = Read_3gx_Header(&plugin, header))))
g_error.message = "Couldn't read file";
// Check titles compatibility
if (!res) res = CheckPluginCompatibility(header, (u32)tid);
// Read code
if (!res && R_FAILED(res = Read_3gx_Code(&plugin, header, g_memBlock + sizeof(PluginHeader))))
g_error.message = "Couldn't read plugin's code";
// Close file
IFile_Close(&plugin);
if (R_FAILED(res))
{
g_error.code = res;
goto exitFail;
}
hdr->version = header->version;
// Code size must be page aligned
fileSize = (header->codeSize + 0x1100) & ~0xFFF;
if (MapPluginInProcess(process, fileSize) == 0)
// Install hook
{
extern u32 g_savedGameInstr[2];
u32 *game = (u32 *)procStart;
g_savedGameInstr[0] = game[0];
g_savedGameInstr[1] = game[1];
game[0] = 0xE51FF004; // ldr pc, [pc, #-4]
game[1] = (u32)PA_FROM_VA_PTR(gamePatchFunc);
}
else
goto exitFail;
svcUnmapProcessMemoryEx(CUR_PROCESS_HANDLE, procStart, 0x1000);
return true;
exitFail:
svcUnmapProcessMemoryEx(CUR_PROCESS_HANDLE, procStart, 0x1000);
return false;
}
static void SetKernelConfigurationMemoryFlag(bool loaded)
{
u32 *flag = (u32 *)PA_FROM_VA_PTR(0x1FF800F0);
*flag = loaded;
}
static void PluginLoader_HandleCommands(void)
{
u32 *cmdbuf = getThreadCommandBuffer();
switch (cmdbuf[0] >> 16)
{
case 1: // Load plugin
{
if (cmdbuf[0] != IPC_MakeHeader(1, 0, 2))
{
error(cmdbuf, 0xD9001830);
break;
}
Handle process = cmdbuf[2];
if (g_isEnabled && TryToLoadPlugin(process))
{
if (!g_userDefinedLoadParameters.isEnabled && g_userDefinedLoadParameters.noFlash)
g_userDefinedLoadParameters.noFlash = false;
else
{
for (u32 i = 0; i < 64; i++)
{
REG32(0x10202204) = 0x01FF9933;
svcSleepThread(5000000);
}
REG32(0x10202204) = 0;
}
g_process = process;
}
else
svcCloseHandle(process);
cmdbuf[0] = IPC_MakeHeader(1, 1, 0);
cmdbuf[1] = 0;
break;
}
case 2: // Check if plugin loader is enabled
{
if (cmdbuf[0] != IPC_MakeHeader(2, 0, 0))
{
error(cmdbuf, 0xD9001830);
break;
}
cmdbuf[0] = IPC_MakeHeader(2, 2, 0);
cmdbuf[1] = 0;
cmdbuf[2] = (u32)g_isEnabled;
break;
}
case 3: // Enable / Disable plugin loader
{
if (cmdbuf[0] != IPC_MakeHeader(3, 1, 0))
{
error(cmdbuf, 0xD9001830);
break;
}
if (cmdbuf[1] != g_isEnabled)
{
g_isEnabled = cmdbuf[1];
SaveSettings();
}
cmdbuf[0] = IPC_MakeHeader(3, 1, 0);
cmdbuf[1] = 0;
break;
}
case 4: // Define next plugin load settings
{
if (cmdbuf[0] != IPC_MakeHeader(4, 2, 4))
{
error(cmdbuf, 0xD9001830);
break;
}
g_userDefinedLoadParameters.isEnabled = true;
g_userDefinedLoadParameters.noFlash = cmdbuf[1];
g_userDefinedLoadParameters.titleid = cmdbuf[2];
strncpy(g_userDefinedLoadParameters.path, (const char *)cmdbuf[4], 255);
memcpy(g_userDefinedLoadParameters.config, (void *)cmdbuf[6], 32 * sizeof(u32));
cmdbuf[0] = IPC_MakeHeader(4, 1, 0);
cmdbuf[1] = 0;
break;
}
case 5: // Display menu
{
if (cmdbuf[0] != IPC_MakeHeader(5, 1, 8))
{
error(cmdbuf, 0xD9001830);
break;
}
u32 nbItems = cmdbuf[1];
u32 states = cmdbuf[3];
DisplayPluginMenu(cmdbuf);
cmdbuf[0] = IPC_MakeHeader(5, 1, 2);
cmdbuf[1] = 0;
cmdbuf[2] = IPC_Desc_Buffer(nbItems, IPC_BUFFER_RW);
cmdbuf[3] = states;
break;
}
case 6: // Display message
{
if (cmdbuf[0] != IPC_MakeHeader(6, 0, 4))
{
error(cmdbuf, 0xD9001830);
break;
}
const char *title = (const char *)cmdbuf[2];
const char *body = (const char *)cmdbuf[4];
DispMessage(title, body);
cmdbuf[0] = IPC_MakeHeader(6, 1, 0);
cmdbuf[1] = 0;
break;
}
case 7: // Display error message
{
if (cmdbuf[0] != IPC_MakeHeader(7, 1, 4))
{
error(cmdbuf, 0xD9001830);
break;
}
const char *title = (const char *)cmdbuf[3];
const char *body = (const char *)cmdbuf[5];
DispErrMessage(title, body, cmdbuf[1]);
cmdbuf[0] = IPC_MakeHeader(7, 1, 0);
cmdbuf[1] = 0;
break;
}
}
}
void PluginLoader__ThreadMain(void)
{
const char *title = "Plugin loader";
Result res = 0;
MemOp memRegion = isN3DS ? MEMOP_REGION_BASE : MEMOP_REGION_SYSTEM;
Handle handles[3];
Handle serverHandle, clientHandle, sessionHandle = 0;
u32 *cmdbuf = getThreadCommandBuffer();
u32 replyTarget = 0;
u32 nbHandle;
s32 index;
// Wait for the system to be completely started
{
bool isAcuRegistered = false;
while (true)
{
if (R_SUCCEEDED(srvIsServiceRegistered(&isAcuRegistered, "ac:u"))
&& isAcuRegistered)
break;
svcSleepThread(100000);
}
}
// Init memory block to hold the plugin
{
u32 free = (u32)osGetMemRegionFree(memRegion);
u32 temp = 0;
svcControlMemoryEx(&temp, 0x00100000, 0, free - MemBlockSize, memRegion | MEMOP_ALLOC, MEMPERM_RW, true);
if (R_FAILED((res = svcControlMemoryEx((u32 *)&g_memBlock, 0x07000000, 0, MemBlockSize, memRegion | MEMOP_ALLOC, MEMPERM_RW, true))))
{
svcSleepThread(5000000000ULL); ///< Wait until the system started to display the error
DispErrMessage(title, "Couldn't allocate memblock", res);
return;
}
svcControlMemoryEx(&temp, (u32)temp, 0, MemBlockSize, memRegion | MEMOP_FREE, 0, true);
}
assertSuccess(svcCreatePort(&serverHandle, &clientHandle, "plg:ldr", 1));
do
{
g_error.message = NULL;
g_error.code = 0;
handles[0] = serverHandle;
handles[1] = sessionHandle == 0 ? g_process : sessionHandle;
handles[2] = g_process;
if(replyTarget == 0) // k11
cmdbuf[0] = 0xFFFF0000;
nbHandle = 1 + (sessionHandle != 0) + (g_process != 0);
res = svcReplyAndReceive(&index, handles, nbHandle, 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 if (index == 1 && handles[1] == sessionHandle)
{
PluginLoader_HandleCommands();
replyTarget = sessionHandle;
}
else ///< The process in which we injected the plugin is terminating
{
// Unmap plugin's memory before closing the process
svcUnmapProcessMemoryEx(g_process, 0x07000000, g_codeSize);
svcUnmapProcessMemoryEx(g_process, 0x06000000, g_heapSize);
svcCloseHandle(g_process);
g_process = 0;
}
}
if (g_error.message != NULL)
DispErrMessage(title, g_error.message, g_error.code);
SetKernelConfigurationMemoryFlag(g_process != 0);
} while(!preTerminationRequested);
svcCloseHandle(sessionHandle);
svcCloseHandle(clientHandle);
svcCloseHandle(serverHandle);
svcControlMemoryEx((u32 *)&g_memBlock, (u32)g_memBlock, 0, MemBlockSize, memRegion | MEMOP_FREE, 0, true);
}

View File

@@ -1,33 +0,0 @@
.section .data
.balign 4
.arm
.global gamePatchFunc
.type gamePatchFunc, %function
gamePatchFunc:
stmfd sp!, {r0-r12, lr}
mrs r0, cpsr
stmfd sp!, {r0}
adr r0, g_savedGameInstr
ldr r1, =0x00100000
ldr r2, [r0]
str r2, [r1]
ldr r2, [r0, #4]
str r2, [r1, #4]
svc 0x92
svc 0x94
startplugin:
ldr r5, =0x07000100
blx r5
exit:
ldmfd sp!, {r0}
msr cpsr, r0
ldmfd sp!, {r0-r12, lr}
ldr lr, =0x00100000
mov pc, lr
.global g_savedGameInstr
g_savedGameInstr:
.word 0, 0

View File

@@ -68,11 +68,11 @@ Result PatchProcessByName(const char *name, Result (*func)(u32 size))
s64 textTotalRoundedSize = 0, startAddress = 0; s64 textTotalRoundedSize = 0, startAddress = 0;
svcGetProcessInfo(&textTotalRoundedSize, processHandle, 0x10002); // only patch .text svcGetProcessInfo(&textTotalRoundedSize, processHandle, 0x10002); // only patch .text
svcGetProcessInfo(&startAddress, processHandle, 0x10005); svcGetProcessInfo(&startAddress, processHandle, 0x10005);
if(R_FAILED(res = svcMapProcessMemoryEx(CUR_PROCESS_HANDLE, 0x00100000, processHandle, (u32) startAddress, textTotalRoundedSize))) if(R_FAILED(res = svcMapProcessMemoryEx(processHandle, 0x00100000, (u32) startAddress, textTotalRoundedSize)))
return res; return res;
res = func(textTotalRoundedSize); res = func(textTotalRoundedSize);
svcUnmapProcessMemoryEx(CUR_PROCESS_HANDLE, 0x00100000, textTotalRoundedSize); svcUnmapProcessMemoryEx(processHandle, 0x00100000, textTotalRoundedSize);
return res; return res;
} }

View File

@@ -1,61 +0,0 @@
/*
* This file is part of Luma3DS
* Copyright (C) 2016-2018 Aurora Wright, TuxSH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
* * Requiring preservation of specified reasonable legal notices or
* author attributions in that material or in the Appropriate Legal
* Notices displayed by works containing it.
* * Prohibiting misrepresentation of the origin of that material,
* or requiring that modified versions of such material be marked in
* reasonable ways as different from the original version.
*/
#include <3ds.h>
static bool g_isSleeping = false;
static LightEvent g_onWakeUpEvent;
void Sleep__Init(void)
{
srvSubscribe(0x214); ///< Sleep entry
srvSubscribe(0x213); ///< Sleep exit
LightEvent_Init(&g_onWakeUpEvent, RESET_STICKY);
}
void Sleep__HandleNotification(u32 notifId)
{
if (notifId == 0x214) ///< Sleep entry
{
LightEvent_Clear(&g_onWakeUpEvent);
g_isSleeping = true;
}
else if (notifId == 0x213) ///< Sleep exit
{
g_isSleeping = false;
LightEvent_Signal(&g_onWakeUpEvent);
}
}
bool Sleep__Status(void)
{
if (g_isSleeping)
{
LightEvent_Wait(&g_onWakeUpEvent);
return true;
}
return false;
}

View File

@@ -9,12 +9,10 @@
#include <3ds/result.h> #include <3ds/result.h>
#include <3ds/svc.h> #include <3ds/svc.h>
#include <3ds/synchronization.h> #include <3ds/synchronization.h>
#include <3ds/services/ac.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include "memory.h" #include "memory.h"
#include "minisoc.h" #include "minisoc.h"
#include "sock_util.h" #include "sock_util.h"
#include "sleep.h"
extern Handle preTerminationEvent; extern Handle preTerminationEvent;
extern bool preTerminationRequested; extern bool preTerminationRequested;
@@ -187,14 +185,6 @@ void server_run(struct sock_server *serv)
for(nfds_t i = 0; i < serv->nfds; i++) for(nfds_t i = 0; i < serv->nfds; i++)
fds[i].revents = 0; fds[i].revents = 0;
if (Sleep__Status())
{
while (!Wifi__IsConnected()
&& serv->running && !preTerminationRequested)
svcSleepThread(1000000000ULL);
}
int pollres = socPoll(fds, serv->nfds, 50); int pollres = socPoll(fds, serv->nfds, 50);
if(server_should_exit(serv) || pollres < -10000) if(server_should_exit(serv) || pollres < -10000)
@@ -331,13 +321,3 @@ void server_finalize(struct sock_server *serv)
svcClearEvent(serv->started_event); svcClearEvent(serv->started_event);
svcCloseHandle(serv->started_event); svcCloseHandle(serv->started_event);
} }
bool Wifi__IsConnected(void)
{
u32 status = 0;
u32 wifistatus = 0;
acInit();
return R_SUCCEEDED(ACU_GetWifiStatus(&wifistatus)) && wifistatus > 0
&& R_SUCCEEDED(ACU_GetStatus(&status)) && status != 1;
}

View File

@@ -3,7 +3,7 @@ Open source replacement of the Arm11 SM system module.
This is licensed under the MIT license. This is licensed under the MIT license.
# Usage # Usage
To run this system module, use a recent release or commit of [Luma3DS](https://github.com/AuroraWright/Luma3DS/), build this project and copy sm.cxi to /luma/sysmodules/. To run this system module, use a recent release or commit of [Luma3DS](https://github.com/LumaTeam/Luma3DS/), build this project and copy sm.cxi to /luma/sysmodules/.
# Credits # Credits
Everyone that helped me fix some of stupid bugs I had been making: @fincs, @Hikari-chin, etc. Everyone that helped me fix some of stupid bugs I had been making: @fincs, @Hikari-chin, etc.

View File

@@ -8,6 +8,18 @@ This is part of 3ds_sm, which is licensed under the MIT license (see LICENSE for
#include "notifications.h" #include "notifications.h"
#include "processes.h" #include "processes.h"
#include <stdatomic.h>
static bool isNotificationInhibited(const ProcessData *processData, u32 notificationId)
{
(void)processData;
switch(notificationId)
{
default:
return false;
}
}
static bool doPublishNotification(ProcessData *processData, u32 notificationId, u32 flags) static bool doPublishNotification(ProcessData *processData, u32 notificationId, u32 flags)
{ {
if((flags & 1) && processData->nbPendingNotifications != 0) // only send if not already pending if((flags & 1) && processData->nbPendingNotifications != 0) // only send if not already pending
@@ -19,14 +31,6 @@ static bool doPublishNotification(ProcessData *processData, u32 notificationId,
} }
} }
// Handle special case for home button notifications on Mode3 O3DS with plugin loaded
if ((notificationId == 0x204 || notificationId == 0x205)
&& *(u32 *)0x1FF80030 == 3 && *(u32 *)0x1FF800F0)
{
svcKernelSetState(0x10007, 1);
return true;
}
if(processData->nbPendingNotifications < 0x10) if(processData->nbPendingNotifications < 0x10)
{ {
s32 count; s32 count;
@@ -126,7 +130,7 @@ Result PublishToSubscriber(u32 notificationId, u32 flags)
{ {
for(ProcessData *node = processDataInUseList.first; node != NULL; node = node->next) for(ProcessData *node = processDataInUseList.first; node != NULL; node = node->next)
{ {
if(!node->notificationEnabled) if(!node->notificationEnabled || isNotificationInhibited(node, notificationId))
continue; continue;
u16 i; u16 i;
@@ -146,7 +150,7 @@ Result PublishAndGetSubscriber(u32 *pidCount, u32 *pidList, u32 notificationId,
u32 nb = 0; u32 nb = 0;
for(ProcessData *node = processDataInUseList.first; node != NULL; node = node->next) for(ProcessData *node = processDataInUseList.first; node != NULL; node = node->next)
{ {
if(!node->notificationEnabled) if(!node->notificationEnabled || isNotificationInhibited(node, notificationId))
continue; continue;
u16 i; u16 i;

View File

@@ -17,3 +17,5 @@ Result PublishToSubscriber(u32 notificationId, u32 flags);
Result PublishAndGetSubscriber(u32 *pidCount, u32 *pidList, u32 notificationId, u32 flags); Result PublishAndGetSubscriber(u32 *pidCount, u32 *pidList, u32 notificationId, u32 flags);
Result PublishToProcess(Handle process, u32 notificationId); Result PublishToProcess(Handle process, u32 notificationId);
Result PublishToAll(u32 notificationId); Result PublishToAll(u32 notificationId);
Result AddToNdmuWorkaroundCount(s32 count);