static void swkbdMessageCallback(void* user, NS_APPID sender, void* msg, size_t msgsize) { SwkbdExtra* extra = (SwkbdExtra*)user; SwkbdState* swkbd = (SwkbdState*)msg; if (sender != APPID_SOFTWARE_KEYBOARD || msgsize != sizeof(SwkbdState)) return; u16* text16 = (u16*)(swkbdSharedMem + swkbd->text_offset); ssize_t units = utf16_to_utf8(NULL, text16, 0); if (units < 0) svcBreak(USERBREAK_PANIC); // Shouldn't happen. char* text8 = (char*)malloc(units+1); if (!text8) svcBreak(USERBREAK_PANIC); // Shouldn't happen. swkbdConvertToUTF8(text8, text16, units); const char* retmsg = NULL; swkbd->callback_result = extra->callback(extra->callback_user, &retmsg, text8, units); if (swkbd->callback_result > SWKBD_CALLBACK_OK) swkbdConvertToUTF16(swkbd->callback_msg, retmsg, SWKBD_MAX_CALLBACK_MSG_LEN); else swkbd->callback_msg[0] = 0; free(text8); APT_SendParameter(envGetAptAppId(), sender, APTCMD_MESSAGE, swkbd, sizeof(*swkbd), 0); }
static inline void initPXI(void) { Result res; Handle handles[2] = {0}; PXIReset(); if(PXISyncInterrupt != 0) svcBreak(USERBREAK_PANIC); //0xE0A0183B assertSuccess(svcCreateEvent(&PXISyncInterrupt, RESET_ONESHOT)); if(PXITransferMutex != 0) svcBreak(USERBREAK_PANIC); //0xE0A0183B assertSuccess(svcCreateMutex(&PXITransferMutex, false)); assertSuccess(svcCreateEvent(&handles[0], RESET_ONESHOT)); //receive FIFO not empty assertSuccess(svcCreateEvent(&handles[1], RESET_ONESHOT)); //send FIFO empty assertSuccess(bindPXIInterrupts(&PXISyncInterrupt, &handles[0], &handles[1])); s32 handleIndex; do { while(!PXIIsSendFIFOFull()) PXISendWord(0); res = assertSuccess(svcWaitSynchronization(handles[0], 0LL)); if(R_DESCRIPTION(res) == RD_TIMEOUT) assertSuccess(svcWaitSynchronizationN(&handleIndex, handles, 2, false, -1LL)); else handleIndex = 0; } while(handleIndex != 0); unbindPXIInterrupts(NULL, &handles[0], &handles[1]); PXISendByte(1); while(PXIReceiveByte() < 1); while (!PXIIsReceiveFIFOEmpty()) PXIReceiveWord(); PXISendByte(2); while(PXIReceiveByte() < 2); svcCloseHandle(handles[0]); svcCloseHandle(handles[1]); }
int main(void) { Handle handles[10] = {0}; //notification handle + service handles MyThread receiverThread = {0}, senderThread = {0}, PXISRV11HandlerThread = {0}; for(u32 i = 0; i < 9; i++) assertSuccess(srvRegisterService(handles + 1 + i, serviceNames[i], 1)); assertSuccess(MyThread_Create(&receiverThread, receiver, receiverStack, THREAD_STACK_SIZE, 0x2D, -2)); assertSuccess(MyThread_Create(&senderThread, sender, senderStack, THREAD_STACK_SIZE, 0x2D, -2)); assertSuccess(MyThread_Create(&PXISRV11HandlerThread, PXISRV11Handler, PXISRV11HandlerStack, THREAD_STACK_SIZE, 0x2D, -2)); assertSuccess(srvEnableNotification(&handles[0])); while(!shouldTerminate) { s32 index = 0; assertSuccess(svcWaitSynchronizationN(&index, handles, 10, false, -1LL)); if(index == 0) { u32 notificationId; assertSuccess(srvReceiveNotification(¬ificationId)); if(notificationId == 0x100) shouldTerminate = true; } else { Handle session = 0; SessionData *data = &sessionManager.sessionData[index - 1]; assertSuccess(svcAcceptSession(&session, handles[index])); RecursiveLock_Lock(&sessionManager.senderLock); if(data->handle != 0) svcBreak(USERBREAK_PANIC); data->handle = session; assertSuccess(svcSignalEvent(sessionManager.sendAllBuffersToArm9Event)); RecursiveLock_Unlock(&sessionManager.senderLock); } } u32 PXIMC_OnPXITerminate = 0x10000; //TODO: see if this is correct sessionManager.sessionData[0].state = STATE_SENT_TO_ARM9; sendPXICmdbuf(NULL, 0, &PXIMC_OnPXITerminate); assertSuccess(MyThread_Join(&receiverThread, -1LL)); assertSuccess(MyThread_Join(&senderThread, -1LL)); assertSuccess(MyThread_Join(&PXISRV11HandlerThread, -1LL)); for(u32 i = 0; i < 10; i++) svcCloseHandle(handles[i]); return 0; }
static struct _reent* __ctru_get_reent() { ThreadVars* tv = getThreadVars(); if (tv->magic != THREADVARS_MAGIC) { svcBreak(USERBREAK_PANIC); for (;;); } return tv->reent; }
// this is called before main void __appInit() { assertSuccess(svcCreateEvent(&terminationRequestedEvent, RESET_STICKY)); assertSuccess(svcCreateEvent(&sessionManager.sendAllBuffersToArm9Event, RESET_ONESHOT)); assertSuccess(svcCreateSemaphore(&sessionManager.replySemaphore, 0, 9)); assertSuccess(svcCreateEvent(&sessionManager.PXISRV11CommandReceivedEvent, RESET_ONESHOT)); assertSuccess(svcCreateEvent(&sessionManager.PXISRV11ReplySentEvent, RESET_ONESHOT)); initPXI(); for(Result res = 0xD88007FA; res == (Result)0xD88007FA; svcSleepThread(500 * 1000LL)) { res = srvInit(); if(R_FAILED(res) && res != (Result)0xD88007FA) svcBreak(USERBREAK_PANIC); } }
Result fsldrInit(void) { Result ret = 0; if (AtomicPostIncrement(&fsldrRefCount)) return 0; ret = srvSysGetServiceHandle(&fsldrHandle, "fs:LDR"); if (R_SUCCEEDED(ret)) { fsldrPatchPermissions(); ret = FSLDR_InitializeWithSdkVersion(fsldrHandle, SDK_VERSION); ret = FSLDR_SetPriority(0); if (R_FAILED(ret)) svcBreak(USERBREAK_ASSERT); } else { AtomicDecrement(&fsldrRefCount); } return ret; }
Result srvSysExit() { Result rc; RecursiveLock_Lock(&initLock); if (srvRefCount > 1) { srvRefCount--; RecursiveLock_Unlock(&initLock); return MAKERESULT(RL_INFO, RS_NOP, 25, RD_BUSY); } if (srvHandle != 0) svcCloseHandle(srvHandle); else svcBreak(USERBREAK_ASSERT); rc = (Result)srvHandle; // yeah, I think this is a benign bug srvHandle = 0; srvRefCount--; RecursiveLock_Unlock(&initLock); return rc; }
void __attribute__((weak)) __system_allocateHeaps(void) { u32 tmp=0; if (!__ctru_heap_size) { // Automatically allocate all remaining free memory, aligning to page size. __ctru_heap_size = osGetMemRegionFree(MEMREGION_APPLICATION) &~ 0xFFF; if (__ctru_heap_size <= __ctru_linear_heap_size) svcBreak(USERBREAK_PANIC); __ctru_heap_size -= __ctru_linear_heap_size; } // Allocate the application heap __ctru_heap = 0x08000000; svcControlMemory(&tmp, __ctru_heap, 0x0, __ctru_heap_size, MEMOP_ALLOC, MEMPERM_READ | MEMPERM_WRITE); // Allocate the linear heap svcControlMemory(&__ctru_linear_heap, 0x0, 0x0, __ctru_linear_heap_size, MEMOP_ALLOC_LINEAR, MEMPERM_READ | MEMPERM_WRITE); // Set up newlib heap fake_heap_start = (char*)__ctru_heap; fake_heap_end = fake_heap_start + __ctru_heap_size; }
void GDB_PreprocessDebugEvent(GDBContext *ctx, DebugEventInfo *info) { switch(info->type) { case DBGEVENT_ATTACH_THREAD: { if(ctx->nbThreads == MAX_DEBUG_THREAD) svcBreak(USERBREAK_ASSERT); else { ctx->threadInfos[ctx->nbThreads].id = info->thread_id; ctx->threadInfos[ctx->nbThreads++].tls = info->attach_thread.thread_local_storage; } break; } case DBGEVENT_EXIT_THREAD: { u32 i; for(i = 0; i < ctx->nbThreads && ctx->threadInfos[i].id != info->thread_id; i++); if(i == ctx->nbThreads || ctx->threadInfos[i].id != info->thread_id) svcBreak(USERBREAK_ASSERT); else { for(u32 j = i; j < ctx->nbThreads - 1; j++) memcpy(ctx->threadInfos + j, ctx->threadInfos + j + 1, sizeof(ThreadInfo)); memset(ctx->threadInfos + --ctx->nbThreads, 0, sizeof(ThreadInfo)); } break; } case DBGEVENT_EXIT_PROCESS: { ctx->processEnded = true; ctx->processExited = info->exit_process.reason == EXITPROCESS_EVENT_EXIT; break; } case DBGEVENT_OUTPUT_STRING: { if(info->output_string.string_addr >= 0xFFFFFFFE) { u32 sz = info->output_string.string_size, addr = info->output_string.string_addr, threadId = info->thread_id; memset(info, 0, sizeof(DebugEventInfo)); info->type = (addr == 0xFFFFFFFF) ? DBGEVENT_SYSCALL_OUT : DBGEVENT_SYSCALL_IN; info->thread_id = threadId; info->flags = 1; info->syscall.syscall = sz; } break; } case DBGEVENT_EXCEPTION: { switch(info->exception.type) { case EXCEVENT_UNDEFINED_INSTRUCTION: { // kernel bugfix for thumb mode ThreadContext regs; Result r = svcGetDebugThreadContext(®s, ctx->debug, info->thread_id, THREADCONTEXT_CONTROL_CPU_SPRS); if(R_SUCCEEDED(r) && (regs.cpu_registers.cpsr & 0x20) != 0) { regs.cpu_registers.pc += 2; r = svcSetDebugThreadContext(ctx->debug, info->thread_id, ®s, THREADCONTEXT_CONTROL_CPU_SPRS); } break; } default: break; } } default: break; } }
void patchCode(u64 progId, u16 progVer, u8 *code, u32 size) { loadCFWInfo(); if(((progId == 0x0004003000008F02LL || //USA Home Menu progId == 0x0004003000008202LL || //JPN Home Menu progId == 0x0004003000009802LL) //EUR Home Menu && progVer > 4) || (progId == 0x000400300000A902LL //KOR Home Menu && progVer > 0) || progId == 0x000400300000A102LL || //CHN Home Menu progId == 0x000400300000B102LL) //TWN Home Menu { static const u8 pattern[] = { 0x0A, 0x0C, 0x00, 0x10 }, patch[] = { 0x01, 0x00, 0xA0, 0xE3, 0x1E, 0xFF, 0x2F, 0xE1 }; //Patch SMDH region checks if(!patchMemory(code, size, pattern, sizeof(pattern), -31, patch, sizeof(patch), 1 )) goto error; } else if(progId == 0x0004013000003202LL) //FRIENDS { static const u8 pattern[] = { 0x42, 0xE0, 0x1E, 0xFF }; u8 mostRecentFpdVer = 8; u8 *off = memsearch(code, pattern, size, sizeof(pattern)); if(off == NULL) goto error; //Allow online access to work with old friends modules if(off[0xA] < mostRecentFpdVer) off[0xA] = mostRecentFpdVer; } else if((progId == 0x0004001000021000LL || //USA MSET progId == 0x0004001000020000LL || //JPN MSET progId == 0x0004001000022000LL || //EUR MSET progId == 0x0004001000026000LL || //CHN MSET progId == 0x0004001000027000LL || //KOR MSET progId == 0x0004001000028000LL) //TWN MSET && CONFIG(PATCHVERSTRING)) { static const u16 pattern[] = u"Ve"; static u16 *patch; u32 patchSize = 0, currentNand = BOOTCFG_NAND; u16 customVerString[19]; loadCustomVerString(customVerString, &patchSize, currentNand); if(patchSize != 0) patch = customVerString; else { patchSize = 8; u32 currentFirm = BOOTCFG_FIRM; static u16 *verStringsNands[] = { u" Sys", u" Emu", u"Emu2", u"Emu3", u"Emu4" }, *verStringsEmuSys[] = { u"EmuS", u"Em2S", u"Em3S", u"Em4S" }, *verStringsSysEmu[] = { u"SysE", u"SyE2", u"SyE3", u"SyE4" }; patch = (currentFirm != 0) == (currentNand != 0) ? verStringsNands[currentNand] : (!currentNand ? verStringsSysEmu[currentFirm - 1] : verStringsEmuSys[currentNand - 1]); } //Patch Ver. string if(!patchMemory(code, size, pattern, sizeof(pattern) - 2, 0, patch, patchSize, 1 )) goto error; } else if(progId == 0x0004013000008002LL) //NS { if(progVer > 4) { static const u8 pattern[] = { 0x0C, 0x18, 0xE1, 0xD8 }, patch[] = { 0x0B, 0x18, 0x21, 0xC8 }; //Disable updates from foreign carts (makes carts region-free) u32 ret = patchMemory(code, size, pattern, sizeof(pattern), 0, patch, sizeof(patch), 2 ); if(ret == 0 || (ret == 1 && progVer > 0xB)) goto error; } if(LOADERFLAG(ISN3DS)) { u32 cpuSetting = MULTICONFIG(NEWCPU); if(cpuSetting != 0) { static const u8 pattern[] = { 0x0C, 0x00, 0x94, 0x15 }; u32 *off = (u32 *)memsearch(code, pattern, size, sizeof(pattern)); if(off == NULL) goto error; //Patch N3DS CPU Clock and L2 cache setting *(off - 4) = *(off - 3); *(off - 3) = *(off - 1); memcpy(off - 1, off, 16); *(off + 3) = 0xE3800000 | cpuSetting; } } } else if(progId == 0x0004013000001702LL) //CFG { static const u8 pattern[] = { 0x06, 0x46, 0x10, 0x48 }, patch[] = { 0x00, 0x26 }; //Disable SecureInfo signature check if(!patchMemory(code, size, pattern, sizeof(pattern), 0, patch, sizeof(patch), 1 )) goto error; if(secureInfoExists()) { static const u16 pattern[] = u"Sec", patch[] = u"C"; //Use SecureInfo_C if(patchMemory(code, size, pattern, sizeof(pattern) - 2, 22, patch, sizeof(patch) - 2, 2 ) != 2) goto error; } } else if(progId == 0x0004013000003702LL && progVer > 0) //RO { static const u8 pattern[] = { 0x20, 0xA0, 0xE1, 0x8B }, pattern2[] = { 0xE1, 0x30, 0x40, 0x2D }, pattern3[] = { 0x2D, 0xE9, 0x01, 0x70 }, patch[] = { 0x00, 0x00, 0xA0, 0xE3, 0x1E, 0xFF, 0x2F, 0xE1 //mov r0, #0; bx lr }; //Disable CRR0 signature (RSA2048 with SHA256) check and CRO0/CRR0 SHA256 hash checks (section hashes, and hash table) if(!patchMemory(code, size, pattern, sizeof(pattern), -9, patch, sizeof(patch), 1 ) || !patchMemory(code, size, pattern2, sizeof(pattern2), 1, patch, sizeof(patch), 1 ) || !patchMemory(code, size, pattern3, sizeof(pattern3), -2, patch, sizeof(patch), 1 )) goto error; } else if(progId == 0x0004003000008A02LL && MULTICONFIG(DEVOPTIONS) == 1) //ErrDisp { static const u8 pattern[] = { 0x00, 0xD0, 0xE5, 0xDB }, pattern2[] = { 0x14, 0x00, 0xD0, 0xE5, 0x01 }, patch[] = { 0x00, 0x00, 0xA0, 0xE3 }; //Patch UNITINFO checks to make ErrDisp more verbose if(!patchMemory(code, size, pattern, sizeof(pattern), -1, patch, sizeof(patch), 1 ) || patchMemory(code, size, pattern2, sizeof(pattern2), 0, patch, sizeof(patch), 3 ) != 3) goto error; } else if (progId == 0x0004013000003802LL) // ACT Module { antibanPatch(code, size); } if(CONFIG(PATCHGAMES) && (u32)((progId >> 0x20) & 0xFFFFFFEDULL) == 0x00040000) { u8 regionId = 0xFF, languageId; if(!loadTitleCodeSection(progId, code, size) || !loadTitleLocaleConfig(progId, ®ionId, &languageId)) goto error; if(regionId != 0xFF) { u32 CFGUHandleOffset; u8 *CFGU_GetConfigInfoBlk2_endPos = getCfgOffsets(code, size, &CFGUHandleOffset); if(CFGU_GetConfigInfoBlk2_endPos == NULL || !patchCfgGetLanguage(code, size, languageId, CFGU_GetConfigInfoBlk2_endPos)) goto error; patchCfgGetRegion(code, size, regionId, CFGUHandleOffset); } if(!patchRomfsRedirection(progId, code, size)) goto error; } return; error: svcBreak(USERBREAK_ASSERT); while(true); }
static void __panic(void) { svcBreak(USERBREAK_PANIC); for (;;); }