[XBDM] Cleanup Stubs

This commit is contained in:
Adrian 2025-07-21 20:17:37 +01:00 committed by Radosław Gliński
parent a717c0cd9f
commit 4702bfb94c
7 changed files with 437 additions and 74 deletions

View File

@ -7,6 +7,8 @@
******************************************************************************
*/
#include <ranges>
#include "xenia/kernel/kernel_state.h"
#include "xenia/base/byte_stream.h"
@ -849,6 +851,19 @@ object_ref<XThread> KernelState::GetThreadByID(uint32_t thread_id) {
return retain_object(thread);
}
std::vector<uint32_t> 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<std::uint32_t> 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));

View File

@ -265,6 +265,7 @@ class KernelState {
void OnThreadExecute(XThread* thread);
void OnThreadExit(XThread* thread);
object_ref<XThread> GetThreadByID(uint32_t thread_id);
std::vector<uint32_t> GetAllThreadIDs();
void RegisterNotifyListener(XNotifyListener* listener);
void UnregisterNotifyListener(XNotifyListener* listener);

View File

@ -199,6 +199,14 @@ struct X_DASH_APP_INFO {
};
static_assert_size(X_DASH_APP_INFO, 0xC);
struct X_GUID {
xe::be<uint32_t> Data1;
xe::be<uint16_t> Data2;
xe::be<uint16_t> Data3;
uint8_t Data4[8];
};
static_assert_size(X_GUID, 0x10);
struct X_PASSPORT_SESSION_TOKEN {
uint8_t SessionToken[28];
};

View File

@ -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<char*>(arg1);
uint32_t* max_name_chars_ptr = ctx->TranslateVirtualGPR<uint32_t*>(arg2);
const size_t xbox_name_size =
xe::string_util::size_in_bytes(DmXboxName, true);
uint32_t max_name_chars = xe::load_and_swap<uint32_t>(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<uint32_t>* 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<uint32_t>(ctx->r[3]);
uint8_t* unknown_addr =
ctx->TranslateVirtual(static_cast<uint32_t>(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<xe::be<uint32_t>*>(
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<DMN_MODULE_LOAD> 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<xe::vfs::HostPathDevice>("\\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<DM_PDB_SIGNATURE> 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<DM_XBE> 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<uint16_t> major;
xe::be<uint16_t> minor;
xe::be<uint16_t> build;
xe::be<uint16_t> qfe;
};
struct XBDM_SYSTEM_INFO {
xe::be<uint32_t> size;
XBDM_VERSION_INFO base_kernel_version;
XBDM_VERSION_INFO kernel_version;
XBDM_VERSION_INFO xdk_version;
xe::be<uint32_t> flags;
};
dword_result_t DmGetSystemInfo_entry(pointer_t<XBDM_SYSTEM_INFO> 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<DM_THREAD_INFO_EX> 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<uint32_t>(
xe::string_util::size_in_bytes(thread->name(), true));
char* thread_name_ptr =
kernel_state()->memory()->TranslateVirtual<char*>(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<xe::be<uint32_t>*>(
tls_base_address) = thread->pcr_ptr();
*kernel_state()->memory()->TranslateVirtual<xe::be<uint32_t>*>(
start_address) = thread->start_address();
*kernel_state()->memory()->TranslateVirtual<xe::be<uint32_t>*>(
stack_base_address) = thread->stack_base();
*kernel_state()->memory()->TranslateVirtual<xe::be<uint32_t>*>(
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<uint32_t>(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);

View File

@ -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<uint16_t> major;
xe::be<uint16_t> minor;
xe::be<uint16_t> build;
xe::be<uint16_t> qfe;
};
static_assert_size(XBDM_VERSION_INFO, 8);
struct XBDM_SYSTEM_INFO {
xe::be<uint32_t> size;
XBDM_VERSION_INFO base_kernel_version;
XBDM_VERSION_INFO kernel_version;
XBDM_VERSION_INFO xdk_version;
xe::be<uint32_t> flags;
};
static_assert_size(XBDM_SYSTEM_INFO, 32);
struct DM_XBE {
char launch_path[MAX_PATH + 1];
xe::be<uint32_t> timestamp;
xe::be<uint32_t> checksum;
xe::be<uint32_t> stack_size;
};
static_assert_size(DM_XBE, 276);
struct DM_THREAD_INFO_EX {
xe::be<uint32_t> size;
xe::be<uint32_t> suspend_count;
xe::be<uint32_t> priority;
xe::be<uint32_t> tls_base_ptr;
xe::be<uint32_t> start_ptr;
xe::be<uint32_t> stack_base_ptr;
xe::be<uint32_t> stack_limit_ptr;
X_FILETIME create_time;
xe::be<uint32_t> stack_slack_space;
xe::be<uint32_t> thread_name_ptr;
xe::be<uint32_t> 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<uint32_t> base_address_ptr;
xe::be<uint32_t> size;
xe::be<uint32_t> TimeStamp;
xe::be<uint32_t> checksum;
xe::be<uint32_t> flags;
xe::be<uint32_t> data_address_ptr;
xe::be<uint32_t> data_size;
xe::be<uint32_t> 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<uint32_t>* 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_

View File

@ -704,6 +704,14 @@ uint32_t XThread::suspend_count() {
return guest_object<X_KTHREAD>()->suspend_count;
}
X_FILETIME XThread::creation_time() {
return static_cast<X_FILETIME>(guest_object<X_KTHREAD>()->create_time);
}
uint32_t XThread::start_address() {
return guest_object<X_KTHREAD>()->start_address;
}
X_STATUS XThread::Resume(uint32_t* out_suspend_count) {
auto guest_thread = guest_object<X_KTHREAD>();

View File

@ -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,