diff --git a/src/xenia/kernel/modules/xboxkrnl/objects/xthread.cc b/src/xenia/kernel/modules/xboxkrnl/objects/xthread.cc index d6b1ef077..2a772a8de 100644 --- a/src/xenia/kernel/modules/xboxkrnl/objects/xthread.cc +++ b/src/xenia/kernel/modules/xboxkrnl/objects/xthread.cc @@ -348,3 +348,29 @@ uint32_t XThread::RaiseIrql(uint32_t new_irql) { void XThread::LowerIrql(uint32_t new_irql) { irql_ = new_irql; } + +X_STATUS XThread::Delay( + uint32_t processor_mode, uint32_t alertable, uint64_t interval) { + int64_t timeout_ticks = interval; + DWORD timeout_ms; + if (timeout_ticks > 0) { + // Absolute time, based on January 1, 1601. + // TODO(benvanik): convert time to relative time. + XEASSERTALWAYS(); + timeout_ms = 0; + } else if (timeout_ticks < 0) { + // Relative time. + timeout_ms = (DWORD)(-timeout_ticks / 10000); // Ticks -> MS + } else { + timeout_ms = 0; + } + DWORD result = SleepEx(timeout_ms, alertable ? TRUE : FALSE); + switch (result) { + case 0: + return X_STATUS_SUCCESS; + case WAIT_IO_COMPLETION: + return X_STATUS_USER_APC; + default: + return X_STATUS_ALERTED; + } +} diff --git a/src/xenia/kernel/modules/xboxkrnl/objects/xthread.h b/src/xenia/kernel/modules/xboxkrnl/objects/xthread.h index c83d4fe51..17359a966 100644 --- a/src/xenia/kernel/modules/xboxkrnl/objects/xthread.h +++ b/src/xenia/kernel/modules/xboxkrnl/objects/xthread.h @@ -61,6 +61,9 @@ public: uint32_t RaiseIrql(uint32_t new_irql); void LowerIrql(uint32_t new_irql); + X_STATUS Delay( + uint32_t processor_mode, uint32_t alertable, uint64_t interval); + private: X_STATUS PlatformCreate(); void PlatformDestroy(); diff --git a/src/xenia/kernel/modules/xboxkrnl/xboxkrnl_threading.cc b/src/xenia/kernel/modules/xboxkrnl/xboxkrnl_threading.cc index 67922c3d6..ed724a1cb 100644 --- a/src/xenia/kernel/modules/xboxkrnl/xboxkrnl_threading.cc +++ b/src/xenia/kernel/modules/xboxkrnl/xboxkrnl_threading.cc @@ -205,6 +205,31 @@ SHIM_CALL KeQueryPerformanceFrequency_shim( } +X_STATUS xeKeDelayExecutionThread( + uint32_t processor_mode, uint32_t alertable, uint64_t interval) { + XThread* thread = XThread::GetCurrentThread(); + return thread->Delay(processor_mode, alertable, interval); +} + + +SHIM_CALL KeDelayExecutionThread_shim( + xe_ppc_state_t* ppc_state, KernelState* state) { + uint32_t processor_mode = SHIM_GET_ARG_32(0); + uint32_t alertable = SHIM_GET_ARG_32(1); + uint32_t interval_ptr = SHIM_GET_ARG_32(2); + uint64_t interval = SHIM_MEM_64(interval_ptr); + + XELOGD( + "KeDelayExecutionThread(%.8X, %d, %.8X(%.16llX)", + processor_mode, alertable, interval_ptr, interval); + + X_STATUS result = xeKeDelayExecutionThread( + processor_mode, alertable, interval); + + SHIM_SET_RETURN(result); +} + + void xeKeQuerySystemTime(uint64_t* time_ptr) { FILETIME t; GetSystemTimeAsFileTime(&t); @@ -654,6 +679,7 @@ void xe::kernel::xboxkrnl::RegisterThreadingExports( SHIM_SET_MAPPING("xboxkrnl.exe", KeGetCurrentProcessType, state); SHIM_SET_MAPPING("xboxkrnl.exe", KeQueryPerformanceFrequency, state); + SHIM_SET_MAPPING("xboxkrnl.exe", KeDelayExecutionThread, state); SHIM_SET_MAPPING("xboxkrnl.exe", KeQuerySystemTime, state); SHIM_SET_MAPPING("xboxkrnl.exe", KeTlsAlloc, state); diff --git a/src/xenia/kernel/modules/xboxkrnl/xboxkrnl_threading.h b/src/xenia/kernel/modules/xboxkrnl/xboxkrnl_threading.h index afa962dd6..68e22f628 100644 --- a/src/xenia/kernel/modules/xboxkrnl/xboxkrnl_threading.h +++ b/src/xenia/kernel/modules/xboxkrnl/xboxkrnl_threading.h @@ -33,6 +33,9 @@ uint32_t xeKeGetCurrentProcessType(); uint64_t xeKeQueryPerformanceFrequency(); void xeKeQuerySystemTime(uint64_t* time_ptr); +X_STATUS xeKeDelayExecutionThread( + uint32_t processor_mode, uint32_t alertable, uint64_t interval); + uint32_t xeKeTlsAlloc(); int KeTlsFree(uint32_t tls_index); uint64_t xeKeTlsGetValue(uint32_t tls_index);