2020-08-19 16:07:20 +08:00

189 lines
4.1 KiB
C

#include <sys/iosupport.h>
#include <malloc.h>
#include <3ds.h>
#include "../core/clipboard.h"
#include "../core/error.h"
#include "../core/fs.h"
#include "../core/screen.h"
#include "../core/task/task.h"
#include "../core/ui/ui.h"
#include "section.h"
#include "task/uitask.h"
#define CURRENT_KPROCESS (*(void**) 0xFFFF9004)
#define KPROCESS_PID_OFFSET_OLD (0xB4)
#define KPROCESS_PID_OFFSET_NEW (0xBC)
static bool backdoor_ran = false;
static bool n3ds = false;
static u32 old_pid = 0;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wreturn-type"
static __attribute__((naked)) Result svcGlobalBackdoor(s32 (*callback)()) {
asm volatile(
"svc 0x30\n"
"bx lr"
);
}
#pragma GCC diagnostic pop
static s32 patch_pid_kernel() {
u32 *pidPtr = (u32*) (CURRENT_KPROCESS + (n3ds ? KPROCESS_PID_OFFSET_NEW : KPROCESS_PID_OFFSET_OLD));
old_pid = *pidPtr;
*pidPtr = 0;
backdoor_ran = true;
return 0;
}
static s32 restore_pid_kernel() {
u32 *pidPtr = (u32*) (CURRENT_KPROCESS + (n3ds ? KPROCESS_PID_OFFSET_NEW : KPROCESS_PID_OFFSET_OLD));
*pidPtr = old_pid;
backdoor_ran = true;
return 0;
}
static bool attempt_patch_pid() {
backdoor_ran = false;
APT_CheckNew3DS(&n3ds);
svcGlobalBackdoor(patch_pid_kernel);
srvExit();
srvInit();
svcGlobalBackdoor(restore_pid_kernel);
return backdoor_ran;
}
static void (*exit_funcs[16])()= {NULL};
static u32 exit_func_count = 0;
static void* soc_buffer = NULL;
void cleanup_services() {
for(u32 i = 0; i < exit_func_count; i++) {
if(exit_funcs[i] != NULL) {
exit_funcs[i]();
exit_funcs[i] = NULL;
}
}
exit_func_count = 0;
if(soc_buffer != NULL) {
free(soc_buffer);
soc_buffer = NULL;
}
}
#define INIT_SERVICE(initStatement, exitFunc) (R_SUCCEEDED(res = (initStatement)) && (exit_funcs[exit_func_count++] = (exitFunc)))
Result init_services() {
Result res = 0;
soc_buffer = memalign(0x1000, 0x100000);
if(soc_buffer != NULL) {
Handle tempAM = 0;
if(R_SUCCEEDED(res = srvGetServiceHandle(&tempAM, "am:net"))) {
svcCloseHandle(tempAM);
if(INIT_SERVICE(amInit(), amExit)
&& INIT_SERVICE(cfguInit(), cfguExit)
&& INIT_SERVICE(acInit(), acExit)
&& INIT_SERVICE(ptmuInit(), ptmuExit)
&& INIT_SERVICE(pxiDevInit(), pxiDevExit)
&& INIT_SERVICE(httpcInit(0), httpcExit)
&& INIT_SERVICE(socInit(soc_buffer, 0x100000), (void (*)()) socExit));
}
} else {
res = R_APP_OUT_OF_MEMORY;
}
if(R_FAILED(res)) {
cleanup_services();
}
return res;
}
static u32 old_time_limit = UINT32_MAX;
void init() {
gfxInitDefault();
Result romfsRes = romfsInit();
if(R_FAILED(romfsRes)) {
error_panic("無法掛載 RomFS: %08lX", romfsRes);
return;
}
if(R_FAILED(init_services())) {
if(!attempt_patch_pid()) {
error_panic("無法操控內核\n請確認已獲得內核權限");
return;
}
Result initRes = init_services();
if(R_FAILED(initRes)) {
error_panic("無法初始化服務: %08lX", initRes);
return;
}
}
osSetSpeedupEnable(true);
APT_GetAppCpuTimeLimit(&old_time_limit);
Result cpuRes = APT_SetAppCpuTimeLimit(30);
if(R_FAILED(cpuRes)) {
error_panic("無法設置 Syscore CPU 時間限制: %08lX", cpuRes);
return;
}
AM_InitializeExternalTitleDatabase(false);
screen_init();
ui_init();
task_init();
}
void cleanup() {
clipboard_clear();
task_exit();
ui_exit();
screen_exit();
if(old_time_limit != UINT32_MAX) {
APT_SetAppCpuTimeLimit(old_time_limit);
}
osSetSpeedupEnable(false);
cleanup_services();
romfsExit();
gfxExit();
}
int main(int argc, const char* argv[]) {
if(argc > 0 && envIsHomebrew()) {
fs_set_3dsx_path(argv[0]);
}
init();
mainmenu_open();
while(aptMainLoop() && ui_update());
cleanup();
return 0;
}