/** ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** * Copyright 2013 Ben Vanik. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ #include #include #include #include #include #include #include #include #include #include #include #include #include namespace xe { namespace kernel { // This is a global object initialized with the XboxkrnlModule. // It references the current kernel state object that all kernel methods should // be using to stash their variables. KernelState* shared_kernel_state_ = nullptr; KernelState::KernelState(Emulator* emulator) : emulator_(emulator), memory_(emulator->memory()), executable_module_(NULL) { processor_ = emulator->processor(); file_system_ = emulator->file_system(); dispatcher_ = new Dispatcher(this); app_manager_ = std::make_unique(); user_profile_ = std::make_unique(); object_table_ = new ObjectTable(); assert_null(shared_kernel_state_); shared_kernel_state_ = this; apps::RegisterApps(this, app_manager_.get()); } KernelState::~KernelState() { SetExecutableModule(NULL); // Delete all objects. delete object_table_; // Shutdown apps. app_manager_.reset(); delete dispatcher_; assert_true(shared_kernel_state_ == this); shared_kernel_state_ = NULL; } KernelState* KernelState::shared() { return shared_kernel_state_; } void KernelState::RegisterModule(XModule* module) {} void KernelState::UnregisterModule(XModule* module) {} XModule* KernelState::GetModule(const char* name) { if (!name) { // NULL name = self. // TODO(benvanik): lookup module from caller address. return GetExecutableModule(); } else if (strcasecmp(name, "xam.xex") == 0) { auto module = emulator_->xam(); module->Retain(); return module; } else if (strcasecmp(name, "xboxkrnl.exe") == 0) { auto module = emulator_->xboxkrnl(); module->Retain(); return module; } else if (strcasecmp(name, "kernel32.dll") == 0) { // Some games request this, for some reason. wtf. return NULL; } else { // TODO(benvanik): support user modules/loading/etc. assert_always(); return NULL; } } XUserModule* KernelState::GetExecutableModule() { if (!executable_module_) { return NULL; } executable_module_->Retain(); return executable_module_; } void KernelState::SetExecutableModule(XUserModule* module) { if (module == executable_module_) { return; } if (executable_module_) { executable_module_->Release(); } executable_module_ = module; if (executable_module_) { executable_module_->Retain(); } } void KernelState::RegisterThread(XThread* thread) { std::lock_guard lock(object_mutex_); threads_by_id_[thread->thread_id()] = thread; } void KernelState::UnregisterThread(XThread* thread) { std::lock_guard lock(object_mutex_); auto it = threads_by_id_.find(thread->thread_id()); if (it != threads_by_id_.end()) { threads_by_id_.erase(it); } } XThread* KernelState::GetThreadByID(uint32_t thread_id) { std::lock_guard lock(object_mutex_); XThread* thread = NULL; auto it = threads_by_id_.find(thread_id); if (it != threads_by_id_.end()) { thread = it->second; // Caller must release. thread->Retain(); } return thread; } void KernelState::RegisterNotifyListener(XNotifyListener* listener) { std::lock_guard lock(object_mutex_); notify_listeners_.push_back(listener); } void KernelState::UnregisterNotifyListener(XNotifyListener* listener) { std::lock_guard lock(object_mutex_); for (auto it = notify_listeners_.begin(); it != notify_listeners_.end(); ++it) { if (*it == listener) { notify_listeners_.erase(it); break; } } } void KernelState::BroadcastNotification(XNotificationID id, uint32_t data) { std::lock_guard lock(object_mutex_); for (auto it = notify_listeners_.begin(); it != notify_listeners_.end(); ++it) { (*it)->EnqueueNotification(id, data); } } void KernelState::CompleteOverlapped(uint32_t overlapped_ptr, X_RESULT result, uint32_t length) { auto ptr = memory()->membase() + overlapped_ptr; XOverlappedSetResult(ptr, result); XOverlappedSetLength(ptr, length); XOverlappedSetExtendedError(ptr, result); X_HANDLE event_handle = XOverlappedGetEvent(ptr); if (event_handle) { XEvent* ev = nullptr; if (XSUCCEEDED(object_table()->GetObject( event_handle, reinterpret_cast(&ev)))) { ev->Set(0, false); ev->Release(); } } if (XOverlappedGetCompletionRoutine(ptr)) { assert_always(); X_HANDLE thread_handle = XOverlappedGetContext(ptr); XThread* thread = nullptr; if (XSUCCEEDED(object_table()->GetObject( thread_handle, reinterpret_cast(&thread)))) { // TODO(benvanik): queue APC on the thread that requested the overlapped operation. thread->Release(); } } } void KernelState::CompleteOverlappedImmediate(uint32_t overlapped_ptr, X_RESULT result, uint32_t length) { auto ptr = memory()->membase() + overlapped_ptr; XOverlappedSetContext(ptr, XThread::GetCurrentThreadHandle()); CompleteOverlapped(overlapped_ptr, result, length); } } // namespace kernel } // namespace xe