// Copyright (c) 2012- PPSSPP Project. // 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, version 2.0. // 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 2.0 for more details. // A copy of the GPL 2.0 should have been included with the program. // If not, see http://www.gnu.org/licenses/ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. #include "HLE.h" #include "../MIPS/MIPS.h" #include "../MIPS/MIPSCodeUtils.h" #include "../MIPS/MIPSInt.h" #include "../FileSystems/FileSystem.h" #include "../FileSystems/MetaFileSystem.h" #include "../PSPLoaders.h" #include "../../Core/CoreTiming.h" #include "../../Core/System.h" #include "__sceAudio.h" #include "sceAudio.h" #include "sceDisplay.h" #include "sceGe.h" #include "sceIo.h" #include "sceKernel.h" #include "sceKernelAlarm.h" #include "sceKernelCallback.h" #include "sceKernelInterrupt.h" #include "sceKernelThread.h" #include "sceKernelMemory.h" #include "sceKernelMutex.h" #include "sceKernelMbx.h" #include "sceKernelMsgPipe.h" #include "sceKernelInterrupt.h" #include "sceKernelSemaphore.h" #include "sceKernelEventFlag.h" #include "sceKernelVTimer.h" #include "sceKernelTime.h" #include "sceUtility.h" #include "sceUmd.h" extern MetaFileSystem pspFileSystem; /* 17: [MIPS32 R4K 00000000 ]: Loader: Type: 1 Vaddr: 00000000 Filesz: 2856816 Memsz: 2856816 18: [MIPS32 R4K 00000000 ]: Loader: Loadable Segment Copied to 0898dab0, size 002b9770 19: [MIPS32 R4K 00000000 ]: Loader: Type: 1 Vaddr: 002b9770 Filesz: 14964 Memsz: 733156 20: [MIPS32 R4K 00000000 ]: Loader: Loadable Segment Copied to 08c47220, size 000b2fe4 */ static bool kernelRunning = false; void __KernelInit() { if (kernelRunning) { ERROR_LOG(HLE, "Can't init kernel when kernel is running"); return; } __KernelMemoryInit(); __KernelThreadingInit(); __IoInit(); __AudioInit(); __DisplayInit(); __InterruptsInit(); __GeInit(); __UtilityInit(); __UmdInit(); kernelRunning = true; INFO_LOG(HLE, "Kernel initialized."); } void __KernelShutdown() { if (!kernelRunning) { ERROR_LOG(HLE, "Can't shut down kernel - not running"); return; } kernelObjects.List(); INFO_LOG(HLE, "Shutting down kernel - %i kernel objects alive", kernelObjects.GetCount()); kernelObjects.Clear(); __GeShutdown(); __AudioShutdown(); __IoShutdown(); __InterruptsShutdown(); __KernelThreadingShutdown(); __KernelMemoryShutdown(); CoreTiming::ClearPendingEvents(); CoreTiming::UnregisterAllEvents(); kernelRunning = false; } void sceKernelExitGame() { INFO_LOG(HLE,"sceKernelExitGame"); if (PSP_CoreParameter().headLess) exit(0); else PanicAlert("Game exited"); Core_Stop(); RETURN(0); } void sceKernelRegisterExitCallback() { u32 cbid = PARAM(0); ERROR_LOG(HLE,"UNIMPL sceKernelRegisterExitCallback(%i)", cbid); RETURN(0); } // TODO: What? void sceKernelDevkitVersion() { ERROR_LOG(HLE,"unimpl sceKernelDevkitVersion"); RETURN(1); } ////////////////////////////////////////////////////////////////////////// // DEBUG ////////////////////////////////////////////////////////////////////////// void sceKernelRegisterKprintfHandler(u32, u32) { ERROR_LOG(HLE,"UNIMPL sceKernelRegisterKprintfHandler()"); RETURN(0); } void sceKernelRegisterDefaultExceptionHandler() { ERROR_LOG(HLE,"UNIMPL sceKernelRegisterDefaultExceptionHandler()"); RETURN(0); } void sceKernelSetGPO(u32 num) { // Sets debug LEDs. INFO_LOG(HLE,"sceKernelSetGPO(%02x)", num); } u32 sceKernelGetGPI() { // Always returns 0 on production systems. INFO_LOG(HLE,"0=sceKernelGetGPI()"); return 0; } void sceKernelDcacheWritebackAll() { } void sceKernelDcacheWritebackRange(u32, u32) { } void sceKernelDcacheWritebackInvalidateRange(u32, u32) { } void sceKernelDcacheWritebackInvalidateAll() { } KernelObjectPool kernelObjects; KernelObjectPool::KernelObjectPool() { memset(occupied, 0, sizeof(bool)*maxCount); } SceUID KernelObjectPool::Create(KernelObject *obj) { for (int i=0; iuid = i + handleOffset; return i + handleOffset; } } _dbg_assert_(HLE, 0); return 0; } bool KernelObjectPool::IsValid(SceUID handle) { int index = handle - handleOffset; if (index < 0) return false; if (index >= maxCount) return false; return occupied[index]; } void KernelObjectPool::Clear() { for (int i=0; iGetQuickInfo(buffer,256); } else { strcpy(buffer,"WTF? Zero Pointer"); } INFO_LOG(HLE, "KO %i: %s \"%s\": %s", i + handleOffset, pool[i]->GetTypeName(), pool[i]->GetName(), buffer); } } } int KernelObjectPool::GetCount() { int count = 0; for (int i=0; i, "sceKernelCreateEventFlag"}, {0x812346E4,&Wrap, "sceKernelClearEventFlag"}, {0xEF9E4C70,&Wrap, "sceKernelDeleteEventFlag"}, {0x1fb15a32,&Wrap, "sceKernelSetEventFlag"}, {0x402FCF22,&Wrap, "sceKernelWaitEventFlag"}, {0x328C546A,&Wrap, "sceKernelWaitEventFlagCB"}, {0x30FD48F0,&Wrap, "sceKernelPollEventFlag"}, {0xCD203292,&Wrap, "sceKernelCancelEventFlag"}, {0xA66B0120,&Wrap,"sceKernelReferEventFlagStatus"}, {0x8FFDF9A2,&Wrap, "sceKernelCancelSema"}, {0xD6DA4BA1,&Wrap, "sceKernelCreateSema"}, {0x28b6489c,&Wrap, "sceKernelDeleteSema"}, {0x58b1f937,&Wrap, "sceKernelPollSema"}, {0xBC6FEBC5,&Wrap,"sceKernelReferSemaStatus"}, {0x3F53E640,&Wrap, "sceKernelSignalSema"}, {0x4E3A1105,&Wrap, "sceKernelWaitSema"}, {0x6d212bac,&Wrap, "sceKernelWaitSemaCB"}, {0x60107536,0,"sceKernelDeleteLwMutex"}, {0x19CFF145,0,"sceKernelCreateLwMutex"}, {0xf8170fbe,&Wrap,"sceKernelDeleteMutex"}, {0xB011B11F,&Wrap,"sceKernelLockMutex"}, {0x5bf4dd27,&Wrap,"sceKernelLockMutexCB"}, {0x6b30100f,&Wrap,"sceKernelUnlockMutex"}, {0xb7d098c6,&Wrap,"sceKernelCreateMutex"}, // NOTE: LockLwMutex and UnlockLwMutex are in Kernel_Library, see sceKernelInterrupt.cpp. {0xFCCFAD26,0,"sceKernelCancelWakeupThread"}, {0xea748e31,&Wrap,"sceKernelChangeCurrentThreadAttr"}, {0x71bc9871,&Wrap,"sceKernelChangeThreadPriority"}, {0x446D8DE6,&Wrap,"sceKernelCreateThread"}, {0x9fa03cd3,&Wrap,"sceKernelDeleteThread"}, {0xBD123D9E,0,"sceKernelDelaySysClockThread"}, {0x1181E963,0,"sceKernelDelaySysClockThreadCB"}, {0xceadeb47,&Wrap,"sceKernelDelayThread"}, {0x68da9e36,&Wrap,"sceKernelDelayThreadCB"}, {0xaa73c935,&Wrap,"sceKernelExitThread"}, {0x809ce29b,&Wrap,"sceKernelExitDeleteThread"}, {0x94aa61ee,0,"sceKernelGetThreadCurrentPriority"}, {0x293b45b8,&Wrap,"sceKernelGetThreadId"}, {0x3B183E26,&Wrap,"sceKernelGetThreadExitStatus"}, {0x52089CA1,&Wrap,"sceKernelGetThreadStackFreeSize"}, {0xFFC36A14,0,"sceKernelReferThreadRunStatus"}, {0x17c1684e,&Wrap,"sceKernelReferThreadStatus"}, {0x2C34E053,0,"sceKernelReleaseWaitThread"}, {0x75156e8f,&Wrap,"sceKernelResumeThread"}, {0x27e22ec2,0,"sceKernelResumeDispatchThread"}, {0x912354a7,&Wrap,"sceKernelRotateThreadReadyQueue"}, {0x9ACE131E,&Wrap,"sceKernelSleepThread"}, {0x82826f70,&Wrap,"sceKernelSleepThreadCB"}, {0xF475845D,&Wrap,"sceKernelStartThread"}, {0x9944f31f,&Wrap,"sceKernelSuspendThread"}, {0x3ad58b8c,0,"sceKernelSuspendDispatchThread"}, {0x616403ba,0,"sceKernelTerminateThread"}, {0x383f7bcc,&Wrap,"sceKernelTerminateDeleteThread"}, {0x840E8133,&Wrap,"sceKernelWaitThreadEndCB"}, {0xd13bde95,&Wrap,"sceKernelCheckThreadStack"}, {0x94416130,0,"sceKernelGetThreadmanIdList"}, {0x57CF62DD,&Wrap,"sceKernelGetThreadmanIdType"}, {0x20fff560,&Wrap,"sceKernelCreateVTimer"}, {0x328F9E52,0,"sceKernelDeleteVTimer"}, {0xc68d9437,&Wrap,"sceKernelStartVTimer"}, {0xD0AEEE87,0,"sceKernelStopVTimer"}, {0xD2D615EF,0,"sceKernelCancelVTimerHandler"}, {0xB3A59970,0,"sceKernelGetVTimerBase"}, {0xB7C18B77,0,"sceKernelGetVTimerBaseWide"}, {0x034A921F,0,"sceKernelGetVTimerTime"}, {0xC0B3FFD2,0,"sceKernelGetVTimerTimeWide"}, {0x5F32BEAA,0,"sceKernelReferVTimerStatus"}, {0x542AD630,0,"sceKernelSetVTimerTime"}, {0xFB6425C3,0,"sceKernelSetVTimerTimeWide"}, {0xd8b299ae,&Wrap,"sceKernelSetVTimerHandler"}, {0x53B00E9A,0,"sceKernelSetVTimerHandlerWide"}, {0x82BC5777,&Wrap,"sceKernelGetSystemTimeWide"}, {0xdb738f35,&Wrap,"sceKernelGetSystemTime"}, {0x369ed59d,&Wrap,"sceKernelGetSystemTimeLow"}, {0x8218B4DD,0,"sceKernelReferGlobalProfiler"}, {0x627E6F3A,0,"sceKernelReferSystemStatus"}, {0x64D4540E,0,"sceKernelReferThreadProfiler"}, //Fifa Street 2 uses alarms {0x6652b8ca,&Wrap,"sceKernelSetAlarm"}, {0xB2C25152,&Wrap,"sceKernelSetSysClockAlarm"}, {0x7e65b999,&Wrap,"sceKernelCancelAlarm"}, {0xDAA3F564,&Wrap,"sceKernelReferAlarmStatus"}, {0xba6b92e2,&Wrap,"sceKernelSysClock2USec"}, {0x110DEC9A,0,"sceKernelUSec2SysClock"}, {0xC8CD158C,0,"sceKernelUSec2SysClockWide"}, {0xE1619D7C,&Wrap,"sceKernelSysClock2USecWide"}, {0x110dec9a,&Wrap,"sceKernelUSec2SysClock"}, {0x278C0DF5,&Wrap,"sceKernelWaitThreadEnd"}, {0xd59ead2f,&Wrap,"sceKernelWakeupThread"}, //AI Go, audio? {0x0C106E53,0,"sceKernelRegisterThreadEventHandler"}, {0x72F3C145,0,"sceKernelReleaseThreadEventHandler"}, {0x369EEB6B,0,"sceKernelReferThreadEventHandlerStatus"}, {0x349d6d6c,&Wrap,"sceKernelCheckCallback"}, {0xE81CAF8F,&Wrap,"sceKernelCreateCallback"}, {0xEDBA5844,&Wrap,"sceKernelDeleteCallback"}, {0xC11BA8C4,&Wrap,"sceKernelNotifyCallback"}, {0xBA4051D6,&Wrap,"sceKernelCancelCallback"}, {0x2A3D44FF,&Wrap,"sceKernelGetCallbackCount"}, {0x349D6D6C,&Wrap,"sceKernelCheckCallback"}, {0x730ED8BC,&Wrap,"sceKernelReferCallbackStatus"}, {0x8125221D,&Wrap,"sceKernelCreateMbx"}, {0x86255ADA,&Wrap,"sceKernelDeleteMbx"}, {0xE9B3061E,&Wrap,"sceKernelSendMbx"}, {0x18260574,&Wrap,"sceKernelReceiveMbx"}, {0xF3986382,&Wrap,"sceKernelReceiveMbxCB"}, {0x0D81716A,&Wrap,"sceKernelPollMbx"}, {0x87D4DD36,&Wrap,"sceKernelCancelReceiveMbx"}, {0xA8E8C846,&Wrap,"sceKernelReferMbxStatus"}, {0x7C0DC2A0,&Wrap,"sceKernelCreateMsgPipe"}, {0xF0B7DA1C,&Wrap,"sceKernelDeleteMsgPipe"}, {0x876DBFAD,&Wrap,"sceKernelSendMsgPipe"}, {0x7C41F2C2,&Wrap,"sceKernelSendMsgPipeCB"}, {0x884C9F90,&Wrap,"sceKernelTrySendMsgPipe"}, {0x74829B76,&Wrap,"sceKernelReceiveMsgPipe"}, {0xFBFA697D,&Wrap,"sceKernelReceiveMsgPipeCB"}, {0xDF52098F,&Wrap,"sceKernelTryReceiveMsgPipe"}, {0x349B864D,&Wrap,"sceKernelCancelMsgPipe"}, {0x33BE4024,&Wrap,"sceKernelReferMsgPipeStatus"}, {0x56C039B5,&Wrap,"sceKernelCreateVpl"}, {0x89B3D48C,&Wrap,"sceKernelDeleteVpl"}, {0xBED27435,&Wrap,"sceKernelAllocateVpl"}, {0xEC0A693F,&Wrap,"sceKernelAllocateVplCB"}, {0xAF36D708,&Wrap,"sceKernelTryAllocateVpl"}, {0xB736E9FF,&Wrap,"sceKernelFreeVpl"}, {0x1D371B8A,&Wrap,"sceKernelCancelVpl"}, {0x39810265,&Wrap,"sceKernelReferVplStatus"}, {0xC07BB470,&Wrap,"sceKernelCreateFpl"}, {0xED1410E0,&Wrap,"sceKernelDeleteFpl"}, {0xD979E9BF,&Wrap,"sceKernelAllocateFpl"}, {0xE7282CB6,&Wrap,"sceKernelAllocateFplCB"}, {0x623AE665,&Wrap,"sceKernelTryAllocateFpl"}, {0xF6414A71,&Wrap,"sceKernelFreeFpl"}, {0xA8AA591F,&Wrap,"sceKernelCancelFpl"}, {0xD8199E4C,&Wrap,"sceKernelReferFplStatus"}, {0x0E927AED, _sceKernelReturnFromTimerHandler, "_sceKernelReturnFromTimerHandler"}, {0x532A522E, _sceKernelExitThread,"_sceKernelExitThread"}, // Shouldn't hook this up. No games should import this function manually and call it. // {0x6E9EA350, _sceKernelReturnFromCallback,"_sceKernelReturnFromCallback"}, }; void Register_ThreadManForUser() { RegisterModule("ThreadManForUser", ARRAY_SIZE(ThreadManForUser), ThreadManForUser); } const HLEFunction LoadExecForUser[] = { {0x05572A5F,sceKernelExitGame, "sceKernelExitGame"}, //() {0x4AC57943,sceKernelRegisterExitCallback,"sceKernelRegisterExitCallback"}, {0xBD2F1094,sceKernelLoadExec,"sceKernelLoadExec"}, {0x2AC9954B,0,"sceKernelExitGameWithStatus"}, }; void Register_LoadExecForUser() { RegisterModule("LoadExecForUser", ARRAY_SIZE(LoadExecForUser), LoadExecForUser); } const HLEFunction ExceptionManagerForKernel[] = { {0x3FB264FC, 0, "sceKernelRegisterExceptionHandler"}, {0x5A837AD4, 0, "sceKernelRegisterPriorityExceptionHandler"}, {0x565C0B0E, sceKernelRegisterDefaultExceptionHandler, "sceKernelRegisterDefaultExceptionHandler"}, {0x1AA6CFFA, 0, "sceKernelReleaseExceptionHandler"}, {0xDF83875E, 0, "sceKernelGetActiveDefaultExceptionHandler"}, {0x291FF031, 0, "sceKernelReleaseDefaultExceptionHandler"}, {0x15ADC862, 0, "sceKernelRegisterNmiHandler"}, {0xB15357C9, 0, "sceKernelReleaseNmiHandler"}, }; void Register_ExceptionManagerForKernel() { RegisterModule("ExceptionManagerForKernel", ARRAY_SIZE(ExceptionManagerForKernel), ExceptionManagerForKernel); }