Compare commits
1 Commits
3gx-master
...
v10.1.4
Author | SHA1 | Date | |
---|---|---|---|
243031aed7 |
17
.github/ISSUE_TEMPLATE/bug-report.md
vendored
17
.github/ISSUE_TEMPLATE/bug-report.md
vendored
@ -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/LumaTeam/Luma3DS/issues/752
|
-- Rosalina feature requests go here: https://github.com/AuroraWright/Luma3DS/issues/752
|
||||||
--
|
--
|
||||||
-- Also check the Wiki (https://github.com/LumaTeam/Luma3DS/wiki) before making an issue.
|
-- Also check the Wiki (https://github.com/AuroraWright/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/LumaTeam/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/AuroraWright/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:**
|
||||||
|
|
||||||
[New 2DS XL, New 3DS XL, New 3DS, Old 2DS, Old 3DS XL, Old 3DS]
|
[e.g. 2DS, New 3DS, 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.2 stable or if using non-releases specify the commit like this https://github.com/LumaTeam/Luma3DS/commit/0543c208fd154e6326ea5da8cbf66ffcbdef010c]
|
[e.g. v10.1.3 stable or if using non-releases specify the commit like this https://github.com/AuroraWright/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 on New 3DS (XL)/New 2DS XL.-->
|
<!--This option is only available for New 3DS/2DS.-->
|
||||||
|
|
||||||
--
|
--
|
||||||
|
|
||||||
@ -70,13 +70,12 @@ 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.-->
|
|
||||||
|
|
||||||
--
|
--
|
||||||
|
|
||||||
|
|
||||||
|
4
.gitignore
vendored
4
.gitignore
vendored
@ -13,12 +13,8 @@ exceptions/arm11/build
|
|||||||
*.d
|
*.d
|
||||||
*.elf
|
*.elf
|
||||||
*.cxi
|
*.cxi
|
||||||
*.3dsx
|
|
||||||
.DS_Store
|
.DS_Store
|
||||||
*.dmp
|
*.dmp
|
||||||
.project
|
.project
|
||||||
.cproject
|
.cproject
|
||||||
.settings
|
.settings
|
||||||
.idea/
|
|
||||||
|
|
||||||
Luma3DS*.zip
|
|
||||||
|
9
Makefile
9
Makefile
@ -15,10 +15,9 @@ 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 *.3dsx
|
@rm -rf *.firm *.zip
|
||||||
|
|
||||||
# boot.3dsx comes from https://github.com/fincs/new-hbmenu/releases
|
$(NAME)$(REVISION).zip: boot.firm exception_dump_parser
|
||||||
$(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)
|
||||||
@ -26,9 +25,5 @@ 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
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
### 3GX Plugin Edition
|
### 3GX Plugin Edition
|
||||||
This edition of **Luma3DS** allows the loading of **.3GX plugins** in Luma3DS, which are otherwise officially unsupported.
|
This edition of **Luma3DS** allows the loading of **.3GX plugins** in Luma3DS, which are otherwise officially unsupported.
|
||||||
|
|
||||||
**Warning!** This was a quick, unstable hotfix I published to get things to work while waiting for official updates. The official firmware has now been updated to include 3gx plugins too. Do NOT use this fork.
|
|
||||||
|
|
||||||
#
|
#
|
||||||
### How to install this Edition
|
### How to install this Edition
|
||||||
|
@ -34,8 +34,6 @@
|
|||||||
#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;
|
||||||
|
190
exception_dump_parser/luma3ds_exception_dump_parser/__main__.py
Executable file
190
exception_dump_parser/luma3ds_exception_dump_parser/__main__.py
Executable file
@ -0,0 +1,190 @@
|
|||||||
|
#!/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()
|
13
exception_dump_parser/setup.py
Normal file
13
exception_dump_parser/setup.py
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
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']},
|
||||||
|
)
|
@ -36,12 +36,11 @@ 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 rosalinaLockThreads(u32 mask);
|
void rosalinaLockAllThreads(void);
|
||||||
void rosalinaUnlockThreads(u32 mask);
|
void rosalinaUnlockAllThreads(void);
|
||||||
|
|
||||||
// Taken from ctrulib:
|
// Taken from ctrulib:
|
||||||
|
|
||||||
@ -50,11 +49,6 @@ 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");
|
||||||
|
@ -89,7 +89,7 @@ void signalSvcReturn(u8 *pageEnd)
|
|||||||
void postprocessSvc(void)
|
void postprocessSvc(void)
|
||||||
{
|
{
|
||||||
KThread *currentThread = currentCoreContext->objectContext.currentThread;
|
KThread *currentThread = currentCoreContext->objectContext.currentThread;
|
||||||
if(!currentThread->shallTerminate && rosalinaThreadLockPredicate(currentThread, rosalinaState & 5))
|
if(!currentThread->shallTerminate && rosalinaThreadLockPredicate(currentThread))
|
||||||
rosalinaRescheduleThread(currentThread, true);
|
rosalinaRescheduleThread(currentThread, true);
|
||||||
|
|
||||||
officialPostProcessSvc();
|
officialPostProcessSvc();
|
||||||
|
@ -5,13 +5,8 @@
|
|||||||
|
|
||||||
typedef bool (*ThreadPredicate)(KThread *thread);
|
typedef bool (*ThreadPredicate)(KThread *thread);
|
||||||
|
|
||||||
static void rosalinaLockThread(KThread *thread)
|
void rosalinaLockThread(KThread *thread);
|
||||||
{
|
void rosalinaRescheduleThread(KThread *thread, bool lock);
|
||||||
KThread *syncThread = synchronizationMutex->owner;
|
|
||||||
|
|
||||||
if(syncThread == NULL || syncThread != thread)
|
|
||||||
rosalinaRescheduleThread(thread, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result ControlProcess(Handle processHandle, ProcessOp op, u32 varg2, u32 varg3)
|
Result ControlProcess(Handle processHandle, ProcessOp op, u32 varg2, u32 varg3)
|
||||||
{
|
{
|
||||||
|
@ -105,22 +105,14 @@ 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 & 0x10)
|
if(rosalinaState & 2)
|
||||||
hasStartedRosalinaNetworkFuncsOnce = true;
|
hasStartedRosalinaNetworkFuncsOnce = true;
|
||||||
|
|
||||||
// 1: all applet/app/dsp/csnd... threads 2: gsp 4: hid/ir
|
if(rosalinaState & 1)
|
||||||
for (u32 v = 4; v != 0; v >>= 1)
|
rosalinaLockAllThreads();
|
||||||
{
|
else if(varg1 & 1)
|
||||||
if (varg1 & v)
|
rosalinaUnlockAllThreads();
|
||||||
{
|
|
||||||
if (rosalinaState & v)
|
|
||||||
rosalinaLockThreads(v);
|
|
||||||
else
|
|
||||||
rosalinaUnlockThreads(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -28,16 +28,9 @@
|
|||||||
#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)
|
||||||
{
|
{
|
||||||
KProcess *currentProcess = currentCoreContext->objectContext.currentProcess;
|
KProcessHandleTable *handleTable = handleTableOfProcess(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);
|
||||||
@ -54,7 +47,7 @@ Result SendSyncRequestHook(Handle handle)
|
|||||||
case 0x10042:
|
case 0x10042:
|
||||||
{
|
{
|
||||||
SessionInfo *info = SessionInfo_Lookup(clientSession->parentSession);
|
SessionInfo *info = SessionInfo_Lookup(clientSession->parentSession);
|
||||||
if(isNdmuWorkaround(info, pid))
|
if(info != NULL && strcmp(info->name, "ndm:u") == 0 && hasStartedRosalinaNetworkFuncsOnce)
|
||||||
{
|
{
|
||||||
cmdbuf[0] = 0x10040;
|
cmdbuf[0] = 0x10040;
|
||||||
cmdbuf[1] = 0;
|
cmdbuf[1] = 0;
|
||||||
@ -94,7 +87,7 @@ Result SendSyncRequestHook(Handle handle)
|
|||||||
case 0x20002:
|
case 0x20002:
|
||||||
{
|
{
|
||||||
SessionInfo *info = SessionInfo_Lookup(clientSession->parentSession);
|
SessionInfo *info = SessionInfo_Lookup(clientSession->parentSession);
|
||||||
if(isNdmuWorkaround(info, pid))
|
if(info != NULL && strcmp(info->name, "ndm:u") == 0 && hasStartedRosalinaNetworkFuncsOnce)
|
||||||
{
|
{
|
||||||
cmdbuf[0] = 0x20040;
|
cmdbuf[0] = 0x20040;
|
||||||
cmdbuf[1] = 0;
|
cmdbuf[1] = 0;
|
||||||
@ -136,7 +129,7 @@ Result SendSyncRequestHook(Handle handle)
|
|||||||
if(!hasStartedRosalinaNetworkFuncsOnce)
|
if(!hasStartedRosalinaNetworkFuncsOnce)
|
||||||
break;
|
break;
|
||||||
SessionInfo *info = SessionInfo_Lookup(clientSession->parentSession);
|
SessionInfo *info = SessionInfo_Lookup(clientSession->parentSession);
|
||||||
skip = isNdmuWorkaround(info, pid); // SuspendScheduler
|
skip = info != NULL && strcmp(info->name, "ndm:u") == 0; // SuspendScheduler
|
||||||
if(skip)
|
if(skip)
|
||||||
cmdbuf[1] = 0;
|
cmdbuf[1] = 0;
|
||||||
break;
|
break;
|
||||||
@ -147,7 +140,7 @@ Result SendSyncRequestHook(Handle handle)
|
|||||||
if(!hasStartedRosalinaNetworkFuncsOnce)
|
if(!hasStartedRosalinaNetworkFuncsOnce)
|
||||||
break;
|
break;
|
||||||
SessionInfo *info = SessionInfo_Lookup(clientSession->parentSession);
|
SessionInfo *info = SessionInfo_Lookup(clientSession->parentSession);
|
||||||
if(isNdmuWorkaround(info, pid)) // ResumeScheduler
|
if(info != NULL && strcmp(info->name, "ndm:u") == 0) // ResumeScheduler
|
||||||
{
|
{
|
||||||
cmdbuf[0] = 0x90040;
|
cmdbuf[0] = 0x90040;
|
||||||
cmdbuf[1] = 0;
|
cmdbuf[1] = 0;
|
||||||
|
@ -66,12 +66,17 @@ void KThread__DebugReschedule(KThread *this, bool lock)
|
|||||||
KRecursiveLock__Unlock(criticalSectionLock);
|
KRecursiveLock__Unlock(criticalSectionLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rosalinaLockThread(KThread *thread)
|
bool rosalinaThreadLockPredicate(KThread *thread)
|
||||||
{
|
{
|
||||||
KThread *syncThread = synchronizationMutex->owner;
|
KProcess *process = thread->ownerProcess;
|
||||||
|
if(process == NULL)
|
||||||
|
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
|
||||||
|
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)
|
||||||
@ -84,45 +89,20 @@ void rosalinaRescheduleThread(KThread *thread, bool lock)
|
|||||||
else
|
else
|
||||||
thread->schedulingMask &= ~0x40;
|
thread->schedulingMask &= ~0x40;
|
||||||
|
|
||||||
if (oldSchedulingMask != thread->schedulingMask)
|
KScheduler__AdjustThread(currentCoreContext->objectContext.currentScheduler, thread, oldSchedulingMask);
|
||||||
KScheduler__AdjustThread(currentCoreContext->objectContext.currentScheduler, thread, oldSchedulingMask);
|
|
||||||
|
|
||||||
KRecursiveLock__Unlock(criticalSectionLock);
|
KRecursiveLock__Unlock(criticalSectionLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool rosalinaThreadLockPredicate(KThread *thread, u32 mask)
|
void rosalinaLockThread(KThread *thread)
|
||||||
{
|
{
|
||||||
KProcess *process = thread->ownerProcess;
|
KThread *syncThread = synchronizationMutex->owner;
|
||||||
if(process == NULL || idOfProcess(process) < nbSection0Modules)
|
|
||||||
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);
|
||||||
|
|
||||||
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 rosalinaLockThreads(u32 mask)
|
void rosalinaLockAllThreads(void)
|
||||||
{
|
{
|
||||||
bool currentThreadsFound = false;
|
bool currentThreadsFound = false;
|
||||||
|
|
||||||
@ -130,7 +110,7 @@ void rosalinaLockThreads(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)
|
||||||
{
|
{
|
||||||
KThread *thread = (KThread *)node->key;
|
KThread *thread = (KThread *)node->key;
|
||||||
if(!rosalinaThreadLockPredicate(thread, mask))
|
if(!rosalinaThreadLockPredicate(thread))
|
||||||
continue;
|
continue;
|
||||||
if(thread == coreCtxs[thread->coreId].objectContext.currentThread)
|
if(thread == coreCtxs[thread->coreId].objectContext.currentThread)
|
||||||
currentThreadsFound = true;
|
currentThreadsFound = true;
|
||||||
@ -143,7 +123,7 @@ void rosalinaLockThreads(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)
|
||||||
{
|
{
|
||||||
KThread *thread = (KThread *)node->key;
|
KThread *thread = (KThread *)node->key;
|
||||||
if(!rosalinaThreadLockPredicate(thread, mask))
|
if(!rosalinaThreadLockPredicate(thread))
|
||||||
continue;
|
continue;
|
||||||
if(!(thread->schedulingMask & 0x40))
|
if(!(thread->schedulingMask & 0x40))
|
||||||
{
|
{
|
||||||
@ -165,7 +145,7 @@ void rosalinaLockThreads(u32 mask)
|
|||||||
KRecursiveLock__Unlock(criticalSectionLock);
|
KRecursiveLock__Unlock(criticalSectionLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void rosalinaUnlockThreads(u32 mask)
|
void rosalinaUnlockAllThreads(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)
|
||||||
{
|
{
|
||||||
@ -174,7 +154,7 @@ void rosalinaUnlockThreads(u32 mask)
|
|||||||
if((thread->schedulingMask & 0xF) == 2) // thread is terminating
|
if((thread->schedulingMask & 0xF) == 2) // thread is terminating
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if((thread->schedulingMask & 0x40) && rosalinaThreadLockPredicate(thread, mask))
|
if(thread->schedulingMask & 0x40)
|
||||||
rosalinaRescheduleThread(thread, false);
|
rosalinaRescheduleThread(thread, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
#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);
|
||||||
|
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
#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;
|
||||||
@ -92,11 +91,6 @@ 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;
|
||||||
@ -190,8 +184,11 @@ 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 (hbldrIs3dsxTitle(exheaderInfo->aci.local_caps.title_id))
|
if (nbSection0Modules == 6 && exheaderInfo->aci.local_caps.title_id == HBLDR_3DSX_TID)
|
||||||
{
|
{
|
||||||
assertSuccess(hbldrInit());
|
assertSuccess(hbldrInit());
|
||||||
HBLDR_PatchExHeaderInfo(exheaderInfo);
|
HBLDR_PatchExHeaderInfo(exheaderInfo);
|
||||||
@ -222,7 +219,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 || hbldrIs3dsxTitle(g_exheaderInfo.aci.local_caps.title_id))
|
if (g_cached_programHandle != programHandle || g_exheaderInfo.aci.local_caps.title_id == HBLDR_3DSX_TID)
|
||||||
{
|
{
|
||||||
res = GetProgramInfo(&g_exheaderInfo, programHandle);
|
res = GetProgramInfo(&g_exheaderInfo, programHandle);
|
||||||
g_cached_programHandle = programHandle;
|
g_cached_programHandle = programHandle;
|
||||||
@ -248,7 +245,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 (hbldrIs3dsxTitle(titleId))
|
if (titleId == HBLDR_3DSX_TID)
|
||||||
{
|
{
|
||||||
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));
|
||||||
@ -428,7 +425,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 || hbldrIs3dsxTitle(g_exheaderInfo.aci.local_caps.title_id))
|
if (programHandle != g_cached_programHandle || g_exheaderInfo.aci.local_caps.title_id == HBLDR_3DSX_TID)
|
||||||
{
|
{
|
||||||
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;
|
||||||
|
@ -1,28 +0,0 @@
|
|||||||
/* 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))
|
|
@ -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/LumaTeam/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/AuroraWright/Luma3DS/), build this project and copy the generated CXI file to `/luma/sysmodules/pm.cxi`.
|
||||||
|
|
||||||
# Credits
|
# Credits
|
||||||
@fincs
|
@fincs
|
||||||
|
@ -218,9 +218,8 @@ 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) && coreVer == 2 && exheaderInfo->aci.local_caps.core_info.core_version != coreVer ? (Result)0xC8A05800 : res;
|
res = R_SUCCEEDED(res) && SYSCOREVER == 2 && exheaderInfo->aci.local_caps.core_info.core_version != SYSCOREVER ? (Result)0xC8A05800 : res;
|
||||||
|
|
||||||
if (R_FAILED(res)) {
|
if (R_FAILED(res)) {
|
||||||
LOADER_UnregisterProgram(programHandle);
|
LOADER_UnregisterProgram(programHandle);
|
||||||
@ -228,7 +227,7 @@ static Result launchTitleImpl(Handle *debug, ProcessData **outProcessData, const
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Change APPMEMALLOC if needed
|
// Change APPMEMALLOC if needed
|
||||||
if (IS_N3DS && OS_KernelConfig->app_memtype == 6 && (launchFlags & PMLAUNCHFLAG_NORMAL_APPLICATION) != 0) {
|
if (IS_N3DS && APPMEMTYPE == 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;
|
||||||
@ -333,11 +332,9 @@ 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;
|
||||||
u32 coreVer = OS_KernelConfig->kernel_syscore_ver;
|
if ((tidh == 0x00040030 || tidh == 0x00040130) && (tidl & 0xFF) != SYSCOREVER) {
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -523,8 +520,8 @@ Result autolaunchSysmodules(void)
|
|||||||
FS_ProgramInfo programInfo = { .mediaType = MEDIATYPE_NAND };
|
FS_ProgramInfo programInfo = { .mediaType = MEDIATYPE_NAND };
|
||||||
|
|
||||||
// Launch NS
|
// Launch NS
|
||||||
if (OS_KernelConfig->ns_tid != 0) {
|
if (NSTID != 0) {
|
||||||
programInfo.programId = OS_KernelConfig->ns_tid;
|
programInfo.programId = NSTID;
|
||||||
TRY(launchTitleImplWrapper(NULL, NULL, &programInfo, &programInfo, PMLAUNCHFLAG_LOAD_DEPENDENCIES));
|
TRY(launchTitleImplWrapper(NULL, NULL, &programInfo, &programInfo, PMLAUNCHFLAG_LOAD_DEPENDENCIES));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 && OS_KernelConfig->app_memtype == 6) {
|
if (IS_N3DS && APPMEMTYPE == 6) {
|
||||||
assertSuccess(resetAppMemLimit());
|
assertSuccess(resetAppMemLimit());
|
||||||
}
|
}
|
||||||
g_manager.runningApplicationData = NULL;
|
g_manager.runningApplicationData = NULL;
|
||||||
|
@ -252,8 +252,7 @@ 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 appmemalloc = OS_KernelConfig->memregion_sz[0];
|
u32 sysmemalloc = SYSMEMALLOC + (hasKExt() ? getStolenSystemMemRegionSize() : 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;
|
||||||
@ -262,7 +261,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 {
|
||||||
@ -272,8 +271,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;
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,13 @@
|
|||||||
#define REG32(reg) (*(vu32 *)reg)
|
#define REG32(reg) (*(vu32 *)reg)
|
||||||
#define REG64(reg) (*(vu64 *)reg)
|
#define REG64(reg) (*(vu64 *)reg)
|
||||||
|
|
||||||
#define IS_N3DS (OS_KernelConfig->app_memtype >= 6) // APPMEMTYPE. Hacky but doesn't use APT
|
#define NSTID REG64(0x1FF80008)
|
||||||
|
#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
|
||||||
|
|
||||||
|
@ -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/LumaTeam/Luma3DS/) and copy pxi.cxi to /luma/sysmodules/.
|
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/.
|
||||||
|
|
||||||
# Credits
|
# Credits
|
||||||
This list is not complete at all:
|
This list is not complete at all:
|
||||||
|
@ -40,7 +40,7 @@ CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11
|
|||||||
ASFLAGS := -g $(ARCH)
|
ASFLAGS := -g $(ARCH)
|
||||||
LDFLAGS = -specs=3dsx.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map),-wrap,exit,--section-start,.text=0x14000000
|
LDFLAGS = -specs=3dsx.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map),-wrap,exit,--section-start,.text=0x14000000
|
||||||
|
|
||||||
LIBS := -lm -lctru
|
LIBS := -lctru
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
# list of directories containing libraries, this must be the top level containing
|
# list of directories containing libraries, this must be the top level containing
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
#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);
|
||||||
|
@ -1,28 +0,0 @@
|
|||||||
/* 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))
|
|
@ -1,33 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <3ds/types.h>
|
|
||||||
|
|
||||||
u32 getMinLuminancePreset(void);
|
|
||||||
u32 getMaxLuminancePreset(void);
|
|
||||||
u32 getCurrentLuminance(bool top);
|
|
@ -32,8 +32,6 @@ extern Menu screenFiltersMenu;
|
|||||||
|
|
||||||
extern int screenFiltersCurrentTemperature;
|
extern int screenFiltersCurrentTemperature;
|
||||||
|
|
||||||
void ScreenFiltersMenu_RestoreCct(void);
|
|
||||||
|
|
||||||
void ScreenFiltersMenu_SetDefault(void); // 6500K (default)
|
void ScreenFiltersMenu_SetDefault(void); // 6500K (default)
|
||||||
|
|
||||||
void ScreenFiltersMenu_SetAquarium(void); // 10000K
|
void ScreenFiltersMenu_SetAquarium(void); // 10000K
|
||||||
|
@ -21,10 +21,6 @@
|
|||||||
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);
|
||||||
|
|
||||||
|
@ -31,7 +31,6 @@
|
|||||||
#include <3ds/result.h>
|
#include <3ds/result.h>
|
||||||
#include <3ds/ipc.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)
|
||||||
|
@ -277,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_FramebufferFormat srcFormat)
|
static inline void Draw_ConvertPixelToBGR8(u8 *dst, const u8 *src, GSPGPU_FramebufferFormats srcFormat)
|
||||||
{
|
{
|
||||||
u8 red, green, blue;
|
u8 red, green, blue;
|
||||||
switch(srcFormat)
|
switch(srcFormat)
|
||||||
@ -354,7 +354,7 @@ 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_FramebufferFormat fmt = args->top ? (GSPGPU_FramebufferFormat)(GPU_FB_TOP_FMT & 7) : (GSPGPU_FramebufferFormat)(GPU_FB_BOTTOM_FMT & 7);
|
GSPGPU_FramebufferFormats fmt = args->top ? (GSPGPU_FramebufferFormats)(GPU_FB_TOP_FMT & 7) : (GSPGPU_FramebufferFormats)(GPU_FB_BOTTOM_FMT & 7);
|
||||||
u32 width = args->width;
|
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;
|
||||||
|
|
||||||
|
@ -36,6 +36,9 @@
|
|||||||
#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;
|
||||||
|
|
||||||
@ -145,7 +148,7 @@ 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
|
||||||
0xFF002109, // Exflags: APPLICATION memtype + "Shared page writing" + "Allow debug" + "Access core2"
|
0xFF002101, // Exflags: APPLICATION memtype + "Allow debug" + "Access core2"
|
||||||
0xFE000200, // Handle table size: 0x200
|
0xFE000200, // Handle table size: 0x200
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -307,22 +310,21 @@ 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));
|
||||||
|
|
||||||
u32 coreVer = OS_KernelConfig->kernel_syscore_ver;
|
if (SYSCOREVER == 2)
|
||||||
if (coreVer == 2)
|
|
||||||
memcpy(exhi->sci.dependencies, dependencyListNativeFirm, sizeof(dependencyListNativeFirm));
|
memcpy(exhi->sci.dependencies, dependencyListNativeFirm, sizeof(dependencyListNativeFirm));
|
||||||
else if (coreVer == 3)
|
else if (SYSCOREVER == 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 = coreVer;
|
localcaps0->core_info.core_version = SYSCOREVER;
|
||||||
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 = OS_KernelConfig->app_memtype;
|
u32 appmemtype = APPMEMTYPE;
|
||||||
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;
|
||||||
|
|
||||||
@ -332,7 +334,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
|
||||||
|
|
||||||
@ -349,7 +351,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 && coreVer == 2) // 9.6+ NFIRM
|
if (GET_VERSION_MINOR(osGetKernelVersion()) >= 50 && SYSCOREVER == 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
|
||||||
|
@ -177,248 +177,6 @@ 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(CUR_PROCESS_HANDLE, 0x00100000, processHandle, (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
|
|
||||||
};
|
|
||||||
|
|
||||||
svcGetProcessInfo(&startAddress, processHandle, 0x10005);
|
|
||||||
res = svcMapProcessMemoryEx(CUR_PROCESS_HANDLE, 0x00100000, processHandle, (u32) startAddress, totalSize);
|
|
||||||
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(CUR_PROCESS_HANDLE, 0x00100000, processHandle, (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)
|
||||||
@ -437,46 +195,209 @@ 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))
|
||||||
{
|
{
|
||||||
res = InputRedirection_DoUndoHidPatches(hidProcHandle, !hidPatched);
|
svcGetProcessInfo(&textTotalRoundedSize, processHandle, 0x10002); // only patch .text + .data
|
||||||
if (R_SUCCEEDED(res))
|
svcGetProcessInfo(&rodataTotalRoundedSize, processHandle, 0x10003);
|
||||||
hidPatched = !hidPatched;
|
svcGetProcessInfo(&dataTotalRoundedSize, processHandle, 0x10004);
|
||||||
}
|
|
||||||
|
|
||||||
|
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)
|
||||||
{
|
{
|
||||||
res = InputRedirection_DoUndoIrPatches(irProcHandle, !irPatched);
|
svcGetProcessInfo(&textTotalRoundedSize, processHandle, 0x10002); // only patch .text + .data
|
||||||
if (R_SUCCEEDED(res))
|
svcGetProcessInfo(&rodataTotalRoundedSize, processHandle, 0x10003);
|
||||||
irPatched = !irPatched;
|
svcGetProcessInfo(&dataTotalRoundedSize, processHandle, 0x10004);
|
||||||
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))
|
||||||
{
|
{
|
||||||
InputRedirection_DoUndoHidPatches(hidProcHandle, false);
|
static bool useOldSyncCode;
|
||||||
hidPatched = 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 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;
|
||||||
}
|
}
|
||||||
|
@ -1,122 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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);
|
|
||||||
}
|
|
@ -83,15 +83,13 @@ void initSystem(void)
|
|||||||
isN3DS = svcGetSystemInfo(&out, 0x10001, 0) == 0;
|
isN3DS = svcGetSystemInfo(&out, 0x10001, 0) == 0;
|
||||||
|
|
||||||
svcGetSystemInfo(&out, 0x10000, 0x100);
|
svcGetSystemInfo(&out, 0x10000, 0x100);
|
||||||
Luma_SharedConfig->hbldr_3dsx_tid = out == 0 ? HBLDR_DEFAULT_3DSX_TID : (u64)out;
|
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 = Luma_SharedConfig->hbldr_3dsx_tid == HBLDR_DEFAULT_3DSX_TID ?
|
miscellaneousMenu.items[0].title = HBLDR_3DSX_TID == HBLDR_DEFAULT_3DSX_TID ? "Switch the hb. title to the current app." :
|
||||||
"Switch the hb. title to the current app." :
|
"Switch the hb. title to hblauncher_loader";
|
||||||
"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))
|
||||||
{
|
{
|
||||||
@ -106,9 +104,6 @@ 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).
|
||||||
|
|
||||||
@ -136,53 +131,11 @@ 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);
|
||||||
|
|
||||||
@ -227,19 +180,11 @@ static const ServiceManagerServiceEntry services[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static const ServiceManagerNotificationEntry notifications[] = {
|
static const ServiceManagerNotificationEntry notifications[] = {
|
||||||
{ 0x100 , handleTermNotification },
|
{ 0x100 , handleTermNotification },
|
||||||
{ PTMNOTIFID_SLEEP_REQUESTED, handleSleepNotification },
|
//{ 0x103 , handlePreTermNotification }, // Sleep mode entry <=== causes issues
|
||||||
{ PTMNOTIFID_SLEEP_DENIED, handleSleepNotification },
|
{ 0x1000, handleNextApplicationDebuggedByForce },
|
||||||
{ PTMNOTIFID_SLEEP_ALLOWED, handleSleepNotification },
|
{ 0x2000, handlePreTermNotification },
|
||||||
{ PTMNOTIFID_GOING_TO_SLEEP, handleSleepNotification },
|
{ 0x3000, handleRestartHbAppNotification },
|
||||||
{ 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 },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -193,7 +193,6 @@ void menuThreadMain(void)
|
|||||||
|
|
||||||
while(!preTerminationRequested)
|
while(!preTerminationRequested)
|
||||||
{
|
{
|
||||||
svcSleepThread(50 * 1000 * 1000LL);
|
|
||||||
if (menuShouldExit)
|
if (menuShouldExit)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -227,13 +226,13 @@ void menuEnter(void)
|
|||||||
if(!menuShouldExit && menuRefCount == 0)
|
if(!menuShouldExit && menuRefCount == 0)
|
||||||
{
|
{
|
||||||
menuRefCount++;
|
menuRefCount++;
|
||||||
svcKernelSetState(0x10000, 2 | 1);
|
svcKernelSetState(0x10000, 1);
|
||||||
svcSleepThread(5 * 1000 * 100LL);
|
svcSleepThread(5 * 1000 * 100LL);
|
||||||
if (R_FAILED(Draw_AllocateFramebufferCache(FB_BOTTOM_SIZE)))
|
if (R_FAILED(Draw_AllocateFramebufferCache(FB_BOTTOM_SIZE)))
|
||||||
{
|
{
|
||||||
// Oops
|
// Oops
|
||||||
menuRefCount = 0;
|
menuRefCount = 0;
|
||||||
svcKernelSetState(0x10000, 2 | 1);
|
svcKernelSetState(0x10000, 1);
|
||||||
svcSleepThread(5 * 1000 * 100LL);
|
svcSleepThread(5 * 1000 * 100LL);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -251,7 +250,7 @@ void menuLeave(void)
|
|||||||
{
|
{
|
||||||
Draw_RestoreFramebuffer();
|
Draw_RestoreFramebuffer();
|
||||||
Draw_FreeFramebufferCache();
|
Draw_FreeFramebufferCache();
|
||||||
svcKernelSetState(0x10000, 2 | 1);
|
svcKernelSetState(0x10000, 1);
|
||||||
}
|
}
|
||||||
Draw_Unlock();
|
Draw_Unlock();
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,6 @@
|
|||||||
#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",
|
||||||
@ -65,11 +64,7 @@ Menu rosalinaMenu = {
|
|||||||
|
|
||||||
bool rosalinaMenuShouldShowDebugInfo(void)
|
bool rosalinaMenuShouldShowDebugInfo(void)
|
||||||
{
|
{
|
||||||
// Don't show on release builds
|
return true;
|
||||||
|
|
||||||
s64 out;
|
|
||||||
svcGetSystemInfo(&out, 0x10000, 0x200);
|
|
||||||
return out == 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RosalinaMenu_ShowDebugInfo(void)
|
void RosalinaMenu_ShowDebugInfo(void)
|
||||||
@ -124,8 +119,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"
|
||||||
" fincs, WinterMute, mtheall, piepie62,\n"
|
" Bond697, WinterMute, piepie62, yifanlu\n"
|
||||||
" Luma3DS contributors, libctru contributors,\n"
|
" Luma3DS contributors, ctrulib contributors,\n"
|
||||||
" other people"
|
" other people"
|
||||||
));
|
));
|
||||||
|
|
||||||
@ -145,7 +140,7 @@ void RosalinaMenu_Reboot(void)
|
|||||||
do
|
do
|
||||||
{
|
{
|
||||||
Draw_Lock();
|
Draw_Lock();
|
||||||
Draw_DrawString(10, 10, COLOR_TITLE, "Reboot");
|
Draw_DrawString(10, 10, COLOR_TITLE, "Rosalina menu");
|
||||||
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();
|
||||||
@ -163,103 +158,107 @@ 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
|
||||||
{
|
{
|
||||||
Draw_Lock();
|
// Assume the current brightness for both screens are the same.
|
||||||
Draw_DrawString(10, 10, COLOR_TITLE, "Screen brightness");
|
s32 brightness = (s32)(LCD_TOP_BRIGHTNESS & 0xFF);
|
||||||
u32 posY = 30;
|
|
||||||
posY = Draw_DrawFormattedString(
|
Draw_Lock();
|
||||||
10,
|
Draw_DrawString(10, 10, COLOR_TITLE, "Rosalina menu");
|
||||||
posY,
|
u32 posY = 30;
|
||||||
COLOR_WHITE,
|
posY = Draw_DrawFormattedString(10, posY, COLOR_WHITE, "Current brightness (0..255): %3lu\n\n", brightness);
|
||||||
"Current luminance: %lu (min. %lu, max. %lu)\n\n",
|
if (R_SUCCEEDED(patchResult))
|
||||||
luminance,
|
{
|
||||||
minLum,
|
posY = Draw_DrawString(10, posY, COLOR_WHITE, "Press Up/Down for +-1, Right/Left for +-10.\n");
|
||||||
maxLum
|
posY = Draw_DrawString(10, posY, COLOR_WHITE, "Press Y to revert the GSP patch and exit.\n\n");
|
||||||
);
|
|
||||||
posY = Draw_DrawString(10, posY, COLOR_WHITE, "Controls: Up/Down for +-1, Right/Left for +-10.\n");
|
posY = Draw_DrawString(10, posY, COLOR_RED, "WARNING: \n");
|
||||||
posY = Draw_DrawString(10, posY, COLOR_WHITE, "Press A to start, B to exit.\n\n");
|
posY = Draw_DrawString(10, posY, COLOR_WHITE, " * avoid using values far higher than the presets.\n");
|
||||||
|
posY = Draw_DrawString(10, posY, COLOR_WHITE, " * normal brightness mngmt. is now broken on N3DS.\nYou'll need to press Y to revert");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
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 & KEY_A)
|
if ((pressed & DIRECTIONAL_KEYS) && R_SUCCEEDED(patchResult))
|
||||||
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;
|
||||||
|
|
||||||
if (pressed & KEY_B)
|
brightness = brightness < 0 ? 0 : brightness;
|
||||||
|
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 < (s32)minLum ? (s32)minLum : lum;
|
|
||||||
lum = lum > (s32)maxLum ? (s32)maxLum : 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.
|
||||||
@ -272,7 +271,7 @@ void RosalinaMenu_PowerOff(void) // Soft shutdown.
|
|||||||
do
|
do
|
||||||
{
|
{
|
||||||
Draw_Lock();
|
Draw_Lock();
|
||||||
Draw_DrawString(10, 10, COLOR_TITLE, "Power off");
|
Draw_DrawString(10, 10, COLOR_TITLE, "Rosalina menu");
|
||||||
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();
|
||||||
|
@ -102,6 +102,7 @@ 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;
|
||||||
|
@ -55,7 +55,7 @@ void MiscellaneousMenu_SwitchBoot3dsxTargetTitle(void)
|
|||||||
Result res;
|
Result res;
|
||||||
char failureReason[64];
|
char failureReason[64];
|
||||||
|
|
||||||
if(Luma_SharedConfig->hbldr_3dsx_tid == HBLDR_DEFAULT_3DSX_TID)
|
if(HBLDR_3DSX_TID == HBLDR_DEFAULT_3DSX_TID)
|
||||||
{
|
{
|
||||||
FS_ProgramInfo progInfo;
|
FS_ProgramInfo progInfo;
|
||||||
u32 pid;
|
u32 pid;
|
||||||
@ -63,7 +63,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))
|
||||||
{
|
{
|
||||||
Luma_SharedConfig->hbldr_3dsx_tid = progInfo.programId;
|
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 +75,7 @@ void MiscellaneousMenu_SwitchBoot3dsxTargetTitle(void)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
res = 0;
|
res = 0;
|
||||||
Luma_SharedConfig->hbldr_3dsx_tid = HBLDR_DEFAULT_3DSX_TID;
|
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.";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -205,7 +205,7 @@ Result SaveSettings(void)
|
|||||||
configData.config = config;
|
configData.config = config;
|
||||||
configData.multiConfig = multiConfig;
|
configData.multiConfig = multiConfig;
|
||||||
configData.bootConfig = bootConfig;
|
configData.bootConfig = bootConfig;
|
||||||
configData.hbldr3dsxTitleId = Luma_SharedConfig->hbldr_3dsx_tid;
|
configData.hbldr3dsxTitleId = HBLDR_3DSX_TID;
|
||||||
configData.rosalinaMenuCombo = menuCombo;
|
configData.rosalinaMenuCombo = menuCombo;
|
||||||
configData.rosalinaFlags = PluginLoader__IsEnabled();
|
configData.rosalinaFlags = PluginLoader__IsEnabled();
|
||||||
|
|
||||||
@ -331,21 +331,7 @@ 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);
|
||||||
}
|
}
|
||||||
|
@ -32,29 +32,26 @@
|
|||||||
#include "redshift/redshift.h"
|
#include "redshift/redshift.h"
|
||||||
#include "redshift/colorramp.h"
|
#include "redshift/colorramp.h"
|
||||||
|
|
||||||
typedef union {
|
typedef struct {
|
||||||
struct {
|
u8 r;
|
||||||
u8 r;
|
u8 g;
|
||||||
u8 g;
|
u8 b;
|
||||||
u8 b;
|
u8 z;
|
||||||
u8 z;
|
|
||||||
};
|
|
||||||
u32 raw;
|
|
||||||
} Pixel;
|
} Pixel;
|
||||||
|
|
||||||
static u16 g_c[0x600];
|
static u16 g_c[0x600];
|
||||||
static Pixel g_px[0x400];
|
static Pixel g_px[0x400];
|
||||||
|
|
||||||
int screenFiltersCurrentTemperature = -1;
|
int screenFiltersCurrentTemperature = 6500;
|
||||||
|
|
||||||
static void ScreenFiltersMenu_WriteLut(const Pixel* lut)
|
static void ScreenFiltersMenu_WriteLut(const u32* lut)
|
||||||
{
|
{
|
||||||
GPU_FB_TOP_COL_LUT_INDEX = 0;
|
GPU_FB_TOP_COL_LUT_INDEX = 0;
|
||||||
GPU_FB_BOTTOM_COL_LUT_INDEX = 0;
|
GPU_FB_BOTTOM_COL_LUT_INDEX = 0;
|
||||||
|
|
||||||
for (int i = 0; i <= 255; i++) {
|
for (int i = 0; i <= 255; i++) {
|
||||||
GPU_FB_TOP_COL_LUT_ELEM = lut->raw;
|
GPU_FB_TOP_COL_LUT_ELEM = *lut;
|
||||||
GPU_FB_BOTTOM_COL_LUT_ELEM = lut->raw;
|
GPU_FB_BOTTOM_COL_LUT_ELEM = *lut;
|
||||||
lut++;
|
lut++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -87,7 +84,7 @@ static void ScreenFiltersMenu_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);
|
||||||
|
|
||||||
ScreenFiltersMenu_WriteLut(g_px);
|
ScreenFiltersMenu_WriteLut((u32*)g_px);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ScreenFiltersMenu_SetCct(int cct)
|
static void ScreenFiltersMenu_SetCct(int cct)
|
||||||
@ -104,6 +101,7 @@ static void ScreenFiltersMenu_SetCct(int cct)
|
|||||||
ScreenFiltersMenu_ApplyColorSettings(&cs);
|
ScreenFiltersMenu_ApplyColorSettings(&cs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Menu screenFiltersMenu = {
|
Menu screenFiltersMenu = {
|
||||||
"Screen filters menu",
|
"Screen filters menu",
|
||||||
{
|
{
|
||||||
@ -116,7 +114,7 @@ Menu screenFiltersMenu = {
|
|||||||
{ "[2700K] Incandescent", METHOD, .method = &ScreenFiltersMenu_SetIncandescent },
|
{ "[2700K] Incandescent", METHOD, .method = &ScreenFiltersMenu_SetIncandescent },
|
||||||
{ "[2300K] Warm Incandescent", METHOD, .method = &ScreenFiltersMenu_SetWarmIncandescent },
|
{ "[2300K] Warm Incandescent", METHOD, .method = &ScreenFiltersMenu_SetWarmIncandescent },
|
||||||
{ "[1900K] Candle", METHOD, .method = &ScreenFiltersMenu_SetCandle },
|
{ "[1900K] Candle", METHOD, .method = &ScreenFiltersMenu_SetCandle },
|
||||||
{ "[1200K] Ember", METHOD, .method = &ScreenFiltersMenu_SetEmber },
|
{ "[2700K] Ember", METHOD, .method = &ScreenFiltersMenu_SetEmber },
|
||||||
{},
|
{},
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -128,20 +126,6 @@ void ScreenFiltersMenu_Set##name(void)\
|
|||||||
ScreenFiltersMenu_SetCct(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(6500, Default)
|
||||||
|
|
||||||
DEF_CCT_SETTER(10000, Aquarium)
|
DEF_CCT_SETTER(10000, Aquarium)
|
||||||
|
@ -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 },
|
||||||
{},
|
{},
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* 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
|
||||||
@ -8,16 +7,18 @@
|
|||||||
|
|
||||||
#include "minisoc.h"
|
#include "minisoc.h"
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <3ds.h>
|
#include <3ds/ipc.h>
|
||||||
|
#include <3ds/os.h>
|
||||||
|
#include <3ds/synchronization.h>
|
||||||
|
#include <3ds/result.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "utils.h"
|
#include "csvc.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;
|
||||||
|
|
||||||
@ -55,41 +56,6 @@ 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))
|
||||||
@ -123,11 +89,8 @@ Result miniSocInit(void)
|
|||||||
ret = SOCU_Initialize(miniSocMemHandle, socContextSize);
|
ret = SOCU_Initialize(miniSocMemHandle, socContextSize);
|
||||||
if(ret != 0) goto cleanup;
|
if(ret != 0) goto cleanup;
|
||||||
|
|
||||||
miniSocLockState();
|
svcKernelSetState(0x10000, 2);
|
||||||
|
|
||||||
svcKernelSetState(0x10000, 0x10);
|
|
||||||
miniSocEnabled = true;
|
miniSocEnabled = true;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
@ -154,6 +117,7 @@ cleanup:
|
|||||||
|
|
||||||
Result miniSocExitDirect(void)
|
Result miniSocExitDirect(void)
|
||||||
{
|
{
|
||||||
|
//if (miniSocRefCount != 0) __builtin_trap();
|
||||||
Result ret = 0;
|
Result ret = 0;
|
||||||
u32 tmp;
|
u32 tmp;
|
||||||
|
|
||||||
@ -168,10 +132,8 @@ 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)
|
||||||
{
|
{
|
||||||
miniSocUnlockState(false);
|
svcKernelSetState(0x10000, 2);
|
||||||
|
|
||||||
miniSocEnabled = false;
|
miniSocEnabled = false;
|
||||||
svcKernelSetState(0x10000, 0x10);
|
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -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/LumaTeam/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/AuroraWright/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.
|
||||||
|
@ -8,18 +8,6 @@ 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
|
||||||
@ -138,7 +126,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 || isNotificationInhibited(node, notificationId))
|
if(!node->notificationEnabled)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
u16 i;
|
u16 i;
|
||||||
@ -158,7 +146,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 || isNotificationInhibited(node, notificationId))
|
if(!node->notificationEnabled)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
u16 i;
|
u16 i;
|
||||||
|
@ -17,5 +17,3 @@ 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);
|
|
||||||
|
Reference in New Issue
Block a user