From 1807da06db181c17c657a09a6614b6fa1a913e29 Mon Sep 17 00:00:00 2001 From: Adrian <78108584+AdrianCassar@users.noreply.github.com> Date: Tue, 28 Jul 2026 21:35:07 +0100 Subject: [PATCH] [Kernel] Added usage of X_DISPATCHER_FLAGS --- src/xenia/kernel/xam/xam_content.cc | 4 +- .../kernel/xboxkrnl/xboxkrnl_threading.cc | 70 +++++++++++-------- src/xenia/kernel/xevent.cc | 9 +-- src/xenia/kernel/xevent.h | 2 +- src/xenia/kernel/xmutant.cc | 3 +- src/xenia/kernel/xmutant.h | 2 +- src/xenia/kernel/xobject.cc | 36 +++++----- src/xenia/kernel/xobject.h | 54 +++++++------- src/xenia/kernel/xsemaphore.cc | 3 +- src/xenia/kernel/xsemaphore.h | 2 +- 10 files changed, 102 insertions(+), 83 deletions(-) diff --git a/src/xenia/kernel/xam/xam_content.cc b/src/xenia/kernel/xam/xam_content.cc index d8a6d696a..d0607a99c 100644 --- a/src/xenia/kernel/xam/xam_content.cc +++ b/src/xenia/kernel/xam/xam_content.cc @@ -700,8 +700,8 @@ dword_result_t XamSwapDisc_entry( auto kevent = xboxkrnl::xeKeSetEvent(completion_handle, 1, 0); // Release the completion handle - auto object = - XObject::GetNativeObject(kernel_state(), completion_handle); + auto object = XObject::GetNativeObject( + kernel_state(), completion_handle, completion_handle->header.type); if (object) { object->Retain(); } diff --git a/src/xenia/kernel/xboxkrnl/xboxkrnl_threading.cc b/src/xenia/kernel/xboxkrnl/xboxkrnl_threading.cc index e63a28db7..73340102b 100644 --- a/src/xenia/kernel/xboxkrnl/xboxkrnl_threading.cc +++ b/src/xenia/kernel/xboxkrnl/xboxkrnl_threading.cc @@ -250,7 +250,8 @@ DECLARE_XBOXKRNL_EXPORT1(NtResumeThread, kThreading, kImplemented); dword_result_t KeResumeThread_entry(pointer_t thread_ptr) { X_STATUS result = X_STATUS_SUCCESS; - auto thread = XObject::GetNativeObject(kernel_state(), thread_ptr); + auto thread = XObject::GetNativeObject(kernel_state(), thread_ptr, + DISPATCHER_THREAD); if (thread) { result = thread->Resume(); } else { @@ -314,8 +315,8 @@ DECLARE_XBOXKRNL_EXPORT1(NtSuspendThread, kThreading, kImplemented); dword_result_t KeSuspendThread_entry(pointer_t kthread, const ppc_context_t& context) { - auto thread = - XObject::GetNativeObject(context->kernel_state, kthread); + auto thread = XObject::GetNativeObject(context->kernel_state, + kthread, DISPATCHER_THREAD); uint32_t suspend_count_out = 0; if (thread) { @@ -356,7 +357,8 @@ void KeSetCurrentStackPointers_entry(lpvoid_t stack_ptr, DECLARE_XBOXKRNL_EXPORT2(KeSetCurrentStackPointers, kThreading, kImplemented, kHighFrequency); -dword_result_t KeSetAffinityThread_entry(lpvoid_t thread_ptr, dword_t affinity, +dword_result_t KeSetAffinityThread_entry(pointer_t thread_ptr, + dword_t affinity, lpdword_t previous_affinity_ptr) { // The Xbox 360, according to disassembly of KeSetAffinityThread, unlike // Windows NT, stores the previous affinity via the pointer provided as an @@ -365,7 +367,8 @@ dword_result_t KeSetAffinityThread_entry(lpvoid_t thread_ptr, dword_t affinity, if (!affinity) { return X_STATUS_INVALID_PARAMETER; } - auto thread = XObject::GetNativeObject(kernel_state(), thread_ptr); + auto thread = XObject::GetNativeObject(kernel_state(), thread_ptr, + DISPATCHER_THREAD); if (!thread) { XELOGW( "KeSetAffinityThread: guest thread pointer {:08X} did not resolve to " @@ -381,10 +384,12 @@ dword_result_t KeSetAffinityThread_entry(lpvoid_t thread_ptr, dword_t affinity, } DECLARE_XBOXKRNL_EXPORT1(KeSetAffinityThread, kThreading, kImplemented); -dword_result_t KeQueryBasePriorityThread_entry(lpvoid_t thread_ptr) { +dword_result_t KeQueryBasePriorityThread_entry( + pointer_t thread_ptr) { int32_t priority = 0; - auto thread = XObject::GetNativeObject(kernel_state(), thread_ptr); + auto thread = XObject::GetNativeObject(kernel_state(), thread_ptr, + DISPATCHER_THREAD); if (thread) { priority = thread->QueryPriority(); } @@ -393,10 +398,11 @@ dword_result_t KeQueryBasePriorityThread_entry(lpvoid_t thread_ptr) { } DECLARE_XBOXKRNL_EXPORT1(KeQueryBasePriorityThread, kThreading, kImplemented); -dword_result_t KeSetBasePriorityThread_entry(lpvoid_t thread_ptr, +dword_result_t KeSetBasePriorityThread_entry(pointer_t thread_ptr, dword_t increment) { int32_t prev_priority = 0; - auto thread = XObject::GetNativeObject(kernel_state(), thread_ptr); + auto thread = XObject::GetNativeObject(kernel_state(), thread_ptr, + DISPATCHER_THREAD); if (thread) { prev_priority = thread->QueryPriority(); @@ -559,10 +565,10 @@ DECLARE_XBOXKRNL_EXPORT1(KeTlsSetValue, kThreading, kImplemented); void KeInitializeEvent_entry(pointer_t event_ptr, dword_t event_type, dword_t initial_state) { event_ptr.Zero(); - event_ptr->header.type = event_type; - event_ptr->header.signal_state = (uint32_t)initial_state; - auto ev = - XObject::GetNativeObject(kernel_state(), event_ptr, event_type); + event_ptr->header.type = static_cast(event_type.value()); + event_ptr->header.signal_state = initial_state.value(); + auto ev = XObject::GetNativeObject(kernel_state(), event_ptr, + event_ptr->header.type); if (!ev) { assert_always(); return; @@ -571,7 +577,8 @@ void KeInitializeEvent_entry(pointer_t event_ptr, dword_t event_type, DECLARE_XBOXKRNL_EXPORT1(KeInitializeEvent, kThreading, kImplemented); uint32_t xeKeSetEvent(X_KEVENT* event_ptr, uint32_t increment, uint32_t wait) { - auto ev = XObject::GetNativeObject(kernel_state(), event_ptr); + auto ev = XObject::GetNativeObject(kernel_state(), event_ptr, + event_ptr->header.type); if (!ev) { assert_always(); return 0; @@ -588,7 +595,8 @@ DECLARE_XBOXKRNL_EXPORT2(KeSetEvent, kThreading, kImplemented, kHighFrequency); dword_result_t KePulseEvent_entry(pointer_t event_ptr, dword_t increment, dword_t wait) { - auto ev = XObject::GetNativeObject(kernel_state(), event_ptr); + auto ev = XObject::GetNativeObject(kernel_state(), event_ptr, + event_ptr->header.type); if (!ev) { assert_always(); return 0; @@ -600,7 +608,8 @@ DECLARE_XBOXKRNL_EXPORT2(KePulseEvent, kThreading, kImplemented, kHighFrequency); dword_result_t KeResetEvent_entry(pointer_t event_ptr) { - auto ev = XObject::GetNativeObject(kernel_state(), event_ptr); + auto ev = XObject::GetNativeObject(kernel_state(), event_ptr, + event_ptr->header.type); if (!ev) { assert_always(); return 0; @@ -727,12 +736,12 @@ DECLARE_XBOXKRNL_EXPORT2(NtClearEvent, kThreading, kImplemented, // https://msdn.microsoft.com/en-us/library/windows/hardware/ff552150(v=vs.85).aspx void KeInitializeSemaphore_entry(pointer_t semaphore_ptr, dword_t count, dword_t limit) { - semaphore_ptr->header.type = X_DISPATCHER_FLAGS::DISPATCHER_SEMAPHORE; + semaphore_ptr->header.type = DISPATCHER_SEMAPHORE; semaphore_ptr->header.signal_state = (uint32_t)count; semaphore_ptr->limit = (uint32_t)limit; - auto sem = XObject::GetNativeObject( - kernel_state(), semaphore_ptr, X_DISPATCHER_FLAGS::DISPATCHER_SEMAPHORE); + auto sem = XObject::GetNativeObject(kernel_state(), semaphore_ptr, + DISPATCHER_SEMAPHORE); if (!sem) { assert_always(); return; @@ -742,8 +751,8 @@ DECLARE_XBOXKRNL_EXPORT1(KeInitializeSemaphore, kThreading, kImplemented); uint32_t xeKeReleaseSemaphore(X_KSEMAPHORE* semaphore_ptr, uint32_t increment, uint32_t adjustment, uint32_t wait) { - auto sem = - XObject::GetNativeObject(kernel_state(), semaphore_ptr); + auto sem = XObject::GetNativeObject(kernel_state(), semaphore_ptr, + DISPATCHER_SEMAPHORE); if (!sem) { assert_always(); return 0; @@ -1057,8 +1066,8 @@ dword_result_t KeWaitForMultipleObjects_entry( auto crit = global_critical_region::AcquireDirect(); for (uint32_t n = 0; n < count; n++) { auto object_ptr = kernel_memory()->TranslateVirtual(objects_ptr[n]); - auto object_ref = XObject::GetNativeObject(kernel_state(), - object_ptr, -1, true); + auto object_ref = XObject::GetNativeObject( + kernel_state(), object_ptr, DISPATCHER_UNDEFINED, true); if (!object_ref) { return X_STATUS_INVALID_PARAMETER; } @@ -1907,19 +1916,21 @@ dword_result_t KeSetPriorityThread_entry(pointer_t thread_ptr, return 0; } - if (thread_ptr->header.type != X_DISPATCHER_FLAGS::DISPATCHER_THREAD) { - XELOGW("{}: Invalid object type: {}", __func__, thread_ptr->header.type); + if (thread_ptr->header.type != DISPATCHER_THREAD) { + XELOGW("{}: Invalid object type: {}", __func__, + static_cast(thread_ptr->header.type)); } X_KPRCB* prcb = context->TranslateVirtual(thread_ptr->a_prcb_ptr); const uint32_t old_irql = xeKeKfAcquireSpinLock(context, &prcb->spin_lock); const uint8_t old_priority = thread_ptr->priority; - auto thread_ref = - XObject::GetNativeObject(kernel_state(), thread_ptr); + auto thread_ref = XObject::GetNativeObject( + kernel_state(), thread_ptr, DISPATCHER_THREAD); if (!thread_ref) { - XELOGW("{}: Missing native thread: {}", __func__, thread_ptr->header.type); + XELOGW("{}: Missing native thread: {}", __func__, + static_cast(thread_ptr->header.type)); } else { thread_ref->SetPriority(new_priority); } @@ -1937,7 +1948,8 @@ void xeKeInitializeTimerEx(X_KTIMER* timer, uint32_t type, uint32_t proctype, // initialize timer->header.process_type = proctype; timer->header.inserted = 0; - timer->header.type = type + 8; + timer->header.type = + type ? DISPATCHER_AUTO_RESET_TIMER : DISPATCHER_MANUAL_RESET_TIMER; timer->header.signal_state = 0; util::XeInitializeListHead(&timer->header.wait_list, context); timer->due_time = 0; diff --git a/src/xenia/kernel/xevent.cc b/src/xenia/kernel/xevent.cc index b583bf732..a2a76cad9 100644 --- a/src/xenia/kernel/xevent.cc +++ b/src/xenia/kernel/xevent.cc @@ -23,7 +23,7 @@ XEvent::~XEvent() = default; void XEvent::Initialize(bool manual_reset, bool initial_state) { assert_false(event_); - this->CreateNative(); + CreateNative(); if (manual_reset) { event_ = xe::threading::Event::CreateManualResetEvent(initial_state); @@ -33,14 +33,15 @@ void XEvent::Initialize(bool manual_reset, bool initial_state) { assert_not_null(event_); } -void XEvent::InitializeNative(void* native_ptr, X_DISPATCH_HEADER* header) { +void XEvent::InitializeNative(void* native_ptr, + const X_DISPATCH_HEADER* header) { assert_false(event_); switch (header->type) { - case 0x00: // EventNotificationObject (manual reset) + case X_DISPATCHER_FLAGS::DISPATCHER_MANUAL_RESET_EVENT: manual_reset_ = true; break; - case 0x01: // EventSynchronizationObject (auto reset) + case X_DISPATCHER_FLAGS::DISPATCHER_AUTO_RESET_EVENT: manual_reset_ = false; break; default: diff --git a/src/xenia/kernel/xevent.h b/src/xenia/kernel/xevent.h index 4fd174cd0..87272531b 100644 --- a/src/xenia/kernel/xevent.h +++ b/src/xenia/kernel/xevent.h @@ -31,7 +31,7 @@ class XEvent : public XObject { ~XEvent() override; void Initialize(bool manual_reset, bool initial_state); - void InitializeNative(void* native_ptr, X_DISPATCH_HEADER* header); + void InitializeNative(void* native_ptr, const X_DISPATCH_HEADER* header); int32_t Set(uint32_t priority_increment, bool wait); int32_t Pulse(uint32_t priority_increment, bool wait); diff --git a/src/xenia/kernel/xmutant.cc b/src/xenia/kernel/xmutant.cc index 42da93d67..ba2dc861c 100644 --- a/src/xenia/kernel/xmutant.cc +++ b/src/xenia/kernel/xmutant.cc @@ -31,7 +31,8 @@ void XMutant::Initialize(bool initial_owner) { assert_not_null(mutant_); } -void XMutant::InitializeNative(void* native_ptr, X_DISPATCH_HEADER* header) { +void XMutant::InitializeNative(void* native_ptr, + const X_DISPATCH_HEADER* header) { assert_false(mutant_); // Haven't seen this yet, but it's possible. diff --git a/src/xenia/kernel/xmutant.h b/src/xenia/kernel/xmutant.h index 93d557f4c..b283df5b1 100644 --- a/src/xenia/kernel/xmutant.h +++ b/src/xenia/kernel/xmutant.h @@ -28,7 +28,7 @@ class XMutant : public XObject { ~XMutant() override; void Initialize(bool initial_owner); - void InitializeNative(void* native_ptr, X_DISPATCH_HEADER* header); + void InitializeNative(void* native_ptr, const X_DISPATCH_HEADER* header); X_STATUS ReleaseMutant(uint32_t priority_increment, bool abandon, bool wait); diff --git a/src/xenia/kernel/xobject.cc b/src/xenia/kernel/xobject.cc index 3c501509c..5ae9a60c0 100644 --- a/src/xenia/kernel/xobject.cc +++ b/src/xenia/kernel/xobject.cc @@ -395,7 +395,8 @@ void XObject::SetNativePointer(uint32_t native_ptr, bool uninitialized) { } object_ref XObject::GetNativeObject(KernelState* kernel_state, - void* native_ptr, int32_t as_type, + void* native_ptr, + X_DISPATCHER_FLAGS as_type, bool already_locked) { assert_not_null(native_ptr); @@ -411,11 +412,13 @@ object_ref XObject::GetNativeObject(KernelState* kernel_state, global_critical_region::mutex().lock(); } - XObject* result; + XObject* result = nullptr; auto header = reinterpret_cast(native_ptr); - if (as_type == -1) { - as_type = header->type; + X_DISPATCHER_FLAGS type = X_DISPATCHER_FLAGS::DISPATCHER_UNDEFINED; + + if (as_type == X_DISPATCHER_FLAGS::DISPATCHER_UNDEFINED) { + type = header->type; } if (header->wait_list.flink_ptr == kXObjSignature) { @@ -428,28 +431,24 @@ object_ref XObject::GetNativeObject(KernelState* kernel_state, } else { // First use, create new. // https://www.nirsoft.net/kernel_struct/vista/KOBJECTS.html - XObject* object = nullptr; - switch (as_type) { - case 0: // EventNotificationObject - case 1: // EventSynchronizationObject - { + switch (type) { + case X_DISPATCHER_FLAGS::DISPATCHER_MANUAL_RESET_EVENT: + case X_DISPATCHER_FLAGS::DISPATCHER_AUTO_RESET_EVENT: { auto ev = new XEvent(kernel_state); ev->InitializeNative(native_ptr, header); - object = ev; + result = ev; } break; - case 2: // MutantObject - { + case X_DISPATCHER_FLAGS::DISPATCHER_MUTANT: { auto mutant = new XMutant(kernel_state); mutant->InitializeNative(native_ptr, header); - object = mutant; + result = mutant; } break; - case 5: // SemaphoreObject - { + case X_DISPATCHER_FLAGS::DISPATCHER_SEMAPHORE: { auto sem = new XSemaphore(kernel_state); auto success = sem->InitializeNative(native_ptr, header); // Can't report failure to the guest at late initialization: assert_true(success); - object = sem; + result = sem; } break; case 3: // ProcessObject case 4: // QueueObject @@ -470,10 +469,9 @@ object_ref XObject::GetNativeObject(KernelState* kernel_state, } // Stash pointer in struct. // FIXME: This assumes the object contains a dispatch header (some don't!) - if (object) { - StashHandle(header, object->handle()); + if (result) { + StashHandle(header, result->handle()); } - result = object; } if (!already_locked) { diff --git a/src/xenia/kernel/xobject.h b/src/xenia/kernel/xobject.h index 9d9e0ba0f..6524d0991 100644 --- a/src/xenia/kernel/xobject.h +++ b/src/xenia/kernel/xobject.h @@ -35,20 +35,21 @@ template class object_ref; enum X_DISPATCHER_FLAGS : uint8_t { - DISPATCHER_MANUAL_RESET_EVENT = 0, - DISPATCHER_AUTO_RESET_EVENT = 1, // EventSynchronizationObject - DISPATCHER_MUTANT = 2, + DISPATCHER_MANUAL_RESET_EVENT = 0, // EventNotificationObject + DISPATCHER_AUTO_RESET_EVENT = 1, // EventSynchronizationObject + DISPATCHER_MUTANT = 2, // MutantObject DISPATCHER_QUEUE = 4, DISPATCHER_SEMAPHORE = 5, // SemaphoreObject DISPATCHER_THREAD = 6, DISPATCHER_MANUAL_RESET_TIMER = 8, DISPATCHER_AUTO_RESET_TIMER = 9, + DISPATCHER_UNDEFINED = 0xFF, }; // https://www.nirsoft.net/kernel_struct/vista/DISPATCHER_HEADER.html typedef struct { struct { - uint8_t type; // X_DISPATCHER_FLAGS + X_DISPATCHER_FLAGS type; union { uint8_t abandoned; @@ -149,27 +150,30 @@ class XObject { default: return false; } - return false; } - static Type MapGuestTypeToHost(uint16_t type) { - // todo: this is not fully filled in - switch (type) { - case 0: - case 1: + static Type MapGuestTypeToHost(X_DISPATCHER_FLAGS flag) { + // TODO: This is not fully filled in. + switch (flag) { + case X_DISPATCHER_FLAGS::DISPATCHER_MANUAL_RESET_EVENT: + case X_DISPATCHER_FLAGS::DISPATCHER_AUTO_RESET_EVENT: return Type::Event; - case 2: return Type::Mutant; - case 5: + case X_DISPATCHER_FLAGS::DISPATCHER_MUTANT: + return Type::Mutant; + case X_DISPATCHER_FLAGS::DISPATCHER_SEMAPHORE: return Type::Semaphore; - case 6: + case X_DISPATCHER_FLAGS::DISPATCHER_THREAD: return Type::Thread; - case 8: - case 9: + case X_DISPATCHER_FLAGS::DISPATCHER_MANUAL_RESET_TIMER: + case X_DISPATCHER_FLAGS::DISPATCHER_AUTO_RESET_TIMER: return Type::Timer; + default: + return Type::Undefined; + // assert_always(); } - return Type::Undefined; } + XObject(Type type); XObject(KernelState* kernel_state, Type type, bool host_object = false); virtual ~XObject(); @@ -228,14 +232,15 @@ class XObject { uint32_t processor_mode, uint32_t alertable, uint64_t* opt_timeout); - static object_ref GetNativeObject(KernelState* kernel_state, - void* native_ptr, - int32_t as_type = -1, - bool already_locked = false); + static object_ref GetNativeObject( + KernelState* kernel_state, void* native_ptr, + X_DISPATCHER_FLAGS as_type = DISPATCHER_UNDEFINED, + bool already_locked = false); template - static object_ref GetNativeObject(KernelState* kernel_state, - void* native_ptr, int32_t as_type = -1, - bool already_locked = false); + static object_ref GetNativeObject( + KernelState* kernel_state, void* native_ptr, + X_DISPATCHER_FLAGS as_type = DISPATCHER_UNDEFINED, + bool already_locked = false); // Priority increment stored by the most recent signal operation // (KeSetEvent, KeReleaseSemaphore, etc.). Read by the waiter on wake @@ -418,7 +423,8 @@ object_ref retain_object(T* ptr) { template object_ref XObject::GetNativeObject(KernelState* kernel_state, - void* native_ptr, int32_t as_type, + void* native_ptr, + X_DISPATCHER_FLAGS as_type, bool already_locked) { return object_ref(reinterpret_cast( GetNativeObject(kernel_state, native_ptr, as_type, already_locked) diff --git a/src/xenia/kernel/xsemaphore.cc b/src/xenia/kernel/xsemaphore.cc index f04d0826e..0ad532389 100644 --- a/src/xenia/kernel/xsemaphore.cc +++ b/src/xenia/kernel/xsemaphore.cc @@ -30,7 +30,8 @@ bool XSemaphore::Initialize(int32_t initial_count, int32_t maximum_count) { return !!semaphore_; } -bool XSemaphore::InitializeNative(void* native_ptr, X_DISPATCH_HEADER* header) { +bool XSemaphore::InitializeNative(void* native_ptr, + const X_DISPATCH_HEADER* header) { assert_false(semaphore_); auto semaphore = reinterpret_cast(native_ptr); diff --git a/src/xenia/kernel/xsemaphore.h b/src/xenia/kernel/xsemaphore.h index 2135fdec3..898e4f28b 100644 --- a/src/xenia/kernel/xsemaphore.h +++ b/src/xenia/kernel/xsemaphore.h @@ -27,7 +27,7 @@ class XSemaphore : public XObject { [[nodiscard]] bool Initialize(int32_t initial_count, int32_t maximum_count); [[nodiscard]] bool InitializeNative(void* native_ptr, - X_DISPATCH_HEADER* header); + const X_DISPATCH_HEADER* header); [[nodiscard]] bool ReleaseSemaphore(int32_t release_count, int32_t* out_previous_count);