diff --git a/src/xenia/kernel/kernel_state.cc b/src/xenia/kernel/kernel_state.cc index 9778f8696..cb97337da 100644 --- a/src/xenia/kernel/kernel_state.cc +++ b/src/xenia/kernel/kernel_state.cc @@ -144,6 +144,25 @@ void KernelState::set_process_type(uint32_t value) { pib->process_type = uint8_t(value); } +void KernelState::RegisterTitleTerminateNotification(uint32_t routine, + uint32_t priority) { + TerminateNotification notify; + notify.guest_routine = routine; + notify.priority = priority; + + terminate_notifications.push_back(notify); +} + +void KernelState::RemoveTitleTerminateNotification(uint32_t routine) { + for (auto it = terminate_notifications.begin(); + it != terminate_notifications.end(); it++) { + if (it->guest_routine == routine) { + terminate_notifications.erase(it); + break; + } + } +} + void KernelState::RegisterModule(XModule* module) {} void KernelState::UnregisterModule(XModule* module) {} @@ -318,7 +337,21 @@ object_ref KernelState::LoadUserModule(const char* raw_name) { void KernelState::TerminateTitle(bool from_guest_thread) { std::lock_guard lock(object_mutex_); - // First: Kill all guest threads. + // First: Call terminate routines + // TODO: These might take arguments + // FIXME: Calling these will send some threads into kernel code and they'll + // hold the lock when terminated! Do we need to wait for all threads to exit? + /* + if (from_guest_thread) { + for (auto routine : terminate_notifications) { + auto thread_state = XThread::GetCurrentThread()->thread_state(); + processor()->Execute(thread_state, routine.guest_routine); + } + } + terminate_notifications.clear(); + */ + + // Second: Kill all guest threads. for (auto it = threads_by_id_.begin(); it != threads_by_id_.end();) { if (it->second->guest_thread()) { auto thread = it->second; @@ -329,7 +362,7 @@ void KernelState::TerminateTitle(bool from_guest_thread) { continue; } - if (it->second->running()) { + if (thread->running()) { thread->Terminate(0); } @@ -340,7 +373,7 @@ void KernelState::TerminateTitle(bool from_guest_thread) { } } - // Second: Unload all user modules (including the executable) + // Third: Unload all user modules (including the executable) for (int i = 0; i < user_modules_.size(); i++) { X_STATUS status = user_modules_[i]->Unload(); assert_true(XSUCCEEDED(status)); diff --git a/src/xenia/kernel/kernel_state.h b/src/xenia/kernel/kernel_state.h index a52c11ebd..1b6cbac4f 100644 --- a/src/xenia/kernel/kernel_state.h +++ b/src/xenia/kernel/kernel_state.h @@ -79,6 +79,11 @@ struct ProcessInfoBlock { xe::be unk_5C; }; +struct TerminateNotification { + uint32_t guest_routine; + uint32_t priority; +}; + class KernelState { public: KernelState(Emulator* emulator); @@ -108,6 +113,9 @@ class KernelState { return process_info_block_address_; } + void RegisterTitleTerminateNotification(uint32_t routine, uint32_t priority); + void RemoveTitleTerminateNotification(uint32_t routine); + void RegisterModule(XModule* module); void UnregisterModule(XModule* module); bool IsKernelModule(const char* name); @@ -179,6 +187,7 @@ class KernelState { object_ref executable_module_; std::vector> kernel_modules_; std::vector> user_modules_; + std::vector terminate_notifications; uint32_t process_info_block_address_; diff --git a/src/xenia/kernel/xboxkrnl_modules.cc b/src/xenia/kernel/xboxkrnl_modules.cc index 0c9aa051a..93ec98442 100644 --- a/src/xenia/kernel/xboxkrnl_modules.cc +++ b/src/xenia/kernel/xboxkrnl_modules.cc @@ -318,27 +318,25 @@ SHIM_CALL XexGetProcedureAddress_shim(PPCContext* ppc_context, SHIM_SET_RETURN_32(result); } -SHIM_CALL ExRegisterTitleTerminateNotification_shim(PPCContext* ppc_context, - KernelState* kernel_state) { - uint32_t registration_ptr = SHIM_GET_ARG_32(0); - uint32_t create = SHIM_GET_ARG_32(1); - - uint32_t routine = SHIM_MEM_32(registration_ptr + 0); - uint32_t priority = SHIM_MEM_32(registration_ptr + 4); - // list entry flink - // list entry blink - - XELOGD("ExRegisterTitleTerminateNotification(%.8X(%.8X, %d), %.1X)", - registration_ptr, routine, priority, create); +void AppendParam(StringBuffer& string_buffer, + pointer_t reg) { + string_buffer.AppendFormat("%.8X(%.8X, %.8X)", reg.guest_address(), + reg->notification_routine, reg->priority); +} +void ExRegisterTitleTerminateNotification( + pointer_t reg, dword_t create) { if (create) { // Adding. - // TODO(benvanik): add to master list (kernel?). + kernel_state()->RegisterTitleTerminateNotification( + reg->notification_routine, reg->priority); } else { // Removing. - // TODO(benvanik): remove from master list. + kernel_state()->RemoveTitleTerminateNotification(reg->notification_routine); } } +DECLARE_XBOXKRNL_EXPORT(ExRegisterTitleTerminateNotification, + ExportTag::kImplemented); } // namespace kernel } // namespace xe @@ -354,6 +352,4 @@ void xe::kernel::xboxkrnl::RegisterModuleExports( SHIM_SET_MAPPING("xboxkrnl.exe", XexLoadImage, state); SHIM_SET_MAPPING("xboxkrnl.exe", XexUnloadImage, state); SHIM_SET_MAPPING("xboxkrnl.exe", XexGetProcedureAddress, state); - - SHIM_SET_MAPPING("xboxkrnl.exe", ExRegisterTitleTerminateNotification, state); }