diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp index fc308b364..26e517bcb 100644 --- a/src/citra_qt/bootmanager.cpp +++ b/src/citra_qt/bootmanager.cpp @@ -35,6 +35,12 @@ void EmuThread::run() { emit DebugModeLeft(); Core::System::ResultStatus result = Core::System::GetInstance().RunLoop(); + if (result == Core::System::ResultStatus::ShutdownRequested) { + // Notify frontend we shutdown + emit ErrorThrown(result, ""); + // End emulation execution + break; + } if (result != Core::System::ResultStatus::Success) { this->SetRunning(false); emit ErrorThrown(result, Core::System::GetInstance().GetStatusDetails()); diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp index 3f0388d0a..43cf839ae 100644 --- a/src/citra_qt/main.cpp +++ b/src/citra_qt/main.cpp @@ -1400,7 +1400,6 @@ void GMainWindow::UpdateStatusBar() { } void GMainWindow::OnCoreError(Core::System::ResultStatus result, std::string details) { - QMessageBox::StandardButton answer; QString status_message; QString title, message; @@ -1435,9 +1434,11 @@ void GMainWindow::OnCoreError(Core::System::ResultStatus result, std::string det message_box.setIcon(QMessageBox::Icon::Critical); QPushButton* continue_button = message_box.addButton(tr("Continue"), QMessageBox::RejectRole); QPushButton* abort_button = message_box.addButton(tr("Abort"), QMessageBox::AcceptRole); - message_box.exec(); + if (result != Core::System::ResultStatus::ShutdownRequested) + message_box.exec(); - if (message_box.clickedButton() == abort_button) { + if (result == Core::System::ResultStatus::ShutdownRequested || + message_box.clickedButton() == abort_button) { if (emu_thread) { ShutdownGame(); } diff --git a/src/core/core.cpp b/src/core/core.cpp index bd8be21c9..cef1ddc4b 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -77,6 +77,12 @@ System::ResultStatus System::RunLoop(bool tight_loop) { HW::Update(); Reschedule(); + if (reset_requested.exchange(false)) { + Reset(); + } else if (shutdown_requested.exchange(false)) { + return ResultStatus::ShutdownRequested; + } + return status; } @@ -132,6 +138,8 @@ System::ResultStatus System::Load(EmuWindow& emu_window, const std::string& file } Memory::SetCurrentPageTable(&Kernel::g_current_process->vm_manager.page_table); status = ResultStatus::Success; + m_emu_window = &emu_window; + m_filepath = filepath; return status; } @@ -241,4 +249,14 @@ void System::Shutdown() { LOG_DEBUG(Core, "Shutdown OK"); } +void System::Reset() { + // This is NOT a proper reset, but a temporary workaround by shutting down the system and + // reloading. + // TODO: Properly implement the reset + + Shutdown(); + // Reload the system with the same setting + Load(*m_emu_window, m_filepath); +} + } // namespace Core diff --git a/src/core/core.h b/src/core/core.h index 3477865fb..12a1e5c68 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -59,6 +59,7 @@ public: /// generic drivers installed ErrorVideoCore_ErrorBelowGL33, ///< Error in the video core due to the user not having /// OpenGL 3.3 or higher + ShutdownRequested, ///< Emulated program requested a system shutdown ErrorUnknown ///< Any other error }; @@ -83,6 +84,19 @@ public: /// Shutdown the emulated system. void Shutdown(); + /// Shutdown and then load again + void Reset(); + + /// Request reset of the system + void RequestReset() { + reset_requested = true; + } + + /// Request shutdown of the system + void RequestShutdown() { + shutdown_requested = true; + } + /** * Load an executable application. * @param emu_window Reference to the host-system window used for video output and keyboard @@ -216,6 +230,12 @@ private: ResultStatus status = ResultStatus::Success; std::string status_details = ""; + /// Saved variables for reset + EmuWindow* m_emu_window; + std::string m_filepath; + + std::atomic reset_requested; + std::atomic shutdown_requested; }; inline ARM_Interface& CPU() { diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp index 656e2fd77..776fba72f 100644 --- a/src/core/hle/service/apt/apt.cpp +++ b/src/core/hle/service/apt/apt.cpp @@ -543,6 +543,65 @@ void Module::Interface::StartLibraryApplet(Kernel::HLERequestContext& ctx) { rb.Push(apt->applet_manager->StartLibraryApplet(applet_id, object, buffer)); } +void Module::Interface::CloseApplication(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x27, 1, 4); + u32 parameters_size = rp.Pop(); + Kernel::SharedPtr object = rp.PopGenericObject(); + std::vector buffer = rp.PopStaticBuffer(); + + LOG_DEBUG(Service_APT, "called"); + + Core::System::GetInstance().RequestShutdown(); + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + rb.Push(RESULT_SUCCESS); +} + +void Module::Interface::PrepareToDoApplicationJump(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x31, 4, 0); + u32 flags = rp.Pop(); + u32 program_id_low = rp.Pop(); + u32 program_id_high = rp.Pop(); + Service::FS::MediaType media_type = static_cast(rp.Pop()); + + LOG_WARNING(Service_APT, + "(STUBBED) called, flags={:08X}, program_id_low={:08X}, program_id_high={:08X}, " + "media_type={:08X}", + flags, program_id_low, program_id_high, static_cast(media_type)); + + if (flags == 0x2) { + // It seems that flags 0x2 means jumping to the same application, + // and ignore the parameters. This is used in Pokemon main series + // to soft reset. + application_reset_prepared = true; + } + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + rb.Push(RESULT_SUCCESS); +} + +void Module::Interface::DoApplicationJump(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x32, 2, 4); + u32 parameter_size = rp.Pop(); + u32 hmac_size = rp.Pop(); + std::vector parameter = rp.PopStaticBuffer(); + std::vector hmac = rp.PopStaticBuffer(); + + LOG_WARNING(Service_APT, "(STUBBED) called"); + + if (application_reset_prepared) { + // Reset system + Core::System::GetInstance().RequestReset(); + } else { + // After the jump, the application should shutdown + // TODO: Actually implement the jump + Core::System::GetInstance().RequestShutdown(); + } + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + rb.Push(RESULT_SUCCESS); +} + void Module::Interface::CancelLibraryApplet(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x3B, 1, 0); // 0x003B0040 bool exiting = rp.Pop(); diff --git a/src/core/hle/service/apt/apt.h b/src/core/hle/service/apt/apt.h index 488c429f6..54149f4e9 100644 --- a/src/core/hle/service/apt/apt.h +++ b/src/core/hle/service/apt/apt.h @@ -409,6 +409,49 @@ public: */ void StartLibraryApplet(Kernel::HLERequestContext& ctx); + /** + * APT::CloseApplication service function + * Inputs: + * 0 : Command header [0x00270044] + * 1 : Parameters Size + * 2 : 0x0 + * 3 : Handle Parameter + * 4 : (Parameters Size << 14) | 2 + * 5 : void*, Parameters + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + */ + void CloseApplication(Kernel::HLERequestContext& ctx); + + /** + * APT::PrepareToDoApplicationJump service function + * Inputs: + * 0 : Command header [0x00310100] + * 1 : Flags + * 2 : Program ID low + * 3 : Program ID high + * 4 : Media type + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * @param ctx + */ + void PrepareToDoApplicationJump(Kernel::HLERequestContext& ctx); + + /** + * APT::DoApplicationJump service function + * Inputs: + * 0 : Command header [0x00320084] + * 1 : Parameter Size (capped to 0x300) + * 2 : HMAC Size (capped to 0x20) + * 3 : (Parameter Size << 14) | 2 + * 4 : void*, Parameter + * 5 : (HMAC Size << 14) | 0x802 + * 6 : void*, HMAC + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + */ + void DoApplicationJump(Kernel::HLERequestContext& ctx); + /** * APT::CancelLibraryApplet service function * Inputs: @@ -533,6 +576,7 @@ public: private: std::shared_ptr apt; + bool application_reset_prepared{}; }; private: diff --git a/src/core/hle/service/apt/apt_a.cpp b/src/core/hle/service/apt/apt_a.cpp index b69ffcc11..8ad09025d 100644 --- a/src/core/hle/service/apt/apt_a.cpp +++ b/src/core/hle/service/apt/apt_a.cpp @@ -48,7 +48,7 @@ APT_A::APT_A(std::shared_ptr apt) {0x00240044, nullptr, "JumpToApplication"}, {0x002500C0, &APT_A::PrepareToCloseLibraryApplet, "PrepareToCloseLibraryApplet"}, {0x00260000, nullptr, "PrepareToCloseSystemApplet"}, - {0x00270044, nullptr, "CloseApplication"}, + {0x00270044, &APT_A::CloseApplication, "CloseApplication"}, {0x00280044, &APT_A::CloseLibraryApplet, "CloseLibraryApplet"}, {0x00290044, nullptr, "CloseSystemApplet"}, {0x002A0000, nullptr, "OrderToCloseSystemApplet"}, @@ -58,8 +58,8 @@ APT_A::APT_A(std::shared_ptr apt) {0x002E0044, nullptr, "LeaveHomeMenu"}, {0x002F0040, nullptr, "PrepareToLeaveResidentApplet"}, {0x00300044, nullptr, "LeaveResidentApplet"}, - {0x00310100, nullptr, "PrepareToDoApplicationJump"}, - {0x00320084, nullptr, "DoApplicationJump"}, + {0x00310100, &APT_A::PrepareToDoApplicationJump, "PrepareToDoApplicationJump"}, + {0x00320084, &APT_A::DoApplicationJump, "DoApplicationJump"}, {0x00330000, nullptr, "GetProgramIdOnApplicationJump"}, {0x00340084, nullptr, "SendDeliverArg"}, {0x00350080, nullptr, "ReceiveDeliverArg"}, diff --git a/src/core/hle/service/apt/apt_s.cpp b/src/core/hle/service/apt/apt_s.cpp index 67ed7b9d9..341c384ca 100644 --- a/src/core/hle/service/apt/apt_s.cpp +++ b/src/core/hle/service/apt/apt_s.cpp @@ -48,7 +48,7 @@ APT_S::APT_S(std::shared_ptr apt) {0x00240044, nullptr, "JumpToApplication"}, {0x002500C0, nullptr, "PrepareToCloseLibraryApplet"}, {0x00260000, nullptr, "PrepareToCloseSystemApplet"}, - {0x00270044, nullptr, "CloseApplication"}, + {0x00270044, &APT_S::CloseApplication, "CloseApplication"}, {0x00280044, nullptr, "CloseLibraryApplet"}, {0x00290044, nullptr, "CloseSystemApplet"}, {0x002A0000, nullptr, "OrderToCloseSystemApplet"}, @@ -58,8 +58,8 @@ APT_S::APT_S(std::shared_ptr apt) {0x002E0044, nullptr, "LeaveHomeMenu"}, {0x002F0040, nullptr, "PrepareToLeaveResidentApplet"}, {0x00300044, nullptr, "LeaveResidentApplet"}, - {0x00310100, nullptr, "PrepareToDoApplicationJump"}, - {0x00320084, nullptr, "DoApplicationJump"}, + {0x00310100, &APT_S::PrepareToDoApplicationJump, "PrepareToDoApplicationJump"}, + {0x00320084, &APT_S::DoApplicationJump, "DoApplicationJump"}, {0x00330000, nullptr, "GetProgramIdOnApplicationJump"}, {0x00340084, nullptr, "SendDeliverArg"}, {0x00350080, nullptr, "ReceiveDeliverArg"}, diff --git a/src/core/hle/service/apt/apt_u.cpp b/src/core/hle/service/apt/apt_u.cpp index 44c9ac8e5..9fcb38005 100644 --- a/src/core/hle/service/apt/apt_u.cpp +++ b/src/core/hle/service/apt/apt_u.cpp @@ -48,7 +48,7 @@ APT_U::APT_U(std::shared_ptr apt) {0x00240044, nullptr, "JumpToApplication"}, {0x002500C0, &APT_U::PrepareToCloseLibraryApplet, "PrepareToCloseLibraryApplet"}, {0x00260000, nullptr, "PrepareToCloseSystemApplet"}, - {0x00270044, nullptr, "CloseApplication"}, + {0x00270044, &APT_U::CloseApplication, "CloseApplication"}, {0x00280044, &APT_U::CloseLibraryApplet, "CloseLibraryApplet"}, {0x00290044, nullptr, "CloseSystemApplet"}, {0x002A0000, nullptr, "OrderToCloseSystemApplet"}, @@ -58,8 +58,8 @@ APT_U::APT_U(std::shared_ptr apt) {0x002E0044, nullptr, "LeaveHomeMenu"}, {0x002F0040, nullptr, "PrepareToLeaveResidentApplet"}, {0x00300044, nullptr, "LeaveResidentApplet"}, - {0x00310100, nullptr, "PrepareToDoApplicationJump"}, - {0x00320084, nullptr, "DoApplicationJump"}, + {0x00310100, &APT_U::PrepareToDoApplicationJump, "PrepareToDoApplicationJump"}, + {0x00320084, &APT_U::DoApplicationJump, "DoApplicationJump"}, {0x00330000, nullptr, "GetProgramIdOnApplicationJump"}, {0x00340084, nullptr, "SendDeliverArg"}, {0x00350080, nullptr, "ReceiveDeliverArg"},