diff --git a/src/xenia/kernel/objects/sources.gypi b/src/xenia/kernel/objects/sources.gypi index 817691d04..419534dc4 100644 --- a/src/xenia/kernel/objects/sources.gypi +++ b/src/xenia/kernel/objects/sources.gypi @@ -15,5 +15,7 @@ 'xsemaphore.h', 'xthread.cc', 'xthread.h', + 'xtimer.cc', + 'xtimer.h', ], } diff --git a/src/xenia/kernel/objects/xtimer.cc b/src/xenia/kernel/objects/xtimer.cc new file mode 100644 index 000000000..988fe6d6d --- /dev/null +++ b/src/xenia/kernel/objects/xtimer.cc @@ -0,0 +1,60 @@ +/** + ****************************************************************************** + * 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; + + +XTimer::XTimer(KernelState* kernel_state) : + XObject(kernel_state, kTypeTimer), + handle_(NULL) { +} + +XTimer::~XTimer() { + if (handle_) { + CloseHandle(handle_); + } +} + +void XTimer::Initialize(uint32_t timer_type) { + XEASSERTNULL(handle_); + + bool manual_reset = false; + switch (timer_type) { + case 0: // NotificationTimer + manual_reset = true; + break; + case 1: // SynchronizationTimer + manual_reset = false; + break; + default: + XEASSERTALWAYS(); + break; + } + + handle_ = CreateWaitableTimer(NULL, manual_reset, NULL); +} + +X_STATUS XTimer::SetTimer(int64_t due_time, uint32_t period_ms) { + LARGE_INTEGER due_time_li; + due_time_li.QuadPart = due_time; + if (SetWaitableTimer(handle_, &due_time_li, period_ms, NULL, NULL, TRUE)) { + return X_STATUS_SUCCESS; + } else { + return X_STATUS_UNSUCCESSFUL; + } +} + +X_STATUS XTimer::Cancel() { + return CancelWaitableTimer(handle_) == 0 ? + X_STATUS_SUCCESS : X_STATUS_UNSUCCESSFUL; +} diff --git a/src/xenia/kernel/objects/xtimer.h b/src/xenia/kernel/objects/xtimer.h new file mode 100644 index 000000000..d25774b22 --- /dev/null +++ b/src/xenia/kernel/objects/xtimer.h @@ -0,0 +1,44 @@ +/** + ****************************************************************************** + * 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_XTIMER_H_ +#define XENIA_KERNEL_XBOXKRNL_XTIMER_H_ + +#include + +#include + + +namespace xe { +namespace kernel { + + +class XTimer : public XObject { +public: + XTimer(KernelState* kernel_state); + virtual ~XTimer(); + + void Initialize(uint32_t timer_type); + + // completion routine, arg to completion routine + X_STATUS SetTimer(int64_t due_time, uint32_t period_ms); + X_STATUS Cancel(); + + virtual void* GetWaitHandle() { return handle_; } + +private: + HANDLE handle_; +}; + + +} // namespace kernel +} // namespace xe + + +#endif // XENIA_KERNEL_XBOXKRNL_TIMER_H_ diff --git a/src/xenia/kernel/xboxkrnl_threading.cc b/src/xenia/kernel/xboxkrnl_threading.cc index ed04f79ee..39bf3abba 100644 --- a/src/xenia/kernel/xboxkrnl_threading.cc +++ b/src/xenia/kernel/xboxkrnl_threading.cc @@ -15,6 +15,7 @@ #include #include #include +#include #include @@ -945,6 +946,100 @@ SHIM_CALL NtReleaseMutant_shim( } +SHIM_CALL NtCreateTimer_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 timer_type = SHIM_GET_ARG_32(2); + + // timer_type = NotificationTimer (0) or SynchronizationTimer (1) + + XELOGD( + "NtCreateTimer(%.8X, %.8X, %.1X)", + handle_ptr, obj_attributes_ptr, timer_type); + + XTimer* timer = new XTimer(state); + timer->Initialize(timer_type); + + // obj_attributes may have a name inside of it, if != NULL. + if (obj_attributes_ptr) { + //timer->SetName(...); + } + + if (handle_ptr) { + SHIM_SET_MEM_32(handle_ptr, timer->handle()); + } + + SHIM_SET_RETURN(X_STATUS_SUCCESS); +} + + +SHIM_CALL NtSetTimerEx_shim( + PPCContext* ppc_state, KernelState* state) { + uint32_t timer_handle = SHIM_GET_ARG_32(0); + uint32_t info_class = SHIM_GET_ARG_32(1); + uint32_t info_ptr = SHIM_GET_ARG_32(2); + uint32_t info_length = SHIM_GET_ARG_32(3); + + // UNVERIFIED + XEASSERTALWAYS(); + + XELOGD( + "NtSetTimerEx(%.8X, %.8X, %.8X, %d)", + timer_handle, info_class, info_ptr, info_length); + + // TIMER_BASIC_INFORMATION + XEASSERT(info_class == 0); + XEASSERT(info_length == 12); + + uint64_t due_time = SHIM_MEM_64(info_ptr + 0); + uint32_t timer_state = SHIM_MEM_32(info_ptr + 8); // unused? + uint32_t period_ms = 0; // Not repeating. + + X_STATUS result = X_STATUS_SUCCESS; + + XTimer* timer = NULL; + result = state->object_table()->GetObject( + timer_handle, (XObject**)&timer); + if (XSUCCEEDED(result)) { + result = timer->SetTimer(due_time, period_ms); + timer->Release(); + } + + SHIM_SET_RETURN(result); +} + + +SHIM_CALL NtCancelTimer_shim( + PPCContext* ppc_state, KernelState* state) { + uint32_t timer_handle = SHIM_GET_ARG_32(0); + uint32_t current_state_ptr = SHIM_GET_ARG_32(1); + + // UNVERIFIED + XEASSERTALWAYS(); + + XELOGD( + "NtCancelTimer(%.8X, %.8X)", + timer_handle, current_state_ptr); + + X_STATUS result = X_STATUS_SUCCESS; + + XTimer* timer = NULL; + result = state->object_table()->GetObject( + timer_handle, (XObject**)&timer); + if (XSUCCEEDED(result)) { + result = timer->Cancel(); + timer->Release(); + + if (current_state_ptr) { + SHIM_SET_MEM_32(current_state_ptr, 0); + } + } + + 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) { @@ -1208,6 +1303,10 @@ void xe::kernel::xboxkrnl::RegisterThreadingExports( SHIM_SET_MAPPING("xboxkrnl.exe", NtCreateMutant, state); SHIM_SET_MAPPING("xboxkrnl.exe", NtReleaseMutant, state); + SHIM_SET_MAPPING("xboxkrnl.exe", NtCreateTimer, state); + SHIM_SET_MAPPING("xboxkrnl.exe", NtSetTimerEx, state); + SHIM_SET_MAPPING("xboxkrnl.exe", NtCancelTimer, 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 fa7a451b0..b849fb328 100644 --- a/src/xenia/kernel/xobject.cc +++ b/src/xenia/kernel/xobject.cc @@ -71,8 +71,7 @@ X_STATUS XObject::Delete() { return shared_kernel_state_->object_table()->RemoveHandle(handle_); } -namespace { -uint32_t ConvertTimeoutTicks(int64_t timeout_ticks) { +uint32_t XObject::TimeoutTicksToMs(int64_t timeout_ticks) { if (timeout_ticks > 0) { // Absolute time, based on January 1, 1601. // TODO(benvanik): convert time to relative time. @@ -85,7 +84,6 @@ uint32_t ConvertTimeoutTicks(int64_t timeout_ticks) { return 0; } } -} X_STATUS XObject::Wait(uint32_t wait_reason, uint32_t processor_mode, uint32_t alertable, uint64_t* opt_timeout) { @@ -96,7 +94,7 @@ X_STATUS XObject::Wait(uint32_t wait_reason, uint32_t processor_mode, } DWORD timeout_ms = opt_timeout ? - ConvertTimeoutTicks(*opt_timeout) : INFINITE; + TimeoutTicksToMs(*opt_timeout) : INFINITE; DWORD result = WaitForSingleObjectEx(wait_handle, timeout_ms, alertable); switch (result) { @@ -119,7 +117,7 @@ X_STATUS XObject::SignalAndWait( uint32_t wait_reason, uint32_t processor_mode, uint32_t alertable, uint64_t* opt_timeout) { DWORD timeout_ms = opt_timeout ? - ConvertTimeoutTicks(*opt_timeout) : INFINITE; + TimeoutTicksToMs(*opt_timeout) : INFINITE; DWORD result = SignalObjectAndWait( signal_object->GetWaitHandle(), @@ -141,7 +139,7 @@ X_STATUS XObject::WaitMultiple( } DWORD timeout_ms = opt_timeout ? - ConvertTimeoutTicks(*opt_timeout) : INFINITE; + TimeoutTicksToMs(*opt_timeout) : INFINITE; DWORD result = WaitForMultipleObjectsEx( count, wait_handles, diff --git a/src/xenia/kernel/xobject.h b/src/xenia/kernel/xobject.h index a93c78ed3..1a3b8fae7 100644 --- a/src/xenia/kernel/xobject.h +++ b/src/xenia/kernel/xobject.h @@ -38,6 +38,7 @@ public: kTypeSemaphore, kTypeNotifyListener, kTypeMutant, + kTypeTimer, }; XObject(KernelState* kernel_state, Type type); @@ -81,6 +82,8 @@ protected: Memory* memory() const; void SetNativePointer(uint32_t native_ptr); + static uint32_t TimeoutTicksToMs(int64_t timeout_ticks); + KernelState* kernel_state_; private: