bool __KernelLoadExec(const char *filename, SceKernelLoadExecParam *param, std::string *error_string) { // Wipe kernel here, loadexec should reset the entire system if (__KernelIsRunning()) __KernelShutdown(); __KernelModuleInit(); __KernelInit(); PSPFileInfo info = pspFileSystem.GetFileInfo(filename); u32 handle = pspFileSystem.OpenFile(filename, FILEACCESS_READ); u8 *temp = new u8[(int)info.size + 0x1000000]; pspFileSystem.ReadFile(handle, temp, (size_t)info.size); Module *module = __KernelLoadModule(temp, 0, error_string); if (!module) { ERROR_LOG(LOADER, "Failed to load module %s", filename); return false; } mipsr4k.pc = module->nm.entry_addr; INFO_LOG(LOADER, "Module entry: %08x", mipsr4k.pc); delete [] temp; pspFileSystem.CloseFile(handle); SceKernelSMOption option; option.size = sizeof(SceKernelSMOption); option.attribute = PSP_THREAD_ATTR_USER; option.mpidstack = 2; option.priority = 0x20; option.stacksize = 0x40000; // crazy? but seems to be the truth // Replace start options with module-specified values if they exist. if (module->nm.module_start_thread_attr != 0) option.attribute = module->nm.module_start_thread_attr; if (module->nm.module_start_thread_priority != 0) option.priority = module->nm.module_start_thread_priority; if (module->nm.module_start_thread_stacksize != 0) option.stacksize = module->nm.module_start_thread_stacksize; __KernelStartModule(module, (u32)strlen(filename) + 1, filename, &option); __KernelStartIdleThreads(); return true; }
void Enqueue(SaveState::Operation op) { std::lock_guard<std::recursive_mutex> guard(mutex); pending.push_back(op); // Don't actually run it until next CoreTiming::Advance(). // It's possible there might be a duplicate but it won't hurt us. if (Core_IsInactive() && __KernelIsRunning()) { // Warning: this may run on a different thread. needsProcess = true; Process(); } else { needsProcess = true; } }
void Process() { #ifndef USING_GLES2 if (g_Config.iRewindFlipFrequency != 0 && gpuStats.numFlips != 0) CheckRewindState(); #endif if (!needsProcess) return; needsProcess = false; if (!__KernelIsRunning()) { ERROR_LOG(COMMON, "Savestate failure: Unable to load without kernel, this should never happen."); return; } std::vector<Operation> operations = Flush(); SaveStart state; for (size_t i = 0, n = operations.size(); i < n; ++i) { Operation &op = operations[i]; CChunkFileReader::Error result; bool callbackResult; std::string reason; I18NCategory *s = GetI18NCategory("Screen"); // I couldn't stand the inconsistency. But trying not to break old lang files. const char *i18nLoadFailure = s->T("Load savestate failed", ""); const char *i18nSaveFailure = s->T("Save State Failed", ""); if (strlen(i18nLoadFailure) == 0) i18nLoadFailure = s->T("Failed to load state"); if (strlen(i18nSaveFailure) == 0) i18nSaveFailure = s->T("Failed to save state"); switch (op.type) { case SAVESTATE_LOAD: INFO_LOG(COMMON, "Loading state from %s", op.filename.c_str()); result = CChunkFileReader::Load(op.filename, REVISION, PPSSPP_GIT_VERSION, state, &reason); if (result == CChunkFileReader::ERROR_NONE) { osm.Show(s->T("Loaded State"), 2.0); callbackResult = true; } else if (result == CChunkFileReader::ERROR_BROKEN_STATE) { HandleFailure(); osm.Show(i18nLoadFailure, 2.0); ERROR_LOG(COMMON, "Load state failure: %s", reason.c_str()); callbackResult = false; } else { osm.Show(s->T(reason.c_str(), i18nLoadFailure), 2.0); callbackResult = false; } break; case SAVESTATE_SAVE: INFO_LOG(COMMON, "Saving state to %s", op.filename.c_str()); result = CChunkFileReader::Save(op.filename, REVISION, PPSSPP_GIT_VERSION, state); if (result == CChunkFileReader::ERROR_NONE) { osm.Show(s->T("Saved State"), 2.0); callbackResult = true; } else if (result == CChunkFileReader::ERROR_BROKEN_STATE) { HandleFailure(); osm.Show(i18nSaveFailure, 2.0); ERROR_LOG(COMMON, "Save state failure: %s", reason.c_str()); callbackResult = false; } else { osm.Show(i18nSaveFailure, 2.0); callbackResult = false; } break; case SAVESTATE_VERIFY: INFO_LOG(COMMON, "Verifying save state system"); callbackResult = CChunkFileReader::Verify(state) == CChunkFileReader::ERROR_NONE; break; case SAVESTATE_REWIND: INFO_LOG(COMMON, "Rewinding to recent savestate snapshot"); result = rewindStates.Restore(); if (result == CChunkFileReader::ERROR_NONE) { osm.Show(s->T("Loaded State"), 2.0); callbackResult = true; } else if (result == CChunkFileReader::ERROR_BROKEN_STATE) { // Cripes. Good news is, we might have more. Let's try those too, better than a reset. if (HandleFailure()) { // Well, we did rewind, even if too much... osm.Show(s->T("Loaded State"), 2.0); callbackResult = true; } else { osm.Show(i18nLoadFailure, 2.0); callbackResult = false; } } else { osm.Show(i18nLoadFailure, 2.0); callbackResult = false; } break; default: ERROR_LOG(COMMON, "Savestate failure: unknown operation type %d", op.type); callbackResult = false; break; } if (op.callback) op.callback(callbackResult, op.cbUserData); } }
void Process() { if (!needsProcess) return; needsProcess = false; if (!__KernelIsRunning()) { ERROR_LOG(COMMON, "Savestate failure: Unable to load without kernel, this should never happen."); return; } std::vector<Operation> operations = Flush(); SaveStart state; for (size_t i = 0, n = operations.size(); i < n; ++i) { Operation &op = operations[i]; bool result; std::string reason; I18NCategory *s = GetI18NCategory("Screen"); switch (op.type) { case SAVESTATE_LOAD: if (MIPSComp::jit) MIPSComp::jit->ClearCache(); INFO_LOG(COMMON, "Loading state from %s", op.filename.c_str()); result = CChunkFileReader::Load(op.filename, REVISION, state, &reason); if(result) osm.Show(s->T("Loaded State"), 2.0); else { osm.Show(s->T(reason.c_str(), "Load savestate failed"), 2.0); } break; case SAVESTATE_SAVE: if (MIPSComp::jit) MIPSComp::jit->ClearCache(); INFO_LOG(COMMON, "Saving state to %s", op.filename.c_str()); result = CChunkFileReader::Save(op.filename, REVISION, state); if(result) osm.Show(s->T("Saved State"), 2.0); else osm.Show(s->T("Save State Failed"), 2.0); break; case SAVESTATE_VERIFY: INFO_LOG(COMMON, "Verifying save state system"); result = CChunkFileReader::Verify(state); break; default: ERROR_LOG(COMMON, "Savestate failure: unknown operation type %d", op.type); result = false; break; } if (op.callback != NULL) op.callback(result, op.cbUserData); } }
void Process() { #ifndef MOBILE_DEVICE if (g_Config.iRewindFlipFrequency != 0 && gpuStats.numFlips != 0) CheckRewindState(); #endif if (!needsProcess) return; needsProcess = false; if (!__KernelIsRunning()) { ERROR_LOG(COMMON, "Savestate failure: Unable to load without kernel, this should never happen."); return; } std::vector<Operation> operations = Flush(); SaveStart state; for (size_t i = 0, n = operations.size(); i < n; ++i) { Operation &op = operations[i]; CChunkFileReader::Error result; bool callbackResult; std::string callbackMessage; std::string reason; I18NCategory *sc = GetI18NCategory("Screen"); const char *i18nLoadFailure = sc->T("Load savestate failed", ""); const char *i18nSaveFailure = sc->T("Save State Failed", ""); if (strlen(i18nLoadFailure) == 0) i18nLoadFailure = sc->T("Failed to load state"); if (strlen(i18nSaveFailure) == 0) i18nSaveFailure = sc->T("Failed to save state"); switch (op.type) { case SAVESTATE_LOAD: INFO_LOG(COMMON, "Loading state from %s", op.filename.c_str()); result = CChunkFileReader::Load(op.filename, PPSSPP_GIT_VERSION, state, &reason); if (result == CChunkFileReader::ERROR_NONE) { callbackMessage = sc->T("Loaded State"); callbackResult = true; hasLoadedState = true; } else if (result == CChunkFileReader::ERROR_BROKEN_STATE) { HandleFailure(); callbackMessage = i18nLoadFailure; ERROR_LOG(COMMON, "Load state failure: %s", reason.c_str()); callbackResult = false; } else { callbackMessage = sc->T(reason.c_str(), i18nLoadFailure); callbackResult = false; } break; case SAVESTATE_SAVE: INFO_LOG(COMMON, "Saving state to %s", op.filename.c_str()); result = CChunkFileReader::Save(op.filename, g_paramSFO.GetValueString("TITLE"), PPSSPP_GIT_VERSION, state); if (result == CChunkFileReader::ERROR_NONE) { callbackMessage = sc->T("Saved State"); callbackResult = true; } else if (result == CChunkFileReader::ERROR_BROKEN_STATE) { HandleFailure(); callbackMessage = i18nSaveFailure; ERROR_LOG(COMMON, "Save state failure: %s", reason.c_str()); callbackResult = false; } else { callbackMessage = i18nSaveFailure; callbackResult = false; } break; case SAVESTATE_VERIFY: callbackResult = CChunkFileReader::Verify(state) == CChunkFileReader::ERROR_NONE; if (callbackResult) { INFO_LOG(COMMON, "Verified save state system"); } else { ERROR_LOG(COMMON, "Save state system verification failed"); } break; case SAVESTATE_REWIND: INFO_LOG(COMMON, "Rewinding to recent savestate snapshot"); result = rewindStates.Restore(); if (result == CChunkFileReader::ERROR_NONE) { callbackMessage = sc->T("Loaded State"); callbackResult = true; hasLoadedState = true; } else if (result == CChunkFileReader::ERROR_BROKEN_STATE) { // Cripes. Good news is, we might have more. Let's try those too, better than a reset. if (HandleFailure()) { // Well, we did rewind, even if too much... callbackMessage = sc->T("Loaded State"); callbackResult = true; hasLoadedState = true; } else { callbackMessage = i18nLoadFailure; callbackResult = false; } } else { callbackMessage = i18nLoadFailure; callbackResult = false; } break; case SAVESTATE_SAVE_SCREENSHOT: callbackResult = TakeGameScreenshot(op.filename.c_str(), SCREENSHOT_JPG, SCREENSHOT_RENDER); if (!callbackResult) { ERROR_LOG(COMMON, "Failed to take a screenshot for the savestate! %s", op.filename.c_str()); } break; default: ERROR_LOG(COMMON, "Savestate failure: unknown operation type %d", op.type); callbackResult = false; break; } if (op.callback) op.callback(callbackResult, callbackMessage, op.cbUserData); } if (operations.size()) { // Avoid triggering frame skipping due to slowdown __DisplaySetWasPaused(); } }