diff --git a/src/xenia/kernel/objects/sources.gypi b/src/xenia/kernel/objects/sources.gypi index 9e74823fe..817691d04 100644 --- a/src/xenia/kernel/objects/sources.gypi +++ b/src/xenia/kernel/objects/sources.gypi @@ -7,6 +7,8 @@ 'xfile.h', 'xmodule.cc', 'xmodule.h', + 'xmutant.cc', + 'xmutant.h', 'xnotify_listener.cc', 'xnotify_listener.h', 'xsemaphore.cc', diff --git a/src/xenia/kernel/objects/xmutant.cc b/src/xenia/kernel/objects/xmutant.cc new file mode 100644 index 000000000..02ff6f27b --- /dev/null +++ b/src/xenia/kernel/objects/xmutant.cc @@ -0,0 +1,51 @@ +/** + ****************************************************************************** + * 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 + + +using namespace xe; +using namespace xe::kernel; + + +XMutant::XMutant(KernelState* kernel_state) : + XObject(kernel_state, kTypeMutant), + handle_(NULL) { +} + +XMutant::~XMutant() { + if (handle_) { + CloseHandle(handle_); + } +} + +void XMutant::Initialize(bool initial_owner) { + XEASSERTNULL(handle_); + + handle_ = CreateMutex(NULL, initial_owner ? TRUE : FALSE, NULL); +} + +void XMutant::InitializeNative(void* native_ptr, DISPATCH_HEADER& header) { + XEASSERTNULL(handle_); + + // Haven't seen this yet, but it's possible. + XEASSERTALWAYS(); +} + +X_STATUS XMutant::ReleaseMutant( + uint32_t priority_increment, bool abandon, bool wait) { + // TODO(benvanik): abandoning. + XEASSERTFALSE(abandon); + BOOL result = ReleaseMutex(handle_); + if (result) { + return X_STATUS_SUCCESS; + } else { + return X_STATUS_MUTANT_NOT_OWNED; + } +} diff --git a/src/xenia/kernel/objects/xmutant.h b/src/xenia/kernel/objects/xmutant.h new file mode 100644 index 000000000..f66a95572 --- /dev/null +++ b/src/xenia/kernel/objects/xmutant.h @@ -0,0 +1,43 @@ +/** + ****************************************************************************** + * 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. * + ****************************************************************************** + */ + +#ifndef XENIA_KERNEL_XBOXKRNL_XMUTANT_H_ +#define XENIA_KERNEL_XBOXKRNL_XMUTANT_H_ + +#include + +#include + + +namespace xe { +namespace kernel { + + +class XMutant : public XObject { +public: + XMutant(KernelState* kernel_state); + virtual ~XMutant(); + + void Initialize(bool initial_owner); + void InitializeNative(void* native_ptr, DISPATCH_HEADER& header); + + X_STATUS ReleaseMutant(uint32_t priority_increment, bool abandon, bool wait); + + virtual void* GetWaitHandle() { return handle_; } + +private: + HANDLE handle_; +}; + + +} // namespace kernel +} // namespace xe + + +#endif // XENIA_KERNEL_XBOXKRNL_XMUTANT_H_ diff --git a/src/xenia/kernel/xboxkrnl_threading.cc b/src/xenia/kernel/xboxkrnl_threading.cc index 74746df21..fbc933e82 100644 --- a/src/xenia/kernel/xboxkrnl_threading.cc +++ b/src/xenia/kernel/xboxkrnl_threading.cc @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -885,6 +886,65 @@ SHIM_CALL NtReleaseSemaphore_shim( } +SHIM_CALL NtCreateMutant_shim( + PPCContext* ppc_state, KernelState* state) { + uint32_t handle_ptr = SHIM_GET_ARG_32(0); + uint32_t obj_attributes_ptr = SHIM_GET_ARG_32(1); + uint32_t initial_owner = SHIM_GET_ARG_32(2); + + XELOGD( + "NtCreateMutant(%.8X, %.8X, %.1X)", + handle_ptr, obj_attributes_ptr, initial_owner); + + XMutant* mutant = new XMutant(state); + mutant->Initialize(initial_owner ? true : false); + + // obj_attributes may have a name inside of it, if != NULL. + if (obj_attributes_ptr) { + //mutant->SetName(...); + } + + if (handle_ptr) { + SHIM_SET_MEM_32(handle_ptr, mutant->handle()); + } + + SHIM_SET_RETURN(X_STATUS_SUCCESS); +} + + +SHIM_CALL NtReleaseMutant_shim( + PPCContext* ppc_state, KernelState* state) { + uint32_t mutant_handle = SHIM_GET_ARG_32(0); + int32_t unknown = SHIM_GET_ARG_32(1); + // This doesn't seem to be supported. + //int32_t previous_count_ptr = SHIM_GET_ARG_32(2); + + // Whatever arg 1 is all games seem to set it to 0, so whether it's + // abandon or wait we just say false. Which is good, cause they are + // both ignored. + XEASSERTZERO(unknown); + uint32_t priority_increment = 0; + bool abandon = false; + bool wait = false; + + XELOGD( + "NtReleaseMutant(%.8X, %8.X)", + mutant_handle, unknown); + + X_STATUS result = X_STATUS_SUCCESS; + + XMutant* mutant = NULL; + result = state->object_table()->GetObject( + mutant_handle, (XObject**)&mutant); + if (XSUCCEEDED(result)) { + result = mutant->ReleaseMutant(priority_increment, abandon, wait); + mutant->Release(); + } + + SHIM_SET_RETURN(result); +} + + X_STATUS xeKeWaitForSingleObject( void* object_ptr, uint32_t wait_reason, uint32_t processor_mode, uint32_t alertable, uint64_t* opt_timeout) { @@ -1145,6 +1205,9 @@ void xe::kernel::xboxkrnl::RegisterThreadingExports( SHIM_SET_MAPPING("xboxkrnl.exe", KeReleaseSemaphore, state); SHIM_SET_MAPPING("xboxkrnl.exe", NtReleaseSemaphore, state); + SHIM_SET_MAPPING("xboxkrnl.exe", NtCreateMutant, state); + SHIM_SET_MAPPING("xboxkrnl.exe", NtReleaseMutant, state); + SHIM_SET_MAPPING("xboxkrnl.exe", KeWaitForSingleObject, state); SHIM_SET_MAPPING("xboxkrnl.exe", NtWaitForSingleObjectEx, state); SHIM_SET_MAPPING("xboxkrnl.exe", KeWaitForMultipleObjects, state); diff --git a/src/xenia/kernel/xobject.cc b/src/xenia/kernel/xobject.cc index 2c1498579..fa7a451b0 100644 --- a/src/xenia/kernel/xobject.cc +++ b/src/xenia/kernel/xobject.cc @@ -11,6 +11,7 @@ #include #include +#include #include @@ -225,6 +226,13 @@ XObject* XObject::GetObject(KernelState* kernel_state, void* native_ptr, object = ev; } break; + case 2: // MutantObjectt + { + XMutant* mutant = new XMutant(kernel_state); + mutant->InitializeNative(native_ptr, header); + object = mutant; + } + break; case 5: // SemaphoreObject { XSemaphore* sem = new XSemaphore(kernel_state); @@ -232,7 +240,6 @@ XObject* XObject::GetObject(KernelState* kernel_state, void* native_ptr, object = sem; } break; - case 2: // MutantObject case 3: // ProcessObject case 4: // QueueObject case 6: // ThreadObject diff --git a/src/xenia/kernel/xobject.h b/src/xenia/kernel/xobject.h index 7f0d2dea0..a93c78ed3 100644 --- a/src/xenia/kernel/xobject.h +++ b/src/xenia/kernel/xobject.h @@ -37,6 +37,7 @@ public: kTypeFile, kTypeSemaphore, kTypeNotifyListener, + kTypeMutant, }; XObject(KernelState* kernel_state, Type type); diff --git a/src/xenia/xbox.h b/src/xenia/xbox.h index 01620d04e..2f164adb7 100644 --- a/src/xenia/xbox.h +++ b/src/xenia/xbox.h @@ -45,6 +45,7 @@ typedef uint32_t X_STATUS; #define X_STATUS_BUFFER_TOO_SMALL ((uint32_t)0xC0000023L) #define X_STATUS_OBJECT_TYPE_MISMATCH ((uint32_t)0xC0000024L) #define X_STATUS_INVALID_PAGE_PROTECTION ((uint32_t)0xC0000045L) +#define X_STATUS_MUTANT_NOT_OWNED ((uint32_t)0xC0000046L) #define X_STATUS_MEMORY_NOT_ALLOCATED ((uint32_t)0xC00000A0L) #define X_STATUS_INVALID_PARAMETER_1 ((uint32_t)0xC00000EFL) #define X_STATUS_INVALID_PARAMETER_2 ((uint32_t)0xC00000F0L)