Compare commits
31 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f6483ec602 | ||
|
|
36c1da1d61 | ||
|
|
6bcb1f8679 | ||
|
|
62932a9639 | ||
|
|
a4629e4b65 | ||
|
|
a0c2b43b34 | ||
|
|
3907c46980 | ||
|
|
7e7ab124a3 | ||
|
|
cfc6cf24bf | ||
|
|
46e9cb6b23 | ||
|
|
ba14efe1f4 | ||
|
|
3d8f62d38f | ||
|
|
3edaf0af64 | ||
|
|
9273a88db7 | ||
|
|
37ba2c15de | ||
|
|
557f2057f7 | ||
|
|
6b5cc93780 | ||
|
|
9760191af8 | ||
|
|
8845e4dd20 | ||
|
|
8cf823f548 | ||
|
|
2538769f3a | ||
|
|
89fca38807 | ||
|
|
dcc0eed69c | ||
|
|
817475257e | ||
|
|
f2861058ba | ||
|
|
5d2a7315d5 | ||
|
|
1520ab7555 | ||
|
|
d4d0fbd73b | ||
|
|
ddb8e98e95 | ||
|
|
fd69b4169f | ||
|
|
b48e0b5c5b |
6
.github/ISSUE_TEMPLATE.md
vendored
6
.github/ISSUE_TEMPLATE.md
vendored
@@ -26,7 +26,7 @@
|
||||
|
||||
**Luma3DS version:**
|
||||
|
||||
[e.g. 7.1 stable or if using nightly/hourly specify the commit like this https://github.com/AuroraWright/Luma3DS/commit/9570e6cbeca53128433abbf5e3473cb8a07fe69e]
|
||||
[e.g. 8.1 stable or if using nightly/hourly specify the commit like this https://github.com/AuroraWright/Luma3DS/commit/9570e6cbeca53128433abbf5e3473cb8a07fe69e]
|
||||
<!--You can check which version you're on in System Settings. It will be on the bottom right of the top screen.-->
|
||||
|
||||
|
||||
@@ -53,8 +53,6 @@ Enable loading external FIRMs and modules: ( )
|
||||
<!--Firmware (.bin) files are not required by Luma, or NTR CFW anymore.
|
||||
-- If you're having issues with this option enabled try deleting them from the luma folder on the root of the SD card and disabling this option.-->
|
||||
|
||||
Use custom path: ( )
|
||||
|
||||
Enable game patching: ( )
|
||||
|
||||
Show NAND or user string in System Settings: ( )
|
||||
@@ -65,6 +63,8 @@ Patch ARM9 access: ( )
|
||||
|
||||
Set developer UNITINFO: ( )
|
||||
|
||||
Disable ARM11 exception handlers: ( )
|
||||
|
||||
--
|
||||
|
||||
|
||||
|
||||
9
Makefile
9
Makefile
@@ -10,13 +10,6 @@ endif
|
||||
|
||||
include $(DEVKITARM)/base_tools
|
||||
|
||||
UNAME_S := $(shell uname -s)
|
||||
ifeq ($(UNAME_S),Darwin)
|
||||
size := stat -f%z
|
||||
else
|
||||
size := stat -c%s
|
||||
endif
|
||||
|
||||
name := Luma3DS
|
||||
revision := $(shell git describe --tags --match v[0-9]* --abbrev=8 | sed 's/-[0-9]*-g/-/')
|
||||
version_major := $(shell git describe --tags --match v[0-9]* | cut -c2- | cut -f1 -d- | cut -f1 -d.)
|
||||
@@ -152,7 +145,7 @@ $(dir_build)/config.o: CFLAGS += -DCONFIG_TITLE="\"$(name) $(revision) configura
|
||||
$(dir_build)/patches.o: CFLAGS += -DVERSION_MAJOR="$(version_major)" -DVERSION_MINOR="$(version_minor)"\
|
||||
-DVERSION_BUILD="$(version_build)" -DISRELEASE="$(is_release)" -DCOMMIT_HASH="0x$(commit)"
|
||||
$(dir_build)/firm.o: $(dir_build)/modules.bin
|
||||
$(dir_build)/firm.o: CFLAGS += -DLUMA_SECTION0_SIZE="$(shell $(size) $(dir_build)/modules.bin)"
|
||||
$(dir_build)/firm.o: CFLAGS += -DLUMA_SECTION0_SIZE="$(shell wc -c $(dir_build)/modules.bin | tr -d [:space:][:alpha:][:punct:])"
|
||||
|
||||
$(dir_build)/bundled.h: $(bundled)
|
||||
@$(foreach f, $(bundled),\
|
||||
|
||||
@@ -16,7 +16,7 @@ Since Luma3DS v8.0, Luma3DS has its own in-game menu, triggerable by `L+Down+Sel
|
||||
First you need to clone the repository with: `git clone https://github.com/AuroraWright/Luma3DS.git`
|
||||
To compile, you'll need [armips](https://github.com/Kingcom/armips) and a build of a recent commit of [makerom](https://github.com/profi200/Project_CTR) added to your PATH. You'll also need to install [firmtool](https://github.com/TuxSH/firmtool), its README contains installation instructions.
|
||||
For now, you'll also need to update your [libctru](https://github.com/smealum/ctrulib) install, building from the latest commit.
|
||||
For your convenience, here are [Windows](http://www91.zippyshare.com/v/ePGpjk9r/file.html) and [Linux](https://mega.nz/#!uQ1T1IAD!Q91O0e12LXKiaXh_YjXD3D5m8_W3FuMI-hEa6KVMRDQ) builds of armips (thanks to who compiled them!).
|
||||
For your convenience, here are [Windows](http://www91.zippyshare.com/v/ePGpjk9r/file.html) and [Linux](https://mega.nz/#!uQ1T1IAD!Q91O0e12LXKiaXh_YjXD3D5m8_W3FuMI-hEa6KVMRDQ) builds of armips (thanks to who compiled them!) and [makerom](https://github.com/Steveice10/buildtools/tree/master/3ds) (thanks @Steveice10!).
|
||||
Finally just run `make` and everything should work!
|
||||
You can find the compiled files in the `out` folder.
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ extern u32 prepareForFirmlaunchSize;
|
||||
|
||||
extern volatile Arm11Operation operation;
|
||||
|
||||
static void initScreens(u32 brightnessLevel, struct fb *fbs)
|
||||
static void initScreens(u32 brightnessLevel)
|
||||
{
|
||||
*(vu32 *)0x10141200 = 0x1007F;
|
||||
*(vu32 *)0x10202014 = 0x00000001;
|
||||
@@ -70,13 +70,9 @@ static void initScreens(u32 brightnessLevel, struct fb *fbs)
|
||||
*(vu32 *)0x1040045C = 0x00f00190;
|
||||
*(vu32 *)0x10400460 = 0x01c100d1;
|
||||
*(vu32 *)0x10400464 = 0x01920002;
|
||||
*(vu32 *)0x10400468 = (u32)fbs[0].top_left;
|
||||
*(vu32 *)0x1040046C = (u32)fbs[1].top_left;
|
||||
*(vu32 *)0x10400470 = 0x80341;
|
||||
*(vu32 *)0x10400474 = 0x00010501;
|
||||
*(vu32 *)0x10400478 = 0;
|
||||
*(vu32 *)0x10400494 = (u32)fbs[0].top_right;
|
||||
*(vu32 *)0x10400498 = (u32)fbs[1].top_right;
|
||||
*(vu32 *)0x10400490 = 0x000002D0;
|
||||
*(vu32 *)0x1040049C = 0x00000000;
|
||||
|
||||
@@ -107,8 +103,6 @@ static void initScreens(u32 brightnessLevel, struct fb *fbs)
|
||||
*(vu32 *)0x1040055C = 0x00f00140;
|
||||
*(vu32 *)0x10400560 = 0x01c100d1;
|
||||
*(vu32 *)0x10400564 = 0x01920052;
|
||||
*(vu32 *)0x10400568 = (u32)fbs[0].bottom;
|
||||
*(vu32 *)0x1040056C = (u32)fbs[1].bottom;
|
||||
*(vu32 *)0x10400570 = 0x80301;
|
||||
*(vu32 *)0x10400574 = 0x00010501;
|
||||
*(vu32 *)0x10400578 = 0;
|
||||
@@ -120,6 +114,16 @@ static void initScreens(u32 brightnessLevel, struct fb *fbs)
|
||||
*(vu32 *)0x10400584 = 0x10101 * i;
|
||||
}
|
||||
|
||||
static void setupFramebuffers(struct fb *fbs)
|
||||
{
|
||||
*(vu32 *)0x10400468 = (u32)fbs[0].top_left;
|
||||
*(vu32 *)0x1040046c = (u32)fbs[1].top_left;
|
||||
*(vu32 *)0x10400494 = (u32)fbs[0].top_right;
|
||||
*(vu32 *)0x10400498 = (u32)fbs[1].top_right;
|
||||
*(vu32 *)0x10400568 = (u32)fbs[0].bottom;
|
||||
*(vu32 *)0x1040056c = (u32)fbs[1].bottom;
|
||||
}
|
||||
|
||||
static void clearScreens(struct fb *fb)
|
||||
{
|
||||
//Setting up two simultaneous memory fills using the GPU
|
||||
@@ -173,7 +177,10 @@ void main(void)
|
||||
case ARM11_READY:
|
||||
continue;
|
||||
case INIT_SCREENS:
|
||||
initScreens(*(vu32 *)ARM11_PARAMETERS_ADDRESS, (struct fb *)(ARM11_PARAMETERS_ADDRESS + 4));
|
||||
initScreens(*(vu32 *)ARM11_PARAMETERS_ADDRESS);
|
||||
break;
|
||||
case SETUP_FRAMEBUFFERS:
|
||||
setupFramebuffers((struct fb *)ARM11_PARAMETERS_ADDRESS);
|
||||
break;
|
||||
case CLEAR_SCREENS:
|
||||
clearScreens((struct fb *)ARM11_PARAMETERS_ADDRESS);
|
||||
|
||||
@@ -55,6 +55,7 @@ struct fb {
|
||||
typedef enum
|
||||
{
|
||||
INIT_SCREENS = 0,
|
||||
SETUP_FRAMEBUFFERS,
|
||||
CLEAR_SCREENS,
|
||||
SWAP_FRAMEBUFFERS,
|
||||
UPDATE_BRIGHTNESS,
|
||||
|
||||
@@ -56,6 +56,7 @@ extern void (*KScheduler__AttemptSwitchingThreadContext)(KScheduler *this);
|
||||
extern Result (*ControlMemory)(u32 *addrOut, u32 addr0, u32 addr1, u32 size, MemOp op, MemPerm perm, bool isLoader);
|
||||
extern void (*SleepThread)(s64 ns);
|
||||
extern Result (*CloseHandle)(Handle handle);
|
||||
extern Result (*GetHandleInfo)(s64 *out, Handle handle, u32 type);
|
||||
extern Result (*GetSystemInfo)(s64 *out, s32 type, s32 param);
|
||||
extern Result (*GetProcessInfo)(s64 *out, Handle processHandle, u32 type);
|
||||
extern Result (*GetThreadInfo)(s64 *out, Handle threadHandle, u32 type);
|
||||
|
||||
@@ -1137,21 +1137,29 @@ typedef struct FcramLayout
|
||||
extern bool isN3DS;
|
||||
extern void *officialSVCs[0x7E];
|
||||
|
||||
#define KPROCESS_OFFSETOF(field) (isN3DS ? offsetof(KProcessN3DS, field) :\
|
||||
((kernelVersion >= SYSTEM_VERSION(2, 44, 6)) ? offsetof(KProcessO3DS8x, field) :\
|
||||
offsetof(KProcessO3DSPre8x, field)))
|
||||
#define KPROCESSRELATED_OFFSETOFF(classname, field) (isN3DS ? offsetof(classname##N3DS, field) :\
|
||||
((kernelVersion >= SYSTEM_VERSION(2, 44, 6)) ? offsetof(classname##O3DS8x, field) :\
|
||||
offsetof(classname##O3DSPre8x, field)))
|
||||
|
||||
#define KPROCESS_GET_PTR(obj, field) (isN3DS ? &(obj)->N3DS.field :\
|
||||
#define KPROCESSRELATED_GET_PTR(obj, field) (isN3DS ? &(obj)->N3DS.field :\
|
||||
((kernelVersion >= SYSTEM_VERSION(2, 44, 6)) ? &(obj)->O3DS8x.field :\
|
||||
&(obj)->O3DSPre8x.field ))
|
||||
&(obj)->O3DSPre8x.field))
|
||||
|
||||
#define KPROCESS_GET_PTR_TYPE(type, obj, field) (isN3DS ? (type *)(&(obj)->N3DS.field) :\
|
||||
#define KPROCESSRELATED_GET_PTR_TYPE(type, obj, field) (isN3DS ? (type *)(&(obj)->N3DS.field) :\
|
||||
((kernelVersion >= SYSTEM_VERSION(2, 44, 6)) ? (type *)(&(obj)->O3DS8x.field) :\
|
||||
(type *)(&(obj)->O3DSPre8x.field) ))
|
||||
(type *)(&(obj)->O3DSPre8x.field)))
|
||||
|
||||
#define KPROCESS_GET_RVALUE(obj, field) *(KPROCESS_GET_PTR(obj, field))
|
||||
#define KPROCESS_OFFSETOF(field) KPROCESSRELATED_OFFSETOFF(KProcess, field)
|
||||
#define KPROCESS_GET_PTR(obj, field) KPROCESSRELATED_GET_PTR(obj, field)
|
||||
#define KPROCESS_GET_PTR_TYPE(type, obj, field) KPROCESSRELATED_GET_PTR_TYPE(type, obj, field)
|
||||
#define KPROCESS_GET_RVALUE(obj, field) *(KPROCESS_GET_PTR(obj, field))
|
||||
#define KPROCESS_GET_RVALUE_TYPE(type, obj, field) *(KPROCESS_GET_PTR_TYPE(type, obj, field))
|
||||
|
||||
#define KPROCESS_GET_RVALUE_TYPE(type, obj, field) *(KPROCESS_GET_PTR(type, obj, field))
|
||||
#define KPROCESSHWINFO_OFFSETOF(field) KPROCESSRELATED_OFFSETOFF(KProcessHwInfo, field)
|
||||
#define KPROCESSHWINFO_GET_PTR(obj, field) KPROCESSRELATED_GET_PTR(obj, field)
|
||||
#define KPROCESSHWINFO_GET_PTR_TYPE(type, obj, field) KPROCESSRELATED_GET_PTR_TYPE(type, obj, field)
|
||||
#define KPROCESSHWINFO_GET_RVALUE(obj, field) *(KPROCESSHWINFO_GET_PTR(obj, field))
|
||||
#define KPROCESSHWINFO_GET_RVALUE_TYPE(type, obj, field) *(KPROCESSHWINFO_GET_PTR_TYPE(type, obj, field))
|
||||
|
||||
static inline u32 idOfProcess(KProcess *process)
|
||||
{
|
||||
@@ -1178,6 +1186,20 @@ static inline KDebug *debugOfProcess(KProcess *process)
|
||||
return KPROCESS_GET_RVALUE(process, debug);
|
||||
}
|
||||
|
||||
static inline const char *classNameOfAutoObject(KAutoObject *object)
|
||||
{
|
||||
const char *name;
|
||||
if(kernelVersion >= SYSTEM_VERSION(2, 46, 0))
|
||||
{
|
||||
KClassToken tok;
|
||||
object->vtable->GetClassToken(&tok, object);
|
||||
name = tok.name;
|
||||
}
|
||||
else
|
||||
name = object->vtable->GetClassName(object);
|
||||
return name;
|
||||
}
|
||||
|
||||
extern Result (*KProcessHandleTable__CreateHandle)(KProcessHandleTable *this, Handle *out, KAutoObject *obj, u8 token);
|
||||
|
||||
static inline Result createHandleForProcess(Handle *out, KProcess *process, KAutoObject *obj)
|
||||
|
||||
34
k11_extension/include/svc/GetHandleInfo.h
Normal file
34
k11_extension/include/svc/GetHandleInfo.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* This file is part of Luma3DS
|
||||
* Copyright (C) 2016-2017 Aurora Wright, TuxSH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <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 "utils.h"
|
||||
#include "kernel.h"
|
||||
#include "svc.h"
|
||||
|
||||
Result GetHandleInfoHookWrapper(u32 dummy, Handle handle, u32 type);
|
||||
Result GetHandleInfoHook(s64 *out, Handle handle, u32 type);
|
||||
@@ -30,4 +30,4 @@
|
||||
#include "kernel.h"
|
||||
#include "svc.h"
|
||||
|
||||
void SetWifiEnabled(bool enable);
|
||||
Result SetWifiEnabled(bool enable);
|
||||
|
||||
@@ -52,6 +52,7 @@ void (*KScheduler__AttemptSwitchingThreadContext)(KScheduler *this);
|
||||
Result (*ControlMemory)(u32 *addrOut, u32 addr0, u32 addr1, u32 size, MemOp op, MemPerm perm, bool isLoader);
|
||||
void (*SleepThread)(s64 ns);
|
||||
Result (*CloseHandle)(Handle handle);
|
||||
Result (*GetHandleInfo)(s64 *out, Handle handle, u32 type);
|
||||
Result (*GetSystemInfo)(s64 *out, s32 type, s32 param);
|
||||
Result (*GetProcessInfo)(s64 *out, Handle processHandle, u32 type);
|
||||
Result (*GetThreadInfo)(s64 *out, Handle threadHandle, u32 type);
|
||||
|
||||
@@ -208,6 +208,7 @@ static void findUsefulSymbols(void)
|
||||
decodeARMBranch((u32 *)officialSVCs[0x01] + 5);
|
||||
SleepThread = (void (*)(s64))officialSVCs[0x0A];
|
||||
CloseHandle = (Result (*)(Handle))officialSVCs[0x23];
|
||||
GetHandleInfo = (Result (*)(s64 *, Handle, u32))decodeARMBranch((u32 *)officialSVCs[0x29] + 3);
|
||||
GetSystemInfo = (Result (*)(s64 *, s32, s32))decodeARMBranch((u32 *)officialSVCs[0x2A] + 3);
|
||||
GetProcessInfo = (Result (*)(s64 *, Handle, u32))decodeARMBranch((u32 *)officialSVCs[0x2B] + 3);
|
||||
GetThreadInfo = (Result (*)(s64 *, Handle, u32))decodeARMBranch((u32 *)officialSVCs[0x2C] + 3);
|
||||
|
||||
@@ -28,9 +28,10 @@
|
||||
#include "synchronization.h"
|
||||
#include "svc.h"
|
||||
#include "svc/ControlMemory.h"
|
||||
#include "svc/GetHandleInfo.h"
|
||||
#include "svc/GetSystemInfo.h"
|
||||
#include "svc/GetProcessInfo.h"
|
||||
#include "svc/GetThreadInfo.h"
|
||||
#include "svc/GetSystemInfo.h"
|
||||
#include "svc/GetCFWInfo.h"
|
||||
#include "svc/ConnectToPort.h"
|
||||
#include "svc/SendSyncRequest.h"
|
||||
@@ -103,6 +104,8 @@ void *svcHook(u8 *pageEnd)
|
||||
doingVeryShittyPmResLimitWorkaround = true;
|
||||
}
|
||||
return officialSVCs[0x17];
|
||||
case 0x29:
|
||||
return GetHandleInfoHookWrapper;
|
||||
case 0x2A:
|
||||
return GetSystemInfoHookWrapper;
|
||||
case 0x2B:
|
||||
|
||||
@@ -42,20 +42,12 @@ Result ControlService(ServiceOp op, u32 varg1, u32 varg2)
|
||||
KAutoObject *obj = KProcessHandleTable__ToKAutoObject(handleTable, (Handle)varg2);
|
||||
if(obj == NULL)
|
||||
return 0xD8E007F7; // invalid handle
|
||||
else if(kernelVersion >= SYSTEM_VERSION(2, 46, 0))
|
||||
{
|
||||
KClassToken tok;
|
||||
obj->vtable->GetClassToken(&tok, obj);
|
||||
if(tok.flags == 0x95)
|
||||
session = ((KServerSession *)obj)->parentSession;
|
||||
else if(tok.flags == 0xA5)
|
||||
session = ((KClientSession *)obj)->parentSession;
|
||||
}
|
||||
else
|
||||
{ // not the exact same tests but it should work
|
||||
if(strcmp(obj->vtable->GetClassName(obj), "KServerSession") == 0)
|
||||
{
|
||||
// not the exact same tests but it should work
|
||||
if(strcmp(classNameOfAutoObject(obj), "KServerSession") == 0)
|
||||
session = ((KServerSession *)obj)->parentSession;
|
||||
else if(strcmp(obj->vtable->GetClassName(obj), "KClientSession") == 0)
|
||||
else if(strcmp(classNameOfAutoObject(obj), "KClientSession") == 0)
|
||||
session = ((KClientSession *)obj)->parentSession;
|
||||
}
|
||||
|
||||
|
||||
62
k11_extension/source/svc/GetHandleInfo.c
Normal file
62
k11_extension/source/svc/GetHandleInfo.c
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* This file is part of Luma3DS
|
||||
* Copyright (C) 2016-2017 Aurora Wright, TuxSH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <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 "svc/GetThreadInfo.h"
|
||||
#include "memory.h"
|
||||
|
||||
Result GetHandleInfoHook(s64 *out, Handle handle, u32 type)
|
||||
{
|
||||
if(type == 0x10000) // KDebug and KProcess: get context ID
|
||||
{
|
||||
KProcessHwInfo *hwInfo;
|
||||
KProcessHandleTable *handleTable = handleTableOfProcess(currentCoreContext->objectContext.currentProcess);
|
||||
KAutoObject *obj;
|
||||
if(handle == CUR_PROCESS_HANDLE)
|
||||
{
|
||||
obj = (KAutoObject *)(currentCoreContext->objectContext.currentProcess);
|
||||
KAutoObject__AddReference(obj);
|
||||
}
|
||||
else
|
||||
obj = KProcessHandleTable__ToKAutoObject(handleTable, handle);
|
||||
|
||||
if(obj == NULL)
|
||||
return 0xD8E007F7;
|
||||
|
||||
if(strcmp(classNameOfAutoObject(obj), "KDebug") == 0)
|
||||
hwInfo = hwInfoOfProcess(((KDebug *)obj)->owner);
|
||||
else if(strcmp(classNameOfAutoObject(obj), "KProcess") == 0)
|
||||
hwInfo = hwInfoOfProcess((KProcess *)obj);
|
||||
else
|
||||
hwInfo = NULL;
|
||||
|
||||
*out = hwInfo != NULL ? KPROCESSHWINFO_GET_RVALUE(hwInfo, contextId) : -1;
|
||||
|
||||
obj->vtable->DecrementReferenceCount(obj);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return GetHandleInfo(out, handle, type);
|
||||
}
|
||||
@@ -73,12 +73,12 @@ Result GetProcessInfoHook(s64 *out, Handle processHandle, u32 type)
|
||||
*out = (s64)(u64)(u32)codeSetOfProcess(process)->dataSection.section.loadAddress;
|
||||
break;
|
||||
case 0x10008:
|
||||
*out = (isN3DS ? hwInfoOfProcess(process)->N3DS.translationTableBase :
|
||||
(kernelVersion >= SYSTEM_VERSION(2, 44, 6)
|
||||
? hwInfoOfProcess(process)->O3DS8x.translationTableBase
|
||||
: hwInfoOfProcess(process)->O3DSPre8x.translationTableBase)
|
||||
) & ~((1 << (14 - TTBCR)) - 1);
|
||||
{
|
||||
KProcessHwInfo *hwInfo = hwInfoOfProcess(process);
|
||||
u32 ttb = KPROCESSHWINFO_GET_RVALUE(hwInfo, translationTableBase);
|
||||
*out = ttb & ~((1 << (14 - TTBCR)) - 1);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
res = 0xD8E007ED; // invalid enum value
|
||||
break;
|
||||
|
||||
@@ -37,15 +37,8 @@ Result SendSyncRequestHook(Handle handle)
|
||||
bool skip = false;
|
||||
Result res = 0;
|
||||
|
||||
bool isValidClientSession = false;
|
||||
if(clientSession != NULL && kernelVersion >= SYSTEM_VERSION(2, 46, 0))
|
||||
{
|
||||
KClassToken tok;
|
||||
clientSession->syncObject.autoObject.vtable->GetClassToken(&tok, &clientSession->syncObject.autoObject);
|
||||
isValidClientSession = tok.flags == 0xA5;
|
||||
}
|
||||
else if(clientSession != NULL) // not the exact same test but it should work
|
||||
isValidClientSession = strcmp(clientSession->syncObject.autoObject.vtable->GetClassName(&clientSession->syncObject.autoObject), "KClientSession") == 0;
|
||||
// not the exact same test but it should work
|
||||
bool isValidClientSession = clientSession != NULL && strcmp(classNameOfAutoObject(&clientSession->syncObject.autoObject), "KClientSession") == 0;
|
||||
|
||||
if(isValidClientSession)
|
||||
{
|
||||
@@ -54,7 +47,7 @@ Result SendSyncRequestHook(Handle handle)
|
||||
case 0x10042:
|
||||
{
|
||||
SessionInfo *info = SessionInfo_Lookup(clientSession->parentSession);
|
||||
if(info != NULL && strcmp(info->name, "srv:pm") == 0)
|
||||
if(info != NULL && kernelVersion >= SYSTEM_VERSION(2, 39, 4) && strcmp(info->name, "srv:pm") == 0)
|
||||
{
|
||||
res = doPublishToProcessHook(handle, cmdbuf);
|
||||
skip = true;
|
||||
@@ -112,7 +105,7 @@ Result SendSyncRequestHook(Handle handle)
|
||||
case 0x50100:
|
||||
{
|
||||
SessionInfo *info = SessionInfo_Lookup(clientSession->parentSession);
|
||||
if(info != NULL && strcmp(info->name, "srv:") == 0)
|
||||
if(info != NULL && (strcmp(info->name, "srv:") == 0 || (kernelVersion < SYSTEM_VERSION(2, 39, 4) && strcmp(info->name, "srv:pm") == 0)))
|
||||
{
|
||||
char name[9] = { 0 };
|
||||
memcpy(name, cmdbuf + 1, 8);
|
||||
@@ -126,7 +119,8 @@ Result SendSyncRequestHook(Handle handle)
|
||||
outClientSession = (KClientSession *)KProcessHandleTable__ToKAutoObject(handleTable, (Handle)cmdbuf[3]);
|
||||
if(outClientSession != NULL)
|
||||
{
|
||||
SessionInfo_Add(outClientSession->parentSession, name);
|
||||
if(strcmp(classNameOfAutoObject(&outClientSession->syncObject.autoObject), "KClientSession") == 0)
|
||||
SessionInfo_Add(outClientSession->parentSession, name);
|
||||
outClientSession->syncObject.autoObject.vtable->DecrementReferenceCount(&outClientSession->syncObject.autoObject);
|
||||
}
|
||||
}
|
||||
@@ -163,7 +157,7 @@ Result SendSyncRequestHook(Handle handle)
|
||||
case 0x4010042:
|
||||
{
|
||||
SessionInfo *info = SessionInfo_Lookup(clientSession->parentSession);
|
||||
if(info != NULL && strcmp(info->name, "srv:pm") == 0)
|
||||
if(info != NULL && kernelVersion < SYSTEM_VERSION(2, 39, 4) && strcmp(info->name, "srv:pm") == 0)
|
||||
{
|
||||
res = doPublishToProcessHook(handle, cmdbuf);
|
||||
skip = true;
|
||||
|
||||
@@ -26,10 +26,12 @@
|
||||
|
||||
#include "svc/SetWifiEnabled.h"
|
||||
|
||||
void SetWifiEnabled(bool enable)
|
||||
Result SetWifiEnabled(bool enable)
|
||||
{
|
||||
if(enable)
|
||||
CFG11_WIFICNT |= 1;
|
||||
else
|
||||
CFG11_WIFICNT &= ~1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -50,14 +50,7 @@ Result TranslateHandle(u32 *outKAddr, char *outClassName, Handle handle)
|
||||
if(obj == NULL)
|
||||
return 0xD8E007F7; // invalid handle
|
||||
|
||||
if(kernelVersion >= SYSTEM_VERSION(2, 46, 0))
|
||||
{
|
||||
KClassToken tok;
|
||||
obj->vtable->GetClassToken(&tok, obj);
|
||||
name = tok.name;
|
||||
}
|
||||
else
|
||||
name = obj->vtable->GetClassName(obj);
|
||||
name = classNameOfAutoObject(obj);
|
||||
|
||||
if(name == NULL) // shouldn't happen
|
||||
name = "KAutoObject";
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
pop {r1, r2, r12, pc}
|
||||
.endm
|
||||
|
||||
GEN_GETINFO_WRAPPER Handle
|
||||
GEN_GETINFO_WRAPPER System
|
||||
GEN_GETINFO_WRAPPER Process
|
||||
GEN_GETINFO_WRAPPER Thread
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
|
||||
#define DPAD_BUTTONS (BUTTON_LEFT | BUTTON_RIGHT | BUTTON_UP | BUTTON_DOWN)
|
||||
#define SAFE_MODE (BUTTON_R1 | BUTTON_L1 | BUTTON_A | BUTTON_UP)
|
||||
#define SINGLE_PAYLOAD_BUTTONS (DPAD_BUTTONS | BUTTON_B | BUTTON_X | BUTTON_Y)
|
||||
#define SINGLE_PAYLOAD_BUTTONS (BUTTON_B | BUTTON_X | BUTTON_Y)
|
||||
#define L_PAYLOAD_BUTTONS (BUTTON_R1 | BUTTON_A | BUTTON_START | BUTTON_SELECT)
|
||||
#define MENU_BUTTONS (DPAD_BUTTONS | BUTTON_A | BUTTON_START)
|
||||
#define PIN_BUTTONS (BUTTON_A | BUTTON_B | BUTTON_X | BUTTON_Y | DPAD_BUTTONS | BUTTON_START | BUTTON_SELECT)
|
||||
|
||||
@@ -152,7 +152,7 @@ void configMenu(bool oldPinStatus, u32 oldPinMode)
|
||||
|
||||
"Enable overriding the region and\n"
|
||||
"language configuration and the usage\n"
|
||||
"of patched code binaries,\n"
|
||||
"of patched code binaries, exHeaders,\n"
|
||||
"IPS code patches and LayeredFS\n"
|
||||
"for specific games.\n\n"
|
||||
"Also makes certain DLCs\n"
|
||||
|
||||
@@ -49,7 +49,6 @@ bool loadSplash(void)
|
||||
if(!isTopSplashValid && !isBottomSplashValid) return false;
|
||||
|
||||
initScreens();
|
||||
clearScreens(true);
|
||||
|
||||
if(isTopSplashValid) isTopSplashValid = fileRead(fbs[1].top_left, topSplashFile, SCREEN_TOP_FBSIZE) == SCREEN_TOP_FBSIZE;
|
||||
if(isBottomSplashValid) isBottomSplashValid = fileRead(fbs[1].bottom, bottomSplashFile, SCREEN_BOTTOM_FBSIZE) == SCREEN_BOTTOM_FBSIZE;
|
||||
|
||||
@@ -263,7 +263,7 @@ u32 vsprintf(char *buf, const char *fmt, va_list args)
|
||||
//Integer number formats - set up the flags and "break"
|
||||
case 'X':
|
||||
flags |= UPPERCASE;
|
||||
|
||||
//Falls through
|
||||
case 'x':
|
||||
isHex = true;
|
||||
break;
|
||||
@@ -271,7 +271,7 @@ u32 vsprintf(char *buf, const char *fmt, va_list args)
|
||||
case 'd':
|
||||
case 'i':
|
||||
flags |= SIGN;
|
||||
|
||||
//Falls through
|
||||
case 'u':
|
||||
isHex = false;
|
||||
break;
|
||||
|
||||
@@ -205,13 +205,15 @@ void main(int argc, char **argv, u32 magicWord)
|
||||
|
||||
if(splashMode == 1 && loadSplash()) pressed = HID_PAD;
|
||||
|
||||
bool autoBootEmu = CONFIG(AUTOBOOTEMU);
|
||||
|
||||
if((pressed & (BUTTON_START | BUTTON_L1)) == BUTTON_START)
|
||||
{
|
||||
loadHomebrewFirm(0);
|
||||
pressed = HID_PAD;
|
||||
}
|
||||
else if(((pressed & SINGLE_PAYLOAD_BUTTONS) && !(pressed & (BUTTON_L1 | BUTTON_R1 | BUTTON_A))) ||
|
||||
((pressed & L_PAYLOAD_BUTTONS) && (pressed & BUTTON_L1))) loadHomebrewFirm(pressed);
|
||||
else if((((pressed & SINGLE_PAYLOAD_BUTTONS) || (!autoBootEmu && (pressed & DPAD_BUTTONS))) && !(pressed & (BUTTON_L1 | BUTTON_R1))) ||
|
||||
(((pressed & L_PAYLOAD_BUTTONS) || (autoBootEmu && (pressed & DPAD_BUTTONS))) && (pressed & BUTTON_L1))) loadHomebrewFirm(pressed);
|
||||
|
||||
if(splashMode == 2) loadSplash();
|
||||
|
||||
@@ -235,7 +237,7 @@ void main(int argc, char **argv, u32 magicWord)
|
||||
|
||||
/* Else, boot the NAND the user set to autoboot or the opposite one, depending on L,
|
||||
with their own FIRM */
|
||||
else firmSource = nandType = (CONFIG(AUTOBOOTEMU) == ((pressed & BUTTON_L1) == BUTTON_L1)) ? FIRMWARE_SYSNAND : FIRMWARE_EMUNAND;
|
||||
else firmSource = nandType = (autoBootEmu == ((pressed & BUTTON_L1) == BUTTON_L1)) ? FIRMWARE_SYSNAND : FIRMWARE_EMUNAND;
|
||||
|
||||
//If we're booting EmuNAND or using EmuNAND FIRM, determine which one from the directional pad buttons, or otherwise from the config
|
||||
if(nandType == FIRMWARE_EMUNAND || firmSource == FIRMWARE_EMUNAND)
|
||||
|
||||
@@ -96,10 +96,12 @@ void initScreens(void)
|
||||
|
||||
if(needToSetup)
|
||||
{
|
||||
memcpy((void *)ARM11_PARAMETERS_ADDRESS, fbs, sizeof(fbs));
|
||||
invokeArm11Function(SETUP_FRAMEBUFFERS);
|
||||
|
||||
if(!ARESCREENSINITIALIZED)
|
||||
{
|
||||
*(vu32 *)ARM11_PARAMETERS_ADDRESS = brightness[MULTICONFIG(BRIGHTNESS)];
|
||||
memcpy((void *)(ARM11_PARAMETERS_ADDRESS + 4), fbs, sizeof(fbs));
|
||||
invokeArm11Function(INIT_SCREENS);
|
||||
|
||||
//Turn on backlight
|
||||
@@ -107,10 +109,10 @@ void initScreens(void)
|
||||
}
|
||||
else updateBrightness(MULTICONFIG(BRIGHTNESS));
|
||||
|
||||
clearScreens(true);
|
||||
needToSetup = false;
|
||||
}
|
||||
|
||||
clearScreens(false);
|
||||
clearScreens(true);
|
||||
swapFramebuffers(false);
|
||||
}
|
||||
|
||||
@@ -54,6 +54,7 @@ struct fb {
|
||||
typedef enum
|
||||
{
|
||||
INIT_SCREENS = 0,
|
||||
SETUP_FRAMEBUFFERS,
|
||||
CLEAR_SCREENS,
|
||||
SWAP_FRAMEBUFFERS,
|
||||
UPDATE_BRIGHTNESS,
|
||||
|
||||
@@ -64,17 +64,20 @@ _start:
|
||||
load r3, customPath
|
||||
pathRedir_1:
|
||||
ldrb r2, [r3], #1
|
||||
strh r2, [r0], #2
|
||||
cmp r2, #0
|
||||
strneh r2, [r0], #2
|
||||
bne pathRedir_1
|
||||
sub r0, r0, #2
|
||||
pathRedir_2:
|
||||
ldrh r2, [r1], #2
|
||||
cmp r2, #0x3A ; ':'
|
||||
bne pathRedir_2
|
||||
; Skip a slash if there are two after the mountpoint,
|
||||
; as some games mistakenly have those
|
||||
ldrh r3, [r1, #2]
|
||||
cmp r3, #0x2F ; '/'
|
||||
pathRedir_3:
|
||||
ldrh r2, [r1], #2
|
||||
strh r2, [r0], #2
|
||||
strneh r2, [r0], #2
|
||||
cmp r2, #0
|
||||
bne pathRedir_3
|
||||
ldmfd sp!, {r0-r3}
|
||||
|
||||
@@ -11,6 +11,9 @@
|
||||
#define MAX_SESSIONS 1
|
||||
#define HBLDR_3DSX_TID (*(vu64 *)0x1FF81100)
|
||||
|
||||
u32 config, multiConfig, bootConfig;
|
||||
bool isN3DS, isSafeMode, isSdMode;
|
||||
|
||||
const char CODE_PATH[] = {0x01, 0x00, 0x00, 0x00, 0x2E, 0x63, 0x6F, 0x64, 0x65, 0x00, 0x00, 0x00};
|
||||
|
||||
typedef struct
|
||||
@@ -30,6 +33,28 @@ static u64 g_cached_prog_handle;
|
||||
static exheader_header g_exheader;
|
||||
static char g_ret_buf[1024];
|
||||
|
||||
static inline void loadCFWInfo(void)
|
||||
{
|
||||
s64 out;
|
||||
|
||||
if(R_FAILED(svcGetSystemInfo(&out, 0x10000, 3))) svcBreak(USERBREAK_ASSERT);
|
||||
config = (u32)out;
|
||||
if(R_FAILED(svcGetSystemInfo(&out, 0x10000, 4))) svcBreak(USERBREAK_ASSERT);
|
||||
multiConfig = (u32)out;
|
||||
if(R_FAILED(svcGetSystemInfo(&out, 0x10000, 5))) svcBreak(USERBREAK_ASSERT);
|
||||
bootConfig = (u32)out;
|
||||
|
||||
if(R_FAILED(svcGetSystemInfo(&out, 0x10000, 0x201))) svcBreak(USERBREAK_ASSERT);
|
||||
isN3DS = (bool)out;
|
||||
if(R_FAILED(svcGetSystemInfo(&out, 0x10000, 0x202))) svcBreak(USERBREAK_ASSERT);
|
||||
isSafeMode = (bool)out;
|
||||
if(R_FAILED(svcGetSystemInfo(&out, 0x10000, 0x203))) svcBreak(USERBREAK_ASSERT);
|
||||
isSdMode = (bool)out;
|
||||
|
||||
IFile file;
|
||||
if(isSafeMode) fileOpen(&file, ARCHIVE_SDMC, "/", FS_OPEN_READ); //Init SD card if SAFE_MODE is being booted
|
||||
}
|
||||
|
||||
static int lzss_decompress(u8 *end)
|
||||
{
|
||||
unsigned int v1; // r1@2
|
||||
@@ -116,44 +141,47 @@ static Result load_code(u64 progid, prog_addrs_t *shared, u64 prog_handle, int i
|
||||
u64 size;
|
||||
u64 total;
|
||||
|
||||
archivePath.type = PATH_BINARY;
|
||||
archivePath.data = &prog_handle;
|
||||
archivePath.size = 8;
|
||||
|
||||
filePath.type = PATH_BINARY;
|
||||
filePath.data = CODE_PATH;
|
||||
filePath.size = sizeof(CODE_PATH);
|
||||
if (R_FAILED(IFile_Open(&file, ARCHIVE_SAVEDATA_AND_CONTENT2, archivePath, filePath, FS_OPEN_READ)))
|
||||
if(!CONFIG(PATCHGAMES) || !loadTitleCodeSection(progid, (u8 *)shared->text_addr, (u64)shared->total_size << 12))
|
||||
{
|
||||
svcBreak(USERBREAK_ASSERT);
|
||||
}
|
||||
archivePath.type = PATH_BINARY;
|
||||
archivePath.data = &prog_handle;
|
||||
archivePath.size = 8;
|
||||
|
||||
// get file size
|
||||
if (R_FAILED(IFile_GetSize(&file, &size)))
|
||||
{
|
||||
IFile_Close(&file);
|
||||
svcBreak(USERBREAK_ASSERT);
|
||||
}
|
||||
filePath.type = PATH_BINARY;
|
||||
filePath.data = CODE_PATH;
|
||||
filePath.size = sizeof(CODE_PATH);
|
||||
if (R_FAILED(IFile_Open(&file, ARCHIVE_SAVEDATA_AND_CONTENT2, archivePath, filePath, FS_OPEN_READ)))
|
||||
{
|
||||
svcBreak(USERBREAK_ASSERT);
|
||||
}
|
||||
|
||||
// check size
|
||||
if (size > (u64)shared->total_size << 12)
|
||||
{
|
||||
IFile_Close(&file);
|
||||
return 0xC900464F;
|
||||
}
|
||||
// get file size
|
||||
if (R_FAILED(IFile_GetSize(&file, &size)))
|
||||
{
|
||||
IFile_Close(&file);
|
||||
svcBreak(USERBREAK_ASSERT);
|
||||
}
|
||||
|
||||
// read code
|
||||
res = IFile_Read(&file, &total, (void *)shared->text_addr, size);
|
||||
IFile_Close(&file); // done reading
|
||||
if (R_FAILED(res))
|
||||
{
|
||||
svcBreak(USERBREAK_ASSERT);
|
||||
}
|
||||
// check size
|
||||
if (size > (u64)shared->total_size << 12)
|
||||
{
|
||||
IFile_Close(&file);
|
||||
return 0xC900464F;
|
||||
}
|
||||
|
||||
// decompress
|
||||
if (is_compressed)
|
||||
{
|
||||
lzss_decompress((u8 *)shared->text_addr + size);
|
||||
// read code
|
||||
res = IFile_Read(&file, &total, (void *)shared->text_addr, size);
|
||||
IFile_Close(&file); // done reading
|
||||
if (R_FAILED(res))
|
||||
{
|
||||
svcBreak(USERBREAK_ASSERT);
|
||||
}
|
||||
|
||||
// decompress
|
||||
if (is_compressed)
|
||||
{
|
||||
lzss_decompress((u8 *)shared->text_addr + size);
|
||||
}
|
||||
}
|
||||
|
||||
u16 progver = g_exheader.codesetinfo.flags.remasterversion[0] | (g_exheader.codesetinfo.flags.remasterversion[1] << 8);
|
||||
@@ -212,21 +240,31 @@ static Result loader_GetProgramInfo(exheader_header *exheader, u64 prog_handle)
|
||||
exheader->accessdesc.arm11systemlocalcaps.storageinfo.accessinfo[0] |= 0x480;
|
||||
|
||||
// Tweak 3dsx placeholder title exheader
|
||||
if (nbSection0Modules == 6 && exheader->arm11systemlocalcaps.programid == HBLDR_3DSX_TID)
|
||||
if (nbSection0Modules == 6)
|
||||
{
|
||||
Handle hbldr = 0;
|
||||
res = HBLDR_Init(&hbldr);
|
||||
if (R_SUCCEEDED(res))
|
||||
if(exheader->arm11systemlocalcaps.programid == HBLDR_3DSX_TID)
|
||||
{
|
||||
u32* cmdbuf = getThreadCommandBuffer();
|
||||
cmdbuf[0] = IPC_MakeHeader(4,0,2);
|
||||
cmdbuf[1] = IPC_Desc_Buffer(sizeof(*exheader), IPC_BUFFER_RW);
|
||||
cmdbuf[2] = (u32)exheader;
|
||||
res = svcSendSyncRequest(hbldr);
|
||||
svcCloseHandle(hbldr);
|
||||
if (R_SUCCEEDED(res)) {
|
||||
res = cmdbuf[1];
|
||||
}
|
||||
Handle hbldr = 0;
|
||||
res = HBLDR_Init(&hbldr);
|
||||
if (R_SUCCEEDED(res))
|
||||
{
|
||||
u32* cmdbuf = getThreadCommandBuffer();
|
||||
cmdbuf[0] = IPC_MakeHeader(4,0,2);
|
||||
cmdbuf[1] = IPC_Desc_Buffer(sizeof(*exheader), IPC_BUFFER_RW);
|
||||
cmdbuf[2] = (u32)exheader;
|
||||
res = svcSendSyncRequest(hbldr);
|
||||
svcCloseHandle(hbldr);
|
||||
if (R_SUCCEEDED(res)) {
|
||||
res = cmdbuf[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
u64 originalProgId = exheader->arm11systemlocalcaps.programid;
|
||||
if(CONFIG(PATCHGAMES) && loadTitleExheader(exheader->arm11systemlocalcaps.programid, exheader))
|
||||
{
|
||||
exheader->arm11systemlocalcaps.programid = originalProgId;
|
||||
exheader->accessdesc.arm11systemlocalcaps.programid = originalProgId;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -586,6 +624,8 @@ int main()
|
||||
svcBreak(USERBREAK_ASSERT);
|
||||
}
|
||||
|
||||
loadCFWInfo();
|
||||
|
||||
g_active_handles = 2;
|
||||
g_cached_prog_handle = 0;
|
||||
index = 1;
|
||||
|
||||
@@ -3,12 +3,8 @@
|
||||
#include "memory.h"
|
||||
#include "strings.h"
|
||||
#include "fsldr.h"
|
||||
#include "ifile.h"
|
||||
#include "../build/bundled.h"
|
||||
|
||||
static u32 config, multiConfig, bootConfig;
|
||||
static bool isN3DS, isSafeMode, isSdMode;
|
||||
|
||||
static u32 patchMemory(u8 *start, u32 size, const void *pattern, u32 patSize, s32 offset, const void *replace, u32 repSize, u32 count)
|
||||
{
|
||||
u32 i;
|
||||
@@ -32,7 +28,7 @@ static u32 patchMemory(u8 *start, u32 size, const void *pattern, u32 patSize, s3
|
||||
return i;
|
||||
}
|
||||
|
||||
static Result fileOpen(IFile *file, FS_ArchiveID archiveId, const char *path, int flags)
|
||||
Result fileOpen(IFile *file, FS_ArchiveID archiveId, const char *path, int flags)
|
||||
{
|
||||
FS_Path filePath = {PATH_ASCII, strnlen(path, 255) + 1, path},
|
||||
archivePath = {PATH_EMPTY, 1, (u8 *)""};
|
||||
@@ -73,32 +69,6 @@ static u32 checkLumaDir(const char *path)
|
||||
return dirCheck(archiveId, path) ? archiveId : 0;
|
||||
}
|
||||
|
||||
static inline void loadCFWInfo(void)
|
||||
{
|
||||
static bool infoLoaded = false;
|
||||
s64 out;
|
||||
|
||||
if(infoLoaded) return;
|
||||
|
||||
if(R_FAILED(svcGetSystemInfo(&out, 0x10000, 3))) svcBreak(USERBREAK_ASSERT);
|
||||
config = (u32)out;
|
||||
if(R_FAILED(svcGetSystemInfo(&out, 0x10000, 4))) svcBreak(USERBREAK_ASSERT);
|
||||
multiConfig = (u32)out;
|
||||
if(R_FAILED(svcGetSystemInfo(&out, 0x10000, 5))) svcBreak(USERBREAK_ASSERT);
|
||||
bootConfig = (u32)out;
|
||||
|
||||
if(R_FAILED(svcGetSystemInfo(&out, 0x10000, 0x201))) svcBreak(USERBREAK_ASSERT);
|
||||
isN3DS = (bool)out;
|
||||
if(R_FAILED(svcGetSystemInfo(&out, 0x10000, 0x202))) svcBreak(USERBREAK_ASSERT);
|
||||
isSafeMode = (bool)out;
|
||||
if(R_FAILED(svcGetSystemInfo(&out, 0x10000, 0x203))) svcBreak(USERBREAK_ASSERT);
|
||||
isSdMode = (bool)out;
|
||||
|
||||
IFile file;
|
||||
if(isSafeMode) fileOpen(&file, ARCHIVE_SDMC, "/", FS_OPEN_READ); //Init SD card if SAFE_MODE is being booted
|
||||
infoLoaded = true;
|
||||
}
|
||||
|
||||
static inline bool secureInfoExists(void)
|
||||
{
|
||||
static bool exists = false;
|
||||
@@ -353,7 +323,7 @@ exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline bool loadTitleCodeSection(u64 progId, u8 *code, u32 size)
|
||||
bool loadTitleCodeSection(u64 progId, u8 *code, u32 size)
|
||||
{
|
||||
/* Here we look for "/luma/titles/[u64 titleID in hex, uppercase]/code.bin"
|
||||
If it exists it should be a decrypted and decompressed binary code file */
|
||||
@@ -363,22 +333,60 @@ static inline bool loadTitleCodeSection(u64 progId, u8 *code, u32 size)
|
||||
|
||||
IFile file;
|
||||
|
||||
if(!openLumaFile(&file, path)) return true;
|
||||
if(!openLumaFile(&file, path)) return false;
|
||||
|
||||
bool ret;
|
||||
u64 fileSize;
|
||||
|
||||
if(R_FAILED(IFile_GetSize(&file, &fileSize)) || fileSize > size) ret = false;
|
||||
if(R_FAILED(IFile_GetSize(&file, &fileSize)) || fileSize > size) goto error;
|
||||
else
|
||||
{
|
||||
u64 total;
|
||||
|
||||
ret = R_SUCCEEDED(IFile_Read(&file, &total, code, fileSize)) && total == fileSize;
|
||||
if(R_FAILED(IFile_Read(&file, &total, code, fileSize)) || total != fileSize) goto error;
|
||||
}
|
||||
|
||||
IFile_Close(&file);
|
||||
|
||||
return ret;
|
||||
return true;
|
||||
|
||||
error:
|
||||
IFile_Close(&file);
|
||||
|
||||
svcBreak(USERBREAK_ASSERT);
|
||||
while(true);
|
||||
}
|
||||
|
||||
bool loadTitleExheader(u64 progId, exheader_header *exheader)
|
||||
{
|
||||
/* Here we look for "/luma/titles/[u64 titleID in hex, uppercase]/exheader.bin"
|
||||
If it exists it should be a decrypted exheader */
|
||||
|
||||
char path[] = "/luma/titles/0000000000000000/exheader.bin";
|
||||
progIdToStr(path + 28, progId);
|
||||
|
||||
IFile file;
|
||||
|
||||
if(!openLumaFile(&file, path)) return false;
|
||||
|
||||
u64 fileSize;
|
||||
|
||||
if(R_FAILED(IFile_GetSize(&file, &fileSize)) || fileSize != sizeof(exheader_header)) goto error;
|
||||
else
|
||||
{
|
||||
u64 total;
|
||||
|
||||
if(R_FAILED(IFile_Read(&file, &total, exheader, fileSize)) || total != fileSize) goto error;
|
||||
}
|
||||
|
||||
IFile_Close(&file);
|
||||
|
||||
return true;
|
||||
|
||||
error:
|
||||
IFile_Close(&file);
|
||||
|
||||
svcBreak(USERBREAK_ASSERT);
|
||||
while(true);
|
||||
}
|
||||
|
||||
static inline bool loadTitleLocaleConfig(u64 progId, u8 *mask, u8 *regionId, u8 *languageId, u8 *countryId, u8 *stateId)
|
||||
@@ -570,8 +578,6 @@ static inline bool patchLayeredFs(u64 progId, u8 *code, u32 size, u32 textSize,
|
||||
|
||||
void patchCode(u64 progId, u16 progVer, u8 *code, u32 size, u32 textSize, u32 roSize, u32 dataSize, u32 roAddress, u32 dataAddress)
|
||||
{
|
||||
loadCFWInfo();
|
||||
|
||||
if(progId == 0x0004003000008F02LL || //USA Home Menu
|
||||
progId == 0x0004003000008202LL || //JPN Home Menu
|
||||
progId == 0x0004003000009802LL || //EUR Home Menu
|
||||
@@ -873,8 +879,7 @@ void patchCode(u64 progId, u16 progVer, u8 *code, u32 size, u32 textSize, u32 ro
|
||||
|
||||
if(CONFIG(PATCHGAMES))
|
||||
{
|
||||
if(!loadTitleCodeSection(progId, code, size) ||
|
||||
!applyCodeIpsPatch(progId, code, size)) goto error;
|
||||
if(!applyCodeIpsPatch(progId, code, size)) goto error;
|
||||
|
||||
if((u32)((progId >> 0x20) & 0xFFFFFFEDULL) == 0x00040000)
|
||||
{
|
||||
@@ -894,5 +899,4 @@ void patchCode(u64 progId, u16 progVer, u8 *code, u32 size, u32 textSize, u32 ro
|
||||
|
||||
error:
|
||||
svcBreak(USERBREAK_ASSERT);
|
||||
while(true);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <3ds/types.h>
|
||||
#include "exheader.h"
|
||||
#include "ifile.h"
|
||||
|
||||
#define MAKE_BRANCH(src,dst) (0xEA000000 | ((u32)((((u8 *)(dst) - (u8 *)(src)) >> 2) - 2) & 0xFFFFFF))
|
||||
#define MAKE_BRANCH_LINK(src,dst) (0xEB000000 | ((u32)((((u8 *)(dst) - (u8 *)(src)) >> 2) - 2) & 0xFFFFFF))
|
||||
@@ -35,4 +37,10 @@ enum singleOptions
|
||||
DISABLEARM11EXCHANDLERS
|
||||
};
|
||||
|
||||
extern u32 config, multiConfig, bootConfig;
|
||||
extern bool isN3DS, isSafeMode, isSdMode;
|
||||
|
||||
void patchCode(u64 progId, u16 progVer, u8 *code, u32 size, u32 textSize, u32 roSize, u32 dataSize, u32 roAddress, u32 dataAddress);
|
||||
Result fileOpen(IFile *file, FS_ArchiveID archiveId, const char *path, int flags);
|
||||
bool loadTitleCodeSection(u64 progId, u8 *code, u32 size);
|
||||
bool loadTitleExheader(u64 progId, exheader_header *exheader);
|
||||
|
||||
@@ -63,6 +63,7 @@
|
||||
#define COLOR_TITLE RGB565(0x00, 0x26, 0x1F)
|
||||
#define COLOR_WHITE RGB565(0x1F, 0x3F, 0x1F)
|
||||
#define COLOR_RED RGB565(0x1F, 0x00, 0x00)
|
||||
#define COLOR_GREEN RGB565(0x00, 0x1F, 0x00)
|
||||
#define COLOR_BLACK RGB565(0x00, 0x00, 0x00)
|
||||
|
||||
#define DRAW_MAX_FORMATTED_STRING_SIZE 512
|
||||
|
||||
37
sysmodules/rosalina/include/mcu.h
Normal file
37
sysmodules/rosalina/include/mcu.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* This file is part of Luma3DS
|
||||
* Copyright (C) 2016-2017 Aurora Wright, TuxSH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <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.h>
|
||||
|
||||
Handle mcuhwcHandle;
|
||||
|
||||
Result mcuInit(void);
|
||||
Result mcuExit(void);
|
||||
Result mcuReadRegister(u8 reg, u8* data, u32 size);
|
||||
Result mcuWriteRegister(u8 reg, u8* data, u32 size);
|
||||
Result mcuGetLEDState(u8* out);
|
||||
@@ -35,3 +35,5 @@ extern Menu rosalinaMenu;
|
||||
void RosalinaMenu_TakeScreenshot(void);
|
||||
void RosalinaMenu_ShowCredits(void);
|
||||
void RosalinaMenu_ProcessList(void);
|
||||
void RosalinaMenu_PowerOff(void);
|
||||
void RosalinaMenu_Reboot(void);
|
||||
|
||||
@@ -35,5 +35,3 @@ void MiscellaneousMenu_SwitchBoot3dsxTargetTitle(void);
|
||||
void MiscellaneousMenu_ChangeMenuCombo(void);
|
||||
void MiscellaneousMenu_SaveSettings(void);
|
||||
void MiscellaneousMenu_InputRedirection(void);
|
||||
void MiscellaneousMenu_PowerOff(void);
|
||||
void MiscellaneousMenu_Reboot(void);
|
||||
|
||||
35
sysmodules/rosalina/include/menus/sysconfig.h
Normal file
35
sysmodules/rosalina/include/menus/sysconfig.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* This file is part of Luma3DS
|
||||
* Copyright (C) 2016-2017 Aurora Wright, TuxSH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <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>
|
||||
#include "menu.h"
|
||||
|
||||
extern Menu sysconfigMenu;
|
||||
|
||||
void SysConfigMenu_ToggleLEDs(void);
|
||||
void SysConfigMenu_ToggleWireless(void);
|
||||
@@ -1,7 +1,7 @@
|
||||
BasicInfo:
|
||||
Title : rosalina
|
||||
CompanyCode : "00"
|
||||
ProductCode : 0828builder
|
||||
ProductCode : lennybuilder
|
||||
ContentType : Application
|
||||
Logo : None
|
||||
|
||||
@@ -47,13 +47,13 @@ AccessControlInfo:
|
||||
# We're using the global custom bit31 mapping
|
||||
|
||||
SystemCallAccess:
|
||||
# The kernel extension removes svc perms checks, so...
|
||||
SendSyncRequest2: 47 # CustomBackdoor
|
||||
UnmapProcessMemory: 114
|
||||
# The kernel extension removes svc perms checks, so below is just to avoid a makerom error
|
||||
Backdoor: 123
|
||||
KernelSetState: 124
|
||||
|
||||
InterruptNumbers:
|
||||
ServiceAccessControl:
|
||||
- srv:pm
|
||||
- fs:USER # Not strictly needed as rosalina has access to everything, it's rather to avoid a makerom warning
|
||||
FileSystemAccess:
|
||||
- DirectSdmc
|
||||
- CtrNandRw
|
||||
|
||||
@@ -29,6 +29,8 @@
|
||||
#include "draw.h"
|
||||
#include "menu.h"
|
||||
#include "memory.h"
|
||||
#include "fmt.h"
|
||||
#include "ifile.h"
|
||||
|
||||
static inline void assertSuccess(Result res)
|
||||
{
|
||||
@@ -37,13 +39,13 @@ static inline void assertSuccess(Result res)
|
||||
}
|
||||
|
||||
static MyThread errDispThread;
|
||||
static u8 ALIGN(8) errDispThreadStack[THREAD_STACK_SIZE];
|
||||
static u8 ALIGN(8) errDispThreadStack[0x2000];
|
||||
|
||||
static char userString[0x100 + 1] = {0};
|
||||
|
||||
MyThread *errDispCreateThread(void)
|
||||
{
|
||||
if(R_FAILED(MyThread_Create(&errDispThread, errDispThreadMain, errDispThreadStack, THREAD_STACK_SIZE, 0x18, CORE_SYSTEM)))
|
||||
if(R_FAILED(MyThread_Create(&errDispThread, errDispThreadMain, errDispThreadStack, 0x2000, 0x18, CORE_SYSTEM)))
|
||||
svcBreak(USERBREAK_PANIC);
|
||||
return &errDispThread;
|
||||
}
|
||||
@@ -53,12 +55,14 @@ static inline u32 ERRF_DisplayRegisterValue(u32 posX, u32 posY, const char *name
|
||||
return Draw_DrawFormattedString(posX, posY, COLOR_WHITE, "%-9s %08x", name, value);
|
||||
}
|
||||
|
||||
void ERRF_DisplayError(ERRF_FatalErrInfo *info)
|
||||
static inline int ERRF_FormatRegisterValue(char *out, const char *name, u32 value)
|
||||
{
|
||||
Draw_Lock();
|
||||
|
||||
u32 posY = Draw_DrawString(10, 10, COLOR_RED, userString[0] == 0 ? "An error occurred (ErrDisp)" : userString);
|
||||
return sprintf(out, "%-9s %08x", name, value);
|
||||
}
|
||||
|
||||
static int ERRF_FormatError(char *out, ERRF_FatalErrInfo *info)
|
||||
{
|
||||
char *outStart = out;
|
||||
static const char *types[] = {
|
||||
"generic", "corrupted", "card removed", "exception", "result failure", "logged", "invalid"
|
||||
};
|
||||
@@ -68,25 +72,23 @@ void ERRF_DisplayError(ERRF_FatalErrInfo *info)
|
||||
};
|
||||
|
||||
const char *type = (u32)info->type > (u32)ERRF_ERRTYPE_LOGGED ? types[6] : types[(u32)info->type];
|
||||
posY = posY < 30 ? 30 : posY;
|
||||
|
||||
if(info->type == ERRF_ERRTYPE_EXCEPTION)
|
||||
{
|
||||
const char *exceptionType = (u32)info->data.exception_data.excep.type > (u32)ERRF_EXCEPTION_VFP ?
|
||||
exceptionTypes[4] : exceptionTypes[(u32)info->data.exception_data.excep.type];
|
||||
|
||||
Draw_DrawFormattedString(10, posY, COLOR_WHITE, "Error type: exception (%s)", exceptionType);
|
||||
out += sprintf(out, "Error type: exception (%s)\n", exceptionType);
|
||||
}
|
||||
else
|
||||
Draw_DrawFormattedString(10, posY, COLOR_WHITE, "Error type: %s", type);
|
||||
out += sprintf(out, "Error type: %s\n", type);
|
||||
|
||||
if(info->type != ERRF_ERRTYPE_CARD_REMOVED)
|
||||
{
|
||||
Handle processHandle;
|
||||
Result res;
|
||||
|
||||
posY += SPACING_Y;
|
||||
posY = Draw_DrawFormattedString(10, posY + SPACING_Y, COLOR_WHITE, "Process ID: %u", info->procId);
|
||||
out += sprintf(out, "\nProcess ID: %u\n", info->procId);
|
||||
|
||||
res = svcOpenProcess(&processHandle, info->procId);
|
||||
if(R_SUCCEEDED(res))
|
||||
@@ -96,11 +98,11 @@ void ERRF_DisplayError(ERRF_FatalErrInfo *info)
|
||||
svcGetProcessInfo((s64 *)name, processHandle, 0x10000);
|
||||
svcGetProcessInfo((s64 *)&titleId, processHandle, 0x10001);
|
||||
svcCloseHandle(processHandle);
|
||||
posY = Draw_DrawFormattedString(10, posY + SPACING_Y, COLOR_WHITE, "Process name: %s", name);
|
||||
posY = Draw_DrawFormattedString(10, posY + SPACING_Y, COLOR_WHITE, "Process title ID: 0x%016llx", titleId);
|
||||
out += sprintf(out, "Process name: %s\n", name);
|
||||
out += sprintf(out, "Process title ID: 0x%016llx\n", titleId);
|
||||
}
|
||||
|
||||
posY += SPACING_Y;
|
||||
out += sprintf(out, "\n");
|
||||
}
|
||||
|
||||
if(info->type == ERRF_ERRTYPE_EXCEPTION)
|
||||
@@ -113,33 +115,43 @@ void ERRF_DisplayError(ERRF_FatalErrInfo *info)
|
||||
u32 *regs = (u32 *)(&info->data.exception_data.regs);
|
||||
for(u32 i = 0; i < 17; i += 2)
|
||||
{
|
||||
posY = ERRF_DisplayRegisterValue(10, posY + SPACING_Y, registerNames[i], regs[i]);
|
||||
|
||||
out += ERRF_FormatRegisterValue(out, registerNames[i], regs[i]);
|
||||
if(i != 16)
|
||||
ERRF_DisplayRegisterValue(10 + 28 * SPACING_X, posY, registerNames[i + 1], i == 16 ? regs[20] : regs[i + 1]);
|
||||
{
|
||||
out += sprintf(out, " ");
|
||||
out += ERRF_FormatRegisterValue(out, registerNames[i + 1], i == 16 ? regs[20] : regs[i + 1]);
|
||||
out += sprintf(out, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
if(info->data.exception_data.excep.type == ERRF_EXCEPTION_PREFETCH_ABORT
|
||||
|| info->data.exception_data.excep.type == ERRF_EXCEPTION_DATA_ABORT)
|
||||
{
|
||||
ERRF_DisplayRegisterValue(10 + 28 * SPACING_X, posY, "far", info->data.exception_data.excep.far);
|
||||
posY = ERRF_DisplayRegisterValue(10, posY + SPACING_Y, "fsr", info->data.exception_data.excep.fsr);
|
||||
out += sprintf(out, " ");
|
||||
out += ERRF_FormatRegisterValue(out, "far", info->data.exception_data.excep.far);
|
||||
out += sprintf(out, "\n");
|
||||
out += ERRF_FormatRegisterValue(out, "fsr", info->data.exception_data.excep.fsr);
|
||||
}
|
||||
|
||||
else if(info->data.exception_data.excep.type == ERRF_EXCEPTION_VFP)
|
||||
{
|
||||
ERRF_DisplayRegisterValue(10 + 28 * SPACING_X, posY, "fpexc", info->data.exception_data.excep.fpexc);
|
||||
posY = ERRF_DisplayRegisterValue(10, posY + SPACING_Y, "fpinst", info->data.exception_data.excep.fpinst);
|
||||
ERRF_DisplayRegisterValue(10 + 28 * SPACING_X, posY, "fpinst2", info->data.exception_data.excep.fpinst2);
|
||||
out += sprintf(out, " ");
|
||||
out += ERRF_FormatRegisterValue(out, "fpexc", info->data.exception_data.excep.fpexc);
|
||||
out += sprintf(out, "\n");
|
||||
out += ERRF_FormatRegisterValue(out, "fpinst", info->data.exception_data.excep.fpinst);
|
||||
out += sprintf(out, " ");
|
||||
out += ERRF_FormatRegisterValue(out, "fpinst2", info->data.exception_data.excep.fpinst2);
|
||||
out += sprintf(out, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
out += sprintf(out, "\n");
|
||||
}
|
||||
else if(info->type != ERRF_ERRTYPE_CARD_REMOVED)
|
||||
{
|
||||
if(info->type != ERRF_ERRTYPE_FAILURE)
|
||||
posY = Draw_DrawFormattedString(10, posY + SPACING_Y, COLOR_WHITE, "Address: 0x%08x", info->pcAddr);
|
||||
out += sprintf(out, "Address: 0x%08x\n", info->pcAddr);
|
||||
|
||||
posY = Draw_DrawFormattedString(10, posY + SPACING_Y, COLOR_WHITE, "Error code: 0x%08x", info->resCode);
|
||||
out += sprintf(out, "Error code: 0x%08x\n", info->resCode);
|
||||
}
|
||||
|
||||
const char *desc;
|
||||
@@ -160,16 +172,70 @@ void ERRF_DisplayError(ERRF_FatalErrInfo *info)
|
||||
break;
|
||||
}
|
||||
|
||||
posY += SPACING_Y;
|
||||
if(desc[0] != 0)
|
||||
posY = Draw_DrawString(10, posY + SPACING_Y, COLOR_WHITE, desc) + SPACING_Y;
|
||||
posY = Draw_DrawString(10, posY + SPACING_Y, COLOR_WHITE, "Press any button to reboot");
|
||||
out += sprintf(out, "\n%s\n", desc);
|
||||
out += sprintf(out, "\n");
|
||||
return out - outStart;
|
||||
}
|
||||
|
||||
|
||||
static void ERRF_DisplayError(ERRF_FatalErrInfo *info)
|
||||
{
|
||||
Draw_Lock();
|
||||
|
||||
u32 posY = Draw_DrawString(10, 10, COLOR_RED, userString[0] == 0 ? "An error occurred (ErrDisp)" : userString);
|
||||
char buf[0x400];
|
||||
|
||||
ERRF_FormatError(buf, info);
|
||||
posY = posY < 30 ? 30 : posY;
|
||||
|
||||
posY = Draw_DrawString(10, posY, COLOR_WHITE, buf);
|
||||
posY = Draw_DrawString(10, posY + SPACING_Y, COLOR_WHITE, "Press any button to reboot.");
|
||||
|
||||
Draw_FlushFramebuffer();
|
||||
Draw_Unlock();
|
||||
}
|
||||
|
||||
void ERRF_HandleCommands(void)
|
||||
static Result ERRF_SaveErrorToFile(ERRF_FatalErrInfo *info)
|
||||
{
|
||||
char buf[0x400];
|
||||
|
||||
FS_ArchiveID archiveId;
|
||||
s64 out;
|
||||
u64 size, total;
|
||||
bool isSdMode;
|
||||
int n = 0;
|
||||
Result res = 0;
|
||||
IFile file;
|
||||
|
||||
n = ERRF_FormatError(buf, info);
|
||||
n += sprintf(buf + n, "-------------------------------------\n\n");
|
||||
|
||||
if(R_FAILED(svcGetSystemInfo(&out, 0x10000, 0x203))) svcBreak(USERBREAK_ASSERT);
|
||||
isSdMode = (bool)out;
|
||||
|
||||
archiveId = isSdMode ? ARCHIVE_SDMC : ARCHIVE_NAND_RW;
|
||||
res = IFile_Open(&file, archiveId, fsMakePath(PATH_EMPTY, ""), fsMakePath(PATH_ASCII, "/luma/errdisp.txt"), FS_OPEN_WRITE | FS_OPEN_CREATE);
|
||||
|
||||
if(R_FAILED(res))
|
||||
return res;
|
||||
|
||||
res = IFile_GetSize(&file, &size);
|
||||
if(R_FAILED(res))
|
||||
{
|
||||
IFile_Close(&file);
|
||||
return res;
|
||||
}
|
||||
|
||||
file.pos = size;
|
||||
|
||||
res = IFile_Write(&file, &total, buf, (u32)n, 0);
|
||||
IFile_Close(&file);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static void ERRF_HandleCommands(void)
|
||||
{
|
||||
u32 *cmdbuf = getThreadCommandBuffer();
|
||||
|
||||
@@ -178,27 +244,30 @@ void ERRF_HandleCommands(void)
|
||||
case 1: // Throw
|
||||
{
|
||||
ERRF_FatalErrInfo *info = (ERRF_FatalErrInfo *)(cmdbuf + 1);
|
||||
menuEnter();
|
||||
if(info->type != ERRF_ERRTYPE_LOGGED || info->procId == 0 || R_FAILED(ERRF_SaveErrorToFile(info)))
|
||||
{
|
||||
menuEnter();
|
||||
|
||||
Draw_Lock();
|
||||
Draw_ClearFramebuffer();
|
||||
Draw_FlushFramebuffer();
|
||||
Draw_Lock();
|
||||
Draw_ClearFramebuffer();
|
||||
Draw_FlushFramebuffer();
|
||||
|
||||
ERRF_DisplayError(info);
|
||||
ERRF_DisplayError(info);
|
||||
|
||||
/*
|
||||
If we ever wanted to return:
|
||||
draw_unlock();
|
||||
menuLeave();
|
||||
/*
|
||||
If we ever wanted to return:
|
||||
Draw_Unlock();
|
||||
menuLeave();
|
||||
|
||||
but we don't
|
||||
*/
|
||||
waitInput();
|
||||
svcKernelSetState(7);
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
cmdbuf[0] = 0x10040;
|
||||
cmdbuf[1] = 0;
|
||||
|
||||
but we don't
|
||||
*/
|
||||
waitInput();
|
||||
svcKernelSetState(7);
|
||||
__builtin_unreachable();
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -259,7 +259,7 @@ int vsprintf(char *buf, const char *fmt, va_list args)
|
||||
//Integer number formats - set up the flags and "break"
|
||||
case 'X':
|
||||
flags |= UPPERCASE;
|
||||
|
||||
//Falls through
|
||||
case 'x':
|
||||
isHex = true;
|
||||
break;
|
||||
@@ -267,7 +267,7 @@ int vsprintf(char *buf, const char *fmt, va_list args)
|
||||
case 'd':
|
||||
case 'i':
|
||||
flags |= SIGN;
|
||||
|
||||
//Falls through
|
||||
case 'u':
|
||||
isHex = false;
|
||||
break;
|
||||
|
||||
@@ -416,6 +416,8 @@ int GDB_SendStopReply(GDBContext *ctx, const DebugEventInfo *info)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case DBGEVENT_SYSCALL_IN:
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
*/
|
||||
|
||||
#include "gdb/watchpoints.h"
|
||||
#include "csvc.h"
|
||||
|
||||
#define _REENT_ONLY
|
||||
#include <errno.h>
|
||||
|
||||
@@ -53,6 +55,92 @@ typedef struct WatchpointManager
|
||||
|
||||
static WatchpointManager manager;
|
||||
|
||||
static void K_EnableMonitorModeDebugging(void)
|
||||
{
|
||||
__asm__ __volatile__("cpsid aif");
|
||||
|
||||
u32 DSCR;
|
||||
__asm__ __volatile__("mrc p15, 0, %[val], c0, c1, 0" : [val] "=r" (DSCR));
|
||||
DSCR |= 0x8000;
|
||||
__asm__ __volatile__("mcr p14, 0, %[val], c0, c1, 0" :: [val] "r" (DSCR));
|
||||
}
|
||||
|
||||
static void K_DisableWatchpoint(u32 id)
|
||||
{
|
||||
u32 control;
|
||||
|
||||
__asm__ __volatile__("cpsid aif");
|
||||
|
||||
if(id == 0)
|
||||
{
|
||||
// WCR0
|
||||
__asm__ __volatile__("mrc p14, 0, %[val], c0, c0, 7" : [val] "=r" (control));
|
||||
control &= ~1;
|
||||
__asm__ __volatile__("mcr p14, 0, %[val], c0, c0, 7" :: [val] "r" (control));
|
||||
|
||||
// BCR4
|
||||
__asm__ __volatile__("mrc p14, 0, %[val], c0, c4, 5" : [val] "=r" (control));
|
||||
control &= ~1;
|
||||
__asm__ __volatile__("mcr p14, 0, %[val], c0, c4, 5" :: [val] "r" (control));
|
||||
}
|
||||
else if(id == 1)
|
||||
{
|
||||
// WCR1
|
||||
__asm__ __volatile__("mrc p14, 0, %[val], c0, c1, 7" : [val] "=r" (control));
|
||||
control &= ~1;
|
||||
__asm__ __volatile__("mcr p14, 0, %[val], c0, c1, 7" :: [val] "r" (control));
|
||||
|
||||
// BCR5
|
||||
__asm__ __volatile__("mrc p14, 0, %[val], c0, c5, 5" : [val] "=r" (control));
|
||||
control &= ~1;
|
||||
__asm__ __volatile__("mcr p14, 0, %[val], c0, c5, 5" :: [val] "r" (control));
|
||||
}
|
||||
}
|
||||
|
||||
static void K_SetWatchpoint0WithContextId(u32 DVA, u32 WCR, u32 contextId)
|
||||
{
|
||||
// http://infocenter.arm.com/help/topic/com.arm.doc.ddi0360f/CEGCFFDF.html
|
||||
u32 BCR =
|
||||
(1 << 21) | /* compare with context ID */
|
||||
(1 << 20) | /* linked (with a WRP in our case) */
|
||||
(0xf << 5) | /* byte address select, +0 to +3 as mandated when linking with a WRP */
|
||||
(3 << 1) | /* either privileged modes or user mode, as mandated when linking with a WRP */
|
||||
(1 << 0) ; /* enabled */
|
||||
|
||||
__asm__ __volatile__("cpsid aif");
|
||||
|
||||
K_DisableWatchpoint(0);
|
||||
|
||||
__asm__ __volatile__("mcr p14, 0, %[val], c0, c0, 6" :: [val] "r" (DVA));
|
||||
__asm__ __volatile__("mcr p14, 0, %[val], c0, c4, 4" :: [val] "r" (contextId));
|
||||
__asm__ __volatile__("mcr p14, 0, %[val], c0, c0, 7" :: [val] "r" (WCR));
|
||||
__asm__ __volatile__("mcr p14, 0, %[val], c0, c4, 5" :: [val] "r" (BCR));
|
||||
|
||||
__asm__ __volatile__("mcr p15, 0, %[val], c7, c10, 5" :: [val] "r" (0) : "memory"); // DMB
|
||||
}
|
||||
|
||||
static void K_SetWatchpoint1WithContextId(u32 DVA, u32 WCR, u32 contextId)
|
||||
{
|
||||
// http://infocenter.arm.com/help/topic/com.arm.doc.ddi0360f/CEGCFFDF.html
|
||||
u32 BCR =
|
||||
(1 << 21) | /* compare with context ID */
|
||||
(1 << 20) | /* linked (with a WRP in our case) */
|
||||
(0xf << 5) | /* byte address select, +0 to +3 as mandated when linking with a WRP */
|
||||
(3 << 1) | /* either privileged modes or user mode, as mandated when linking with a WRP */
|
||||
(1 << 0) ; /* enabled */
|
||||
|
||||
__asm__ __volatile__("cpsid aif");
|
||||
|
||||
K_DisableWatchpoint(1);
|
||||
|
||||
__asm__ __volatile__("mcr p14, 0, %[val], c0, c1, 6" :: [val] "r" (DVA));
|
||||
__asm__ __volatile__("mcr p14, 0, %[val], c0, c5, 4" :: [val] "r" (contextId));
|
||||
__asm__ __volatile__("mcr p14, 0, %[val], c0, c1, 7" :: [val] "r" (WCR));
|
||||
__asm__ __volatile__("mcr p14, 0, %[val], c0, c5, 5" :: [val] "r" (BCR));
|
||||
|
||||
__asm__ __volatile__("mcr p15, 0, %[val], c7, c10, 5" :: [val] "r" (0) : "memory"); // DMB
|
||||
}
|
||||
|
||||
void GDB_ResetWatchpoints(void)
|
||||
{
|
||||
static bool lockInitialized = false;
|
||||
@@ -63,11 +151,9 @@ void GDB_ResetWatchpoints(void)
|
||||
}
|
||||
RecursiveLock_Lock(&watchpointManagerLock);
|
||||
|
||||
svcSetHardwareBreakPoint(4, 0, 0);
|
||||
svcSetHardwareBreakPoint(0x100, 0, 0);
|
||||
|
||||
svcSetHardwareBreakPoint(5, 0, 0);
|
||||
svcSetHardwareBreakPoint(0x101, 0, 0);
|
||||
svcCustomBackdoor(K_EnableMonitorModeDebugging);
|
||||
svcCustomBackdoor(K_DisableWatchpoint, 0);
|
||||
svcCustomBackdoor(K_DisableWatchpoint, 1);
|
||||
|
||||
memset(&manager, 0, sizeof(WatchpointManager));
|
||||
|
||||
@@ -93,26 +179,20 @@ int GDB_AddWatchpoint(GDBContext *ctx, u32 address, u32 size, WatchpointKind kin
|
||||
u32 id = manager.watchpoints[0].kind == WATCHPOINT_DISABLED ? 0 : 1;
|
||||
u32 selectMask = ((1 << size) - 1) << offset;
|
||||
|
||||
u32 BCR = (1 << 21) | /* compare with context ID */
|
||||
(1 << 20) | /* linked (with a WRP in our case) */
|
||||
(0xf << 5) | /* byte address select, +0 to +3 as mandated when linking with a WRP */
|
||||
(3 << 1) | /* either privileged modes or user mode, as mandated when linking with a WRP */
|
||||
(1 << 0) ; /* enabled */
|
||||
|
||||
u32 WCR = (1 << 20) | /* linked */
|
||||
((4 + id) << 16) | /* ID of the linked BRP */
|
||||
(selectMask << 5) | /* byte address select */
|
||||
((u32)kind << 3) | /* kind */
|
||||
(2 << 1) | /* user mode only */
|
||||
(1 << 0) ; /* enabled */
|
||||
|
||||
s64 out;
|
||||
|
||||
Result r = svcSetHardwareBreakPoint(0x100 | id, WCR, address & ~3);
|
||||
|
||||
if(R_SUCCEEDED(r))
|
||||
r = svcSetHardwareBreakPoint(4 + id, BCR, (u32)ctx->debug);
|
||||
Result r = svcGetHandleInfo(&out, ctx->debug, 0x10000); // context ID
|
||||
|
||||
if(R_SUCCEEDED(r))
|
||||
{
|
||||
svcCustomBackdoor(id == 0 ? K_SetWatchpoint0WithContextId : K_SetWatchpoint1WithContextId, address, WCR, (u32)out);
|
||||
Watchpoint *watchpoint = &manager.watchpoints[id];
|
||||
manager.total++;
|
||||
watchpoint->address = address;
|
||||
@@ -144,8 +224,7 @@ int GDB_RemoveWatchpoint(GDBContext *ctx, u32 address, WatchpointKind kind)
|
||||
}
|
||||
else
|
||||
{
|
||||
svcSetHardwareBreakPoint(4 + id, 0, 0);
|
||||
svcSetHardwareBreakPoint(0x100 | id, 0, 0);
|
||||
svcCustomBackdoor(K_DisableWatchpoint, id);
|
||||
|
||||
memset(&manager.watchpoints[id], 0, sizeof(Watchpoint));
|
||||
manager.total--;
|
||||
|
||||
@@ -280,6 +280,8 @@ static void HBLDR_HandleCommands(void)
|
||||
localcaps1->priority = 0;
|
||||
memset(localcaps0->resourcelimitdescriptor, 0, 0x10);
|
||||
memset(localcaps1->resourcelimitdescriptor, 0, 0x10);
|
||||
localcaps0->resourcelimitdescriptor[0] = 0x9E;
|
||||
localcaps0->resourcelimitdescriptor[1] = 0x9E;
|
||||
memset(localcaps0->storageinfo.accessinfo, 0xFF, 7);
|
||||
memset(localcaps1->storageinfo.accessinfo, 0xFF, 7);
|
||||
memcpy(localcaps0->serviceaccesscontrol, serviceList, sizeof(serviceList));
|
||||
|
||||
68
sysmodules/rosalina/source/mcu.c
Normal file
68
sysmodules/rosalina/source/mcu.c
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* This file is part of Luma3DS
|
||||
* Copyright (C) 2016-2017 Aurora Wright, TuxSH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
#include "mcu.h"
|
||||
|
||||
Result mcuInit(void)
|
||||
{
|
||||
return srvGetServiceHandle(&mcuhwcHandle, "mcu::HWC");
|
||||
}
|
||||
|
||||
Result mcuExit(void)
|
||||
{
|
||||
return svcCloseHandle(mcuhwcHandle);
|
||||
}
|
||||
|
||||
Result mcuReadRegister(u8 reg, u8* data, u32 size)
|
||||
{
|
||||
u32* ipc = getThreadCommandBuffer();
|
||||
ipc[0] = 0x10082;
|
||||
ipc[1] = reg;
|
||||
ipc[2] = size;
|
||||
ipc[3] = size << 4 | 0xC;
|
||||
ipc[4] = (u32)data;
|
||||
Result ret = svcSendSyncRequest(mcuhwcHandle);
|
||||
if(ret < 0) return ret;
|
||||
return ipc[1];
|
||||
}
|
||||
|
||||
Result mcuWriteRegister(u8 reg, u8* data, u32 size)
|
||||
{
|
||||
u32* ipc = getThreadCommandBuffer();
|
||||
ipc[0] = 0x20082;
|
||||
ipc[1] = reg;
|
||||
ipc[2] = size;
|
||||
ipc[3] = size << 4 | 0xA;
|
||||
ipc[4] = (u32)data;
|
||||
Result ret = svcSendSyncRequest(mcuhwcHandle);
|
||||
if(ret < 0) return ret;
|
||||
return ipc[1];
|
||||
}
|
||||
|
||||
Result mcuGetLEDState(u8* out)
|
||||
{
|
||||
return mcuReadRegister(0x28, out, 1);
|
||||
}
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "menu.h"
|
||||
#include "draw.h"
|
||||
#include "fmt.h"
|
||||
#include "mcu.h"
|
||||
#include "memory.h"
|
||||
#include "ifile.h"
|
||||
#include "menus.h"
|
||||
@@ -125,11 +126,10 @@ u32 waitCombo(void)
|
||||
|
||||
static Result _MCUHWC_GetBatteryLevel(u8 *out)
|
||||
{
|
||||
#define TRY(expr) if(R_FAILED(res = (expr))) { svcCloseHandle(mcuhwcHandle); return res; }
|
||||
#define TRY(expr) if(R_FAILED(res = (expr))) { mcuExit(); return res; }
|
||||
Result res;
|
||||
Handle mcuhwcHandle;
|
||||
|
||||
TRY(srvGetServiceHandle(&mcuhwcHandle, "mcu::HWC"));
|
||||
TRY(mcuInit());
|
||||
|
||||
u32 *cmdbuf = getThreadCommandBuffer();
|
||||
cmdbuf[0] = 0x50000;
|
||||
|
||||
@@ -33,20 +33,24 @@
|
||||
#include "menus/n3ds.h"
|
||||
#include "menus/debugger.h"
|
||||
#include "menus/miscellaneous.h"
|
||||
#include "menus/sysconfig.h"
|
||||
#include "ifile.h"
|
||||
#include "memory.h"
|
||||
#include "fmt.h"
|
||||
|
||||
Menu rosalinaMenu = {
|
||||
"Rosalina menu",
|
||||
.nbItems = 7,
|
||||
.nbItems = 10,
|
||||
{
|
||||
{ "Process list", METHOD, .method = &RosalinaMenu_ProcessList },
|
||||
{ "Process patches menu...", MENU, .menu = &processPatchesMenu },
|
||||
{ "Take screenshot (slow!)", METHOD, .method = &RosalinaMenu_TakeScreenshot },
|
||||
{ "New 3DS menu...", MENU, .menu = &N3DSMenu },
|
||||
{ "Debugger options...", MENU, .menu = &debuggerMenu },
|
||||
{ "System configuration...", MENU, .menu = &sysconfigMenu },
|
||||
{ "Miscellaneous options...", MENU, .menu = &miscellaneousMenu },
|
||||
{ "Power off", METHOD, .method = &RosalinaMenu_PowerOff },
|
||||
{ "Reboot", METHOD, .method = &RosalinaMenu_Reboot },
|
||||
{ "Credits", METHOD, .method = &RosalinaMenu_ShowCredits }
|
||||
}
|
||||
};
|
||||
@@ -85,6 +89,59 @@ void RosalinaMenu_ShowCredits(void)
|
||||
while(!(waitInput() & BUTTON_B) && !terminationRequest);
|
||||
}
|
||||
|
||||
void RosalinaMenu_Reboot(void)
|
||||
{
|
||||
Draw_Lock();
|
||||
Draw_ClearFramebuffer();
|
||||
Draw_FlushFramebuffer();
|
||||
Draw_Unlock();
|
||||
|
||||
do
|
||||
{
|
||||
Draw_Lock();
|
||||
Draw_DrawString(10, 10, COLOR_TITLE, "Rosalina menu");
|
||||
Draw_DrawString(10, 30, COLOR_WHITE, "Press A to reboot, press B to go back.");
|
||||
Draw_FlushFramebuffer();
|
||||
Draw_Unlock();
|
||||
|
||||
u32 pressed = waitInputWithTimeout(1000);
|
||||
|
||||
if(pressed & BUTTON_A)
|
||||
svcKernelSetState(7);
|
||||
else if(pressed & BUTTON_B)
|
||||
return;
|
||||
}
|
||||
while(!terminationRequest);
|
||||
}
|
||||
|
||||
void RosalinaMenu_PowerOff(void) // Soft shutdown.
|
||||
{
|
||||
Draw_Lock();
|
||||
Draw_ClearFramebuffer();
|
||||
Draw_FlushFramebuffer();
|
||||
Draw_Unlock();
|
||||
|
||||
do
|
||||
{
|
||||
Draw_Lock();
|
||||
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_FlushFramebuffer();
|
||||
Draw_Unlock();
|
||||
|
||||
u32 pressed = waitInputWithTimeout(1000);
|
||||
|
||||
if(pressed & BUTTON_A)
|
||||
{
|
||||
menuLeave();
|
||||
srvPublishToSubscriber(0x203, 0);
|
||||
}
|
||||
else if(pressed & BUTTON_B)
|
||||
return;
|
||||
}
|
||||
while(!terminationRequest);
|
||||
}
|
||||
|
||||
extern u8 framebufferCache[FB_BOTTOM_SIZE];
|
||||
void RosalinaMenu_TakeScreenshot(void)
|
||||
{
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <3ds.h>
|
||||
#include "menus/miscellaneous.h"
|
||||
#include "input_redirection.h"
|
||||
#include "mcu.h"
|
||||
#include "memory.h"
|
||||
#include "draw.h"
|
||||
#include "hbloader.h"
|
||||
@@ -37,14 +38,12 @@
|
||||
|
||||
Menu miscellaneousMenu = {
|
||||
"Miscellaneous options menu",
|
||||
.nbItems = 6,
|
||||
.nbItems = 4,
|
||||
{
|
||||
{ "Switch the hb. title to the current app.", METHOD, .method = &MiscellaneousMenu_SwitchBoot3dsxTargetTitle },
|
||||
{ "Change the menu combo", METHOD, .method = MiscellaneousMenu_ChangeMenuCombo },
|
||||
{ "Save settings", METHOD, .method = &MiscellaneousMenu_SaveSettings },
|
||||
{ "Start InputRedirection", METHOD, .method = &MiscellaneousMenu_InputRedirection },
|
||||
{ "Power off", METHOD, .method = &MiscellaneousMenu_PowerOff },
|
||||
{ "Reboot", METHOD, .method = &MiscellaneousMenu_Reboot },
|
||||
{ "Save settings", METHOD, .method = &MiscellaneousMenu_SaveSettings },
|
||||
}
|
||||
};
|
||||
|
||||
@@ -129,6 +128,7 @@ static void MiscellaneousMenu_ConvertComboToString(char *out, u32 combo)
|
||||
|
||||
out[-1] = 0;
|
||||
}
|
||||
|
||||
void MiscellaneousMenu_ChangeMenuCombo(void)
|
||||
{
|
||||
char comboStrOrig[64], comboStr[64];
|
||||
@@ -255,7 +255,7 @@ void MiscellaneousMenu_InputRedirection(void)
|
||||
if(res != 0)
|
||||
sprintf(buf, "Failed to stop InputRedirection (0x%08x).", (u32)res);
|
||||
else
|
||||
miscellaneousMenu.items[3].title = "Start InputRedirection";
|
||||
miscellaneousMenu.items[2].title = "Start InputRedirection";
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -311,7 +311,7 @@ void MiscellaneousMenu_InputRedirection(void)
|
||||
if(res != 0)
|
||||
sprintf(buf, "Starting InputRedirection... failed (0x%08x).", (u32)res);
|
||||
else
|
||||
miscellaneousMenu.items[3].title = "Stop InputRedirection";
|
||||
miscellaneousMenu.items[2].title = "Stop InputRedirection";
|
||||
|
||||
done = true;
|
||||
}
|
||||
@@ -334,56 +334,3 @@ void MiscellaneousMenu_InputRedirection(void)
|
||||
}
|
||||
while(!(waitInput() & BUTTON_B) && !terminationRequest);
|
||||
}
|
||||
|
||||
void MiscellaneousMenu_Reboot(void)
|
||||
{
|
||||
Draw_Lock();
|
||||
Draw_ClearFramebuffer();
|
||||
Draw_FlushFramebuffer();
|
||||
Draw_Unlock();
|
||||
|
||||
do
|
||||
{
|
||||
Draw_Lock();
|
||||
Draw_DrawString(10, 10, COLOR_TITLE, "Miscellaneous options menu");
|
||||
Draw_DrawString(10, 30, COLOR_WHITE, "Press A to reboot, press B to go back.");
|
||||
Draw_FlushFramebuffer();
|
||||
Draw_Unlock();
|
||||
|
||||
u32 pressed = waitInputWithTimeout(1000);
|
||||
|
||||
if(pressed & BUTTON_A)
|
||||
svcKernelSetState(7);
|
||||
else if(pressed & BUTTON_B)
|
||||
return;
|
||||
}
|
||||
while(!terminationRequest);
|
||||
}
|
||||
|
||||
void MiscellaneousMenu_PowerOff(void) // Soft shutdown.
|
||||
{
|
||||
Draw_Lock();
|
||||
Draw_ClearFramebuffer();
|
||||
Draw_FlushFramebuffer();
|
||||
Draw_Unlock();
|
||||
|
||||
do
|
||||
{
|
||||
Draw_Lock();
|
||||
Draw_DrawString(10, 10, COLOR_TITLE, "Miscellaneous options menu");
|
||||
Draw_DrawString(10, 30, COLOR_WHITE, "Press A to power off, press B to go back.");
|
||||
Draw_FlushFramebuffer();
|
||||
Draw_Unlock();
|
||||
|
||||
u32 pressed = waitInputWithTimeout(1000);
|
||||
|
||||
if(pressed & BUTTON_A)
|
||||
{
|
||||
menuLeave();
|
||||
srvPublishToSubscriber(0x203, 0);
|
||||
}
|
||||
else if(pressed & BUTTON_B)
|
||||
return;
|
||||
}
|
||||
while(!terminationRequest);
|
||||
}
|
||||
|
||||
112
sysmodules/rosalina/source/menus/sysconfig.c
Normal file
112
sysmodules/rosalina/source/menus/sysconfig.c
Normal file
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* This file is part of Luma3DS
|
||||
* Copyright (C) 2016-2017 Aurora Wright, TuxSH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
#include <3ds.h>
|
||||
#include "menus/sysconfig.h"
|
||||
#include "mcu.h"
|
||||
#include "memory.h"
|
||||
#include "draw.h"
|
||||
#include "fmt.h"
|
||||
#include "utils.h"
|
||||
#include "ifile.h"
|
||||
|
||||
Menu sysconfigMenu = {
|
||||
"System configuration menu",
|
||||
.nbItems = 2,
|
||||
{
|
||||
{ "Toggle LEDs", METHOD, .method = &SysConfigMenu_ToggleLEDs },
|
||||
{ "Toggle Wireless", METHOD, .method = &SysConfigMenu_ToggleWireless },
|
||||
}
|
||||
};
|
||||
|
||||
void SysConfigMenu_ToggleLEDs(void)
|
||||
{
|
||||
Draw_Lock();
|
||||
Draw_ClearFramebuffer();
|
||||
Draw_FlushFramebuffer();
|
||||
Draw_Unlock();
|
||||
|
||||
do
|
||||
{
|
||||
Draw_Lock();
|
||||
Draw_DrawString(10, 10, COLOR_TITLE, "System configuration menu");
|
||||
Draw_DrawString(10, 30, COLOR_WHITE, "Press A to toggle, press B to go back.");
|
||||
Draw_DrawString(10, 50, COLOR_RED, "WARNING:");
|
||||
Draw_DrawString(10, 60, COLOR_WHITE, " * Entering sleep mode will reset the LED state!");
|
||||
Draw_DrawString(10, 70, COLOR_WHITE, " * LEDs cannot be toggled when the battery is low!");
|
||||
|
||||
Draw_FlushFramebuffer();
|
||||
Draw_Unlock();
|
||||
|
||||
u32 pressed = waitInputWithTimeout(1000);
|
||||
|
||||
if(pressed & BUTTON_A)
|
||||
{
|
||||
mcuInit();
|
||||
u8 result;
|
||||
mcuGetLEDState(&result);
|
||||
u8 value = ~result;
|
||||
mcuWriteRegister(40, &value, 1);
|
||||
mcuExit();
|
||||
}
|
||||
else if(pressed & BUTTON_B)
|
||||
return;
|
||||
}
|
||||
while(!terminationRequest);
|
||||
}
|
||||
|
||||
void SysConfigMenu_ToggleWireless(void)
|
||||
{
|
||||
Draw_Lock();
|
||||
Draw_ClearFramebuffer();
|
||||
Draw_FlushFramebuffer();
|
||||
Draw_Unlock();
|
||||
|
||||
do
|
||||
{
|
||||
Draw_Lock();
|
||||
Draw_DrawString(10, 10, COLOR_TITLE, "System configuration menu");
|
||||
Draw_DrawString(10, 30, COLOR_WHITE, "Press A to toggle, press B to go back.");
|
||||
Draw_DrawString(10, 50, COLOR_WHITE, "Current status:");
|
||||
|
||||
u8 wireless = (*(vu8 *)((0x10140000 | (1u << 31)) + 0x180));
|
||||
Draw_DrawString(100, 50, (wireless ? COLOR_GREEN : COLOR_RED), (wireless ? " ON " : " OFF"));
|
||||
Draw_FlushFramebuffer();
|
||||
Draw_Unlock();
|
||||
|
||||
u32 pressed = waitInputWithTimeout(1000);
|
||||
|
||||
if(pressed & BUTTON_A)
|
||||
{
|
||||
nwmExtInit();
|
||||
NWMEXT_ControlWirelessEnabled(!wireless);
|
||||
nwmExtExit();
|
||||
}
|
||||
else if(pressed & BUTTON_B)
|
||||
return;
|
||||
}
|
||||
while(!terminationRequest);
|
||||
}
|
||||
Reference in New Issue
Block a user