diff --git a/src/xenia/kernel/kernel_state.cc b/src/xenia/kernel/kernel_state.cc index c19f23ead..f0d0c439e 100644 --- a/src/xenia/kernel/kernel_state.cc +++ b/src/xenia/kernel/kernel_state.cc @@ -7,6 +7,8 @@ ****************************************************************************** */ +#include + #include "xenia/kernel/kernel_state.h" #include "xenia/base/byte_stream.h" @@ -849,6 +851,19 @@ object_ref KernelState::GetThreadByID(uint32_t thread_id) { return retain_object(thread); } +std::vector KernelState::GetAllThreadIDs() { + auto global_lock = global_critical_region_.Acquire(); + + auto thread_ids_view = + threads_by_id_ | + std::views::transform([](const auto& pair) { return pair.first; }); + + std::vector thread_ids(thread_ids_view.begin(), + thread_ids_view.end()); + + return thread_ids; +} + void KernelState::RegisterNotifyListener(XNotifyListener* listener) { auto global_lock = global_critical_region_.Acquire(); notify_listeners_.push_back(retain_object(listener)); diff --git a/src/xenia/kernel/kernel_state.h b/src/xenia/kernel/kernel_state.h index 78dd615bf..26ccad48e 100644 --- a/src/xenia/kernel/kernel_state.h +++ b/src/xenia/kernel/kernel_state.h @@ -265,6 +265,7 @@ class KernelState { void OnThreadExecute(XThread* thread); void OnThreadExit(XThread* thread); object_ref GetThreadByID(uint32_t thread_id); + std::vector GetAllThreadIDs(); void RegisterNotifyListener(XNotifyListener* listener); void UnregisterNotifyListener(XNotifyListener* listener); diff --git a/src/xenia/kernel/xam/xam.h b/src/xenia/kernel/xam/xam.h index 12cfc7512..58636ebb1 100644 --- a/src/xenia/kernel/xam/xam.h +++ b/src/xenia/kernel/xam/xam.h @@ -199,6 +199,14 @@ struct X_DASH_APP_INFO { }; static_assert_size(X_DASH_APP_INFO, 0xC); +struct X_GUID { + xe::be Data1; + xe::be Data2; + xe::be Data3; + uint8_t Data4[8]; +}; +static_assert_size(X_GUID, 0x10); + struct X_PASSPORT_SESSION_TOKEN { uint8_t SessionToken[28]; }; diff --git a/src/xenia/kernel/xbdm/xbdm_misc.cc b/src/xenia/kernel/xbdm/xbdm_misc.cc index 454e7f2d1..e4feb0bd9 100644 --- a/src/xenia/kernel/xbdm/xbdm_misc.cc +++ b/src/xenia/kernel/xbdm/xbdm_misc.cc @@ -2,12 +2,14 @@ ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** - * Copyright 2022 Ben Vanik. All rights reserved. * + * Copyright 2025 Xenia Canary. All rights reserved. * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ +#include "xenia/kernel/xbdm/xbdm_misc.h" #include "xenia/base/logging.h" +#include "xenia/base/string_util.h" #include "xenia/kernel/kernel_state.h" #include "xenia/kernel/util/shim_utils.h" #include "xenia/kernel/xbdm/xbdm_private.h" @@ -15,54 +17,38 @@ #include "xenia/vfs/devices/host_path_device.h" #include "xenia/xbox.h" -// chrispy: no idea what a real valid value is for this -static constexpr const char DmXboxName[] = "Xbox360Name"; - DECLARE_bool(debug); namespace xe { namespace kernel { namespace xbdm { -#define XBDM_SUCCESSFUL 0x02DA0000 -#define XBDM_UNSUCCESSFUL 0x82DA0000 - -#define MAKE_DUMMY_STUB_PTR(x) \ - dword_result_t x##_entry() { return 0; } \ - DECLARE_XBDM_EXPORT1(x, kDebug, kStub) - -#define MAKE_DUMMY_STUB_STATUS(x) \ - dword_result_t x##_entry() { return X_STATUS_INVALID_PARAMETER; } \ - DECLARE_XBDM_EXPORT1(x, kDebug, kStub) dword_result_t DmAllocatePool_entry(dword_t bytes) { return kernel_memory()->SystemHeapAlloc(bytes); }; DECLARE_XBDM_EXPORT1(DmAllocatePool, kDebug, kImplemented); -void DmCloseLoadedModules_entry(lpdword_t unk0_ptr) {} -DECLARE_XBDM_EXPORT1(DmCloseLoadedModules, kDebug, kStub); +dword_result_t DmFreePool_entry(lpvoid_t data_ptr) { + kernel_state()->memory()->SystemHeapFree(data_ptr.guest_address()); -MAKE_DUMMY_STUB_STATUS(DmFreePool); - -dword_result_t DmGetXbeInfo_entry() { - // TODO(gibbed): 4D5307DC appears to expect this as success? - // Unknown arguments -- let's hope things don't explode. return XBDM_SUCCESSFUL; } -DECLARE_XBDM_EXPORT1(DmGetXbeInfo, kDebug, kStub); +DECLARE_XBDM_EXPORT1(DmFreePool, kDebug, kImplemented); -dword_result_t DmGetXboxName_entry(const ppc_context_t& ctx) { - uint64_t arg1 = ctx->r[3]; - uint64_t arg2 = ctx->r[4]; - if (!arg1 || !arg2) { - return 0x80070057; +dword_result_t DmGetXboxName_entry(lpstring_t name_ptr, + lpdword_t max_name_size_ptr) { + if (!name_ptr || !max_name_size_ptr) { + return X_E_INVALIDARG; } - char* name_out = ctx->TranslateVirtualGPR(arg1); - uint32_t* max_name_chars_ptr = ctx->TranslateVirtualGPR(arg2); + const size_t xbox_name_size = + xe::string_util::size_in_bytes(DmXboxName, true); - uint32_t max_name_chars = xe::load_and_swap(max_name_chars_ptr); - strncpy(name_out, DmXboxName, sizeof(DmXboxName)); + if (xbox_name_size > *max_name_size_ptr) { + return XBDM_BUFFER_TOO_SMALL; + } + + xe::string_util::copy_truncating(name_ptr, DmXboxName, xbox_name_size); return XBDM_SUCCESSFUL; } @@ -73,46 +59,76 @@ dword_result_t DmIsDebuggerPresent_entry() { } DECLARE_XBDM_EXPORT1(DmIsDebuggerPresent, kDebug, kStub); -void DmSendNotificationString_entry(lpdword_t unk0_ptr) {} +dword_result_t DmSendNotificationString_entry(lpstring_t notify_string_ptr) { + if (!notify_string_ptr) { + return X_E_INVALIDARG; + } + + return XBDM_SUCCESSFUL; +} DECLARE_XBDM_EXPORT1(DmSendNotificationString, kDebug, kStub); -dword_result_t DmRegisterCommandProcessor_entry(lpdword_t name_ptr, +uint32_t DmRegisterCommandProcessorEx(char* cmd_handler_name_ptr, + xe::be* handler_fn, + uint32_t thread) { + if (!cmd_handler_name_ptr) { + return X_E_INVALIDARG; + } + + return XBDM_SUCCESSFUL; +} + +dword_result_t DmRegisterCommandProcessor_entry(lpstring_t cmd_handler_name_ptr, lpdword_t handler_fn) { // Return success to prevent some games from crashing - return XBDM_SUCCESSFUL; + return DmRegisterCommandProcessorEx(cmd_handler_name_ptr, handler_fn, 0); } DECLARE_XBDM_EXPORT1(DmRegisterCommandProcessor, kDebug, kStub); -dword_result_t DmRegisterCommandProcessorEx_entry(lpdword_t name_ptr, - lpdword_t handler_fn, - dword_t unk3) { +dword_result_t DmRegisterCommandProcessorEx_entry( + lpstring_t cmd_handler_name_ptr, lpdword_t handler_fn, dword_t thread) { // Return success to prevent some games from stalling - return XBDM_SUCCESSFUL; + return DmRegisterCommandProcessorEx(cmd_handler_name_ptr, handler_fn, thread); } DECLARE_XBDM_EXPORT1(DmRegisterCommandProcessorEx, kDebug, kStub); -MAKE_DUMMY_STUB_STATUS(DmStartProfiling); -MAKE_DUMMY_STUB_STATUS(DmStopProfiling); -// two arguments, first is num frames i think, second is some kind of pointer to -// where to capture -dword_result_t DmCaptureStackBackTrace_entry(const ppc_context_t& ctx) { - uint32_t nframes = static_cast(ctx->r[3]); - uint8_t* unknown_addr = - ctx->TranslateVirtual(static_cast(ctx->r[4])); - return X_STATUS_INVALID_PARAMETER; +dword_result_t DmCaptureStackBackTrace_entry(dword_t frames_to_capture, + lpvoid_t backtrace_ptr) { + auto trace_ptr = + kernel_state()->memory()->TranslateVirtual*>( + backtrace_ptr); + + if (frames_to_capture > MAX_FRAMES_TO_CAPTURE) { + return X_E_INVALIDARG; + } + + std::fill_n(trace_ptr, frames_to_capture, 0); + + std::vector stack_frames = + std::vector(trace_ptr, trace_ptr + frames_to_capture); + + return XBDM_SUCCESSFUL; } DECLARE_XBDM_EXPORT1(DmCaptureStackBackTrace, kDebug, kStub); -MAKE_DUMMY_STUB_STATUS(DmGetThreadInfoEx); -MAKE_DUMMY_STUB_STATUS(DmSetProfilingOptions); +dword_result_t DmWalkLoadedModules_entry( + lpdword_t walk_modules_ptr, pointer_t module_load_ptr) { + if (!walk_modules_ptr || !module_load_ptr) { + return X_E_INVALIDARG; + } + + module_load_ptr.Zero(); -dword_result_t DmWalkLoadedModules_entry(lpdword_t unk0_ptr, - lpdword_t unk1_ptr) { // Some games will loop forever unless this code is returned - return 0x82DA0104; + return XBDM_ENDOFLIST; } DECLARE_XBDM_EXPORT1(DmWalkLoadedModules, kDebug, kStub); +dword_result_t DmCloseLoadedModules_entry(lpdword_t walk_modules_ptr) { + return XBDM_SUCCESSFUL; +} +DECLARE_XBDM_EXPORT1(DmCloseLoadedModules, kDebug, kStub); + dword_result_t DmMapDevkitDrive_entry(const ppc_context_t& ctx) { auto devkit_device = std::make_unique("\\DEVKIT", "devkit", false); @@ -135,33 +151,46 @@ dword_result_t DmMapDevkitDrive_entry(const ppc_context_t& ctx) { } DECLARE_XBDM_EXPORT1(DmMapDevkitDrive, kDebug, kImplemented); -dword_result_t DmFindPdbSignature_entry(lpdword_t unk0_ptr, - lpdword_t unk1_ptr) { - return X_STATUS_INVALID_PARAMETER; +dword_result_t DmFindPdbSignature_entry( + lpvoid_t base_address, pointer_t pdb_signature_ptr) { + if (!base_address || !pdb_signature_ptr) { + return X_E_INVALIDARG; + } + + pdb_signature_ptr.Zero(); + + return X_ERROR_INVALID_PARAMETER; } DECLARE_XBDM_EXPORT1(DmFindPdbSignature, kDebug, kStub); -dword_result_t DmGetConsoleDebugMemoryStatus_entry() { return XBDM_SUCCESSFUL; } +dword_result_t DmGetXbeInfo_entry(lpstring_t name, + pointer_t xbe_info_ptr) { + if (!xbe_info_ptr) { + return X_E_INVALIDARG; + } + + xbe_info_ptr.Zero(); + + // TODO(gibbed): 4D5307DC appears to expect this as success? + return XBDM_SUCCESSFUL; +} +DECLARE_XBDM_EXPORT1(DmGetXbeInfo, kDebug, kStub); + +dword_result_t DmGetConsoleDebugMemoryStatus_entry( + lpdword_t memory_config_ptr) { + if (!memory_config_ptr) { + return X_E_INVALIDARG; + } + + *memory_config_ptr = DM_CONSOLEMEMCONFIG_NOADDITIONALMEM; + + return XBDM_SUCCESSFUL; +} DECLARE_XBDM_EXPORT1(DmGetConsoleDebugMemoryStatus, kDebug, kStub); -struct XBDM_VERSION_INFO { - xe::be major; - xe::be minor; - xe::be build; - xe::be qfe; -}; - -struct XBDM_SYSTEM_INFO { - xe::be size; - XBDM_VERSION_INFO base_kernel_version; - XBDM_VERSION_INFO kernel_version; - XBDM_VERSION_INFO xdk_version; - xe::be flags; -}; - dword_result_t DmGetSystemInfo_entry(pointer_t info) { if (!info) { - return XBDM_UNSUCCESSFUL; + return X_E_INVALIDARG; } info->base_kernel_version.major = info->kernel_version.major = 2; @@ -178,7 +207,7 @@ DECLARE_XBDM_EXPORT1(DmGetSystemInfo, kDebug, kStub); dword_result_t DmSetMemory_entry(lpvoid_t dest_ptr, dword_t buf_size, lpvoid_t src_ptr, lpdword_t bytes_written) { if (!dest_ptr || !src_ptr || !buf_size) { - return XBDM_UNSUCCESSFUL; + return X_E_INVALIDARG; } if (bytes_written) { @@ -219,7 +248,7 @@ DECLARE_XBDM_EXPORT1(DmSetMemory, kDebug, kImplemented); dword_result_t DmGetMemory_entry(lpvoid_t src_ptr, dword_t buf_size, lpvoid_t dest_ptr, lpdword_t bytes_written) { if (!dest_ptr || !src_ptr || !buf_size) { - return XBDM_UNSUCCESSFUL; + return X_E_INVALIDARG; } if (bytes_written) { @@ -257,6 +286,179 @@ dword_result_t DmGetMemory_entry(lpvoid_t src_ptr, dword_t buf_size, } DECLARE_XBDM_EXPORT1(DmGetMemory, kDebug, kImplemented); +dword_result_t DmGetThreadInfoEx_entry( + dword_t thread_id, pointer_t thread_info) { + if (!thread_info) { + return X_E_INVALIDARG; + } + + thread_info.Zero(); + + auto thread = kernel_state()->GetThreadByID(thread_id); + + if (!thread) { + return XBDM_UNSUCCESSFUL; + } + + const uint32_t page_size = + kernel_state()->memory()->GetPhysicalHeap()->page_size(); + uint32_t thread_info_address = + kernel_state()->memory()->SystemHeapAlloc(page_size); + + const uint32_t thread_name_size = static_cast( + xe::string_util::size_in_bytes(thread->name(), true)); + + char* thread_name_ptr = + kernel_state()->memory()->TranslateVirtual(thread_info_address); + + xe::string_util::copy_truncating(thread_name_ptr, thread->name().data(), + thread_name_size); + + uint32_t tls_base_address = thread_info_address + thread_name_size; + uint32_t start_address = tls_base_address + sizeof(uint32_t); + uint32_t stack_base_address = start_address + sizeof(uint32_t); + uint32_t stack_limit_address = stack_base_address + sizeof(uint32_t); + + *kernel_state()->memory()->TranslateVirtual*>( + tls_base_address) = thread->pcr_ptr(); + *kernel_state()->memory()->TranslateVirtual*>( + start_address) = thread->start_address(); + *kernel_state()->memory()->TranslateVirtual*>( + stack_base_address) = thread->stack_base(); + *kernel_state()->memory()->TranslateVirtual*>( + stack_limit_address) = thread->stack_limit(); + + thread_info->size = sizeof(DM_THREAD_INFO_EX); + thread_info->suspend_count = thread->suspend_count(); + thread_info->priority = thread->priority(); + thread_info->tls_base_ptr = tls_base_address; + thread_info->start_ptr = start_address; + thread_info->stack_base_ptr = stack_base_address; + thread_info->stack_limit_ptr = stack_limit_address; + thread_info->create_time = thread->creation_time(); + thread_info->stack_slack_space = 0; + thread_info->thread_name_ptr = thread_info_address; + thread_info->thread_name_length = thread_name_size; + thread_info->current_processor = 0; + + return XBDM_SUCCESSFUL; +} +DECLARE_XBDM_EXPORT1(DmGetThreadInfoEx, kDebug, kSketchy); + +dword_result_t DmGetThreadList_entry(lpdword_t thread_ids_ptr, + lpdword_t thread_ids_size_ptr) { + if (!thread_ids_ptr || !thread_ids_size_ptr) { + return X_E_INVALIDARG; + } + + const uint32_t array_entries = *thread_ids_size_ptr; + uint32_t array_size = sizeof(uint32_t) * array_entries; + + auto thread_ids = kernel_state()->GetAllThreadIDs(); + uint32_t thread_ids_count = static_cast(thread_ids.size()); + + if (thread_ids_count > array_entries) { + return XBDM_BUFFER_TOO_SMALL; + } + + if (thread_ids_count > MAX_FRAMES_TO_CAPTURE) { + return XBDM_UNSUCCESSFUL; + } + + std::memset(thread_ids_ptr, 0, array_size); + + for (uint32_t i = 0; const auto thread_id : thread_ids) { + thread_ids_ptr[i] = thread_id; + i++; + } + + *thread_ids_size_ptr = thread_ids_count; + + return XBDM_SUCCESSFUL; +} +DECLARE_XBDM_EXPORT1(DmGetThreadList, kDebug, kImplemented); + +dword_result_t DmSuspendThread_entry(dword_t thread_id) { + auto thread = kernel_state()->GetThreadByID(thread_id); + + if (!thread) { + return XBDM_UNSUCCESSFUL; + } + + X_STATUS result = thread->Suspend(); + + if (XFAILED(result)) { + return XBDM_UNSUCCESSFUL; + } + + return XBDM_SUCCESSFUL; +} +DECLARE_XBDM_EXPORT1(DmSuspendThread, kDebug, kImplemented); + +dword_result_t DmResumeThread_entry(dword_t thread_id) { + auto thread = kernel_state()->GetThreadByID(thread_id); + + if (!thread) { + return XBDM_UNSUCCESSFUL; + } + + X_STATUS result = thread->Resume(); + + if (XFAILED(result)) { + return XBDM_UNSUCCESSFUL; + } + + return XBDM_SUCCESSFUL; +} +DECLARE_XBDM_EXPORT1(DmResumeThread, kDebug, kImplemented); + +dword_result_t DmOpenNotificationSession_entry(dword_t flags, + lpvoid_t dmn_session_ptr) { + if (!dmn_session_ptr) { + return X_E_INVALIDARG; + } + + *dmn_session_ptr = 0; + + // Prevents 555308C2 from crashing + return XBDM_SUCCESSFUL; +} +DECLARE_XBDM_EXPORT1(DmOpenNotificationSession, kDebug, kStub); + +dword_result_t DmNotify_entry(lpvoid_t dmn_session_ptr, dword_t notification, + lpvoid_t callback_ptr) { + if (!dmn_session_ptr) { + return X_E_INVALIDARG; + } + + // Prevents 555308C2 from crashing + return XBDM_SUCCESSFUL; +} +DECLARE_XBDM_EXPORT1(DmNotify, kDebug, kStub); + +dword_result_t DmStartProfiling_entry(lpstring_t log_file_name_ptr, + dword_t buffer_size) { + if (!log_file_name_ptr) { + return X_E_INVALIDARG; + } + + return XBDM_SUCCESSFUL; +} +DECLARE_XBDM_EXPORT1(DmStartProfiling, kDebug, kStub); + +dword_result_t DmStopProfiling_entry() { return XBDM_SUCCESSFUL; } +DECLARE_XBDM_EXPORT1(DmStopProfiling, kDebug, kStub); + +dword_result_t DmSetProfilingOptions_entry(dword_t flags) { + return XBDM_SUCCESSFUL; +} +DECLARE_XBDM_EXPORT1(DmSetProfilingOptions, kDebug, kStub); + +dword_result_t DmSetDumpMode_entry(dword_t dump_mode) { + return XBDM_SUCCESSFUL; +} +DECLARE_XBDM_EXPORT1(DmSetDumpMode, kDebug, kStub); + dword_result_t DmIsFastCAPEnabled_entry() { return XBDM_UNSUCCESSFUL; } DECLARE_XBDM_EXPORT1(DmIsFastCAPEnabled, kDebug, kStub); diff --git a/src/xenia/kernel/xbdm/xbdm_misc.h b/src/xenia/kernel/xbdm/xbdm_misc.h new file mode 100644 index 000000000..eaa639f79 --- /dev/null +++ b/src/xenia/kernel/xbdm/xbdm_misc.h @@ -0,0 +1,123 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2025 Xenia Canary. All rights reserved. + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef XENIA_KERNEL_XBDM_XBDM_MSIC_H_ +#define XENIA_KERNEL_XBDM_XBDM_MSIC_H_ + +#include "xenia/kernel/util/shim_utils.h" +#include "xenia/kernel/xam/xam.h" + +namespace xe { +namespace kernel { +namespace xbdm { + +// chrispy: no idea what a real valid value is for this +static constexpr char DmXboxName[] = "Xbox360Name"; + +// clang-format off + +#define XBDM_SUCCESSFUL 0x02DA0000 +#define XBDM_UNSUCCESSFUL 0x82DA0000 +#define XBDM_FASTCAPENABLED 0x82DA0007 +#define XBDM_ALREADYEXISTS 0x82DA0010 +#define XBDM_ENDOFLIST 0x82DA0104 +#define XBDM_BUFFER_TOO_SMALL 0x82DA0105 + +#define MAX_NOTIFY 32 +#define DM_NOTIFYMAX 18 +#define MAX_ENH 16 +#define MAX_PATH 260 +#define MAX_FRAMES_TO_CAPTURE 256 + +// clang-format on + +enum CONSOLE_MEMORY_CONFIG_STATE : uint32_t { + DM_CONSOLEMEMCONFIG_NOADDITIONALMEM, + DM_CONSOLEMEMCONFIG_ADDITIONALMEMDISABLED, + DM_CONSOLEMEMCONFIG_ADDITIONALMEMENABLED +}; + +struct XBDM_VERSION_INFO { + xe::be major; + xe::be minor; + xe::be build; + xe::be qfe; +}; +static_assert_size(XBDM_VERSION_INFO, 8); + +struct XBDM_SYSTEM_INFO { + xe::be size; + XBDM_VERSION_INFO base_kernel_version; + XBDM_VERSION_INFO kernel_version; + XBDM_VERSION_INFO xdk_version; + xe::be flags; +}; +static_assert_size(XBDM_SYSTEM_INFO, 32); + +struct DM_XBE { + char launch_path[MAX_PATH + 1]; + xe::be timestamp; + xe::be checksum; + xe::be stack_size; +}; +static_assert_size(DM_XBE, 276); + +struct DM_THREAD_INFO_EX { + xe::be size; + xe::be suspend_count; + xe::be priority; + xe::be tls_base_ptr; + xe::be start_ptr; + xe::be stack_base_ptr; + xe::be stack_limit_ptr; + X_FILETIME create_time; + xe::be stack_slack_space; + xe::be thread_name_ptr; + xe::be thread_name_length; + uint8_t current_processor; +}; +static_assert_size(DM_THREAD_INFO_EX, 52); + +struct DMN_MODULE_LOAD { + char name[MAX_PATH]; + xe::be base_address_ptr; + xe::be size; + xe::be TimeStamp; + xe::be checksum; + xe::be flags; + xe::be data_address_ptr; + xe::be data_size; + xe::be thread_id; +}; +static_assert_size(DMN_MODULE_LOAD, 292); + +struct DM_PDB_SIGNATURE { + xam::X_GUID guid; + uint32_t age; + char path[MAX_PATH]; +}; +static_assert_size(DM_PDB_SIGNATURE, 280); + +uint32_t DmRegisterCommandProcessorEx(char* cmd_handler_name_ptr, + xe::be* handler_fn, + uint32_t thread); + +#define MAKE_DUMMY_STUB_PTR(x) \ + dword_result_t x##_entry() { return 0; } \ + DECLARE_XBDM_EXPORT1(x, kDebug, kStub) + +#define MAKE_DUMMY_STUB_STATUS(x) \ + dword_result_t x##_entry() { return X_STATUS_INVALID_PARAMETER; } \ + DECLARE_XBDM_EXPORT1(x, kDebug, kStub) + +} // namespace xbdm +} // namespace kernel +} // namespace xe + +#endif // XENIA_KERNEL_XBDM_XBDM_MSIC_H_ diff --git a/src/xenia/kernel/xthread.cc b/src/xenia/kernel/xthread.cc index 8f113f829..6cb2b53a7 100644 --- a/src/xenia/kernel/xthread.cc +++ b/src/xenia/kernel/xthread.cc @@ -704,6 +704,14 @@ uint32_t XThread::suspend_count() { return guest_object()->suspend_count; } +X_FILETIME XThread::creation_time() { + return static_cast(guest_object()->create_time); +} + +uint32_t XThread::start_address() { + return guest_object()->start_address; +} + X_STATUS XThread::Resume(uint32_t* out_suspend_count) { auto guest_thread = guest_object(); diff --git a/src/xenia/kernel/xthread.h b/src/xenia/kernel/xthread.h index 6a6bd2882..4884ba3e5 100644 --- a/src/xenia/kernel/xthread.h +++ b/src/xenia/kernel/xthread.h @@ -18,6 +18,7 @@ #include "xenia/cpu/thread.h" #include "xenia/cpu/thread_state.h" #include "xenia/kernel/util/native_list.h" +#include "xenia/kernel/util/xfiletime.h" #include "xenia/kernel/xmutant.h" #include "xenia/kernel/xobject.h" #include "xenia/xbox.h" @@ -371,6 +372,8 @@ class XThread : public XObject, public cpu::Thread { const CreationParams* creation_params() const { return &creation_params_; } uint32_t tls_ptr() const { return tls_static_address_; } uint32_t pcr_ptr() const { return pcr_address_; } + uint32_t stack_base() const { return stack_base_; } + uint32_t stack_limit() const { return stack_limit_; } // True if the thread is created by the guest app. bool is_guest_thread() const { return guest_thread_; } bool main_thread() const { return main_thread_; } @@ -414,6 +417,9 @@ class XThread : public XObject, public cpu::Thread { bool SetTLSValue(uint32_t slot, uint32_t value); uint32_t suspend_count(); + X_FILETIME creation_time(); + uint32_t start_address(); + X_STATUS Resume(uint32_t* out_suspend_count = nullptr); X_STATUS Suspend(uint32_t* out_suspend_count = nullptr); X_STATUS Delay(uint32_t processor_mode, uint32_t alertable,