From 2fa2f1a78cf111f771a352eb3332b1c6ac6a73ce Mon Sep 17 00:00:00 2001 From: "chss95cs@gmail.com" Date: Sun, 23 Apr 2023 10:39:52 -0400 Subject: [PATCH] =?UTF-8?q?Add=20more=20wrapper=20functions=20to=20ppc=5Fc?= =?UTF-8?q?ontext=5Ft=20in=20kernel,=20want=20to=20switch=E2=80=A6=20?= =?UTF-8?q?=E2=80=A6=20over=20to=20referencing=20state=20through=20ppc=5Fc?= =?UTF-8?q?ontext=20as=20much=20as=20possible,=20it'll=20make=20implementi?= =?UTF-8?q?ng=20things=20like=20kernel=20processes=20much=20easier=20in=20?= =?UTF-8?q?the=20future?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move forward definitions of kernel types into kernel_fwd.h Stub implementation of XamLoaderGetMediaInfoEx Partially implement XamSetDashContext implement XamGetDashContext Stub implementation of XamUserIsUnsafeProgrammingAllowed Stub implementation of XamUserGetSubscriptionType Expanded the supported object types for ObReferenceObjectByHandle and wrapped the logic for encoding the type in a constexpr function ObReferenceObjectByName was taking lpstring_t for first param, but the function actually takes X_ANSI_STRING ptr NtReleaseMutant actually does not return anything from KeReleaseMutant, it just checks the handle and returns whether it was invalid. Changed the raise/lower irql functions to just set the irql on the pcr instead of setting it on field of Processor, processor is a shared object and irql is per-thread Semi-stub implementation of KeGetImagePageTableEntry. I locked at it in the HV and got it so the values are in the same range the HV returns + actually reflect the page & memory range, but i doubt its equal to the values the hv returns on real hw. Used by modern dashboards, don't know for what. Log error message for ObDereferenceObject w/ null ptr. Allocate a special fixed page that dashboards reference, currently don't know what the data on that page is supposed to be. Add current_irql field to X_KPCR Added Device object member of XObject::Type enum Added some notes about other gpu registers, found a table of register names and indices in xam --- src/xenia/gpu/register_table.inc | 6 ++ src/xenia/kernel/kernel_state.cc | 12 +++- src/xenia/kernel/kernel_state.h | 15 ++--- src/xenia/kernel/util/kernel_fwd.h | 30 +++++++++ src/xenia/kernel/util/shim_utils.cc | 6 +- src/xenia/kernel/util/shim_utils.h | 15 ++++- src/xenia/kernel/xam/xam_content.cc | 10 ++- src/xenia/kernel/xam/xam_ui.cc | 16 +++++ src/xenia/kernel/xam/xam_user.cc | 22 ++++++ src/xenia/kernel/xboxkrnl/xboxkrnl_memory.cc | 27 +++++++- src/xenia/kernel/xboxkrnl/xboxkrnl_ob.cc | 34 ++++++++-- .../kernel/xboxkrnl/xboxkrnl_threading.cc | 67 ++++++++++++++----- src/xenia/kernel/xobject.h | 1 + src/xenia/kernel/xthread.h | 5 +- 14 files changed, 225 insertions(+), 41 deletions(-) create mode 100644 src/xenia/kernel/util/kernel_fwd.h diff --git a/src/xenia/gpu/register_table.inc b/src/xenia/gpu/register_table.inc index bfe7549d3..2ea5bf93f 100644 --- a/src/xenia/gpu/register_table.inc +++ b/src/xenia/gpu/register_table.inc @@ -52,6 +52,10 @@ XE_GPU_REGISTER(0x057F, kDword, SCRATCH_REG7) XE_GPU_REGISTER(0x05C8, kDword, WAIT_UNTIL) +//src is flash_xam.xex, i've seen it used by the kernel and aurora +//seems to have a negative value while the gpu is busy +//XE_GPU_REGISTER(0x05D0, kDword, RBBM_STATUS) + //update count = 6 bit field, bits 8- 14 //there are several other fields here, they have an unknown purpose @@ -271,6 +275,8 @@ XE_GPU_REGISTER(0x0F0C, kDword, BC_PERFCOUNTER2_LOW) XE_GPU_REGISTER(0x0F0D, kDword, BC_PERFCOUNTER2_HI) XE_GPU_REGISTER(0x0F0E, kDword, BC_PERFCOUNTER3_LOW) XE_GPU_REGISTER(0x0F0F, kDword, BC_PERFCOUNTER3_HI) +//src is flash_xam.xex +//XE_GPU_REGISTER(0x0F12, RB_SIDEBAND_DATA, XE_GPU_REGISTER(0x1004, kDword, HZ_PERFCOUNTER0_SELECT) XE_GPU_REGISTER(0x1005, kDword, HZ_PERFCOUNTER0_HI) diff --git a/src/xenia/kernel/kernel_state.cc b/src/xenia/kernel/kernel_state.cc index 54b357e13..6835ef6fe 100644 --- a/src/xenia/kernel/kernel_state.cc +++ b/src/xenia/kernel/kernel_state.cc @@ -67,6 +67,14 @@ KernelState::KernelState(Emulator* emulator) // Hardcoded maximum of 2048 TLS slots. tls_bitmap_.Resize(2048); + auto hc_loc_heap = memory_->LookupHeap(strange_hardcoded_page_); + bool fixed_alloc_worked = hc_loc_heap->AllocFixed( + strange_hardcoded_page_, 65536, 0, + kMemoryAllocationCommit | kMemoryAllocationReserve, + kMemoryProtectRead | kMemoryProtectWrite); + + xenia_assert(fixed_alloc_worked); + xam::AppManager::RegisterApps(this, app_manager_.get()); } @@ -954,9 +962,7 @@ void KernelState::UpdateKeTimestampBundle() { } uint32_t KernelState::GetKeTimestampBundle() { - XE_LIKELY_IF(ke_timestamp_bundle_ptr_) { - return ke_timestamp_bundle_ptr_; - } + XE_LIKELY_IF(ke_timestamp_bundle_ptr_) { return ke_timestamp_bundle_ptr_; } else { global_critical_region::PrepareToAcquire(); return CreateKeTimestampBundle(); diff --git a/src/xenia/kernel/kernel_state.h b/src/xenia/kernel/kernel_state.h index c917cdfb7..9c8e23766 100644 --- a/src/xenia/kernel/kernel_state.h +++ b/src/xenia/kernel/kernel_state.h @@ -22,6 +22,7 @@ #include "xenia/base/cvar.h" #include "xenia/base/mutex.h" #include "xenia/cpu/export_resolver.h" +#include "xenia/kernel/util/kernel_fwd.h" #include "xenia/kernel/util/native_list.h" #include "xenia/kernel/util/object_table.h" #include "xenia/kernel/util/xdbf_utils.h" @@ -45,14 +46,6 @@ namespace kernel { constexpr fourcc_t kKernelSaveSignature = make_fourcc("KRNL"); -class Dispatcher; -class XHostThread; -class KernelModule; -class XModule; -class XNotifyListener; -class XThread; -class UserModule; - // (?), used by KeGetCurrentProcessType constexpr uint32_t X_PROCTYPE_IDLE = 0; constexpr uint32_t X_PROCTYPE_USER = 1; @@ -292,7 +285,13 @@ class KernelState { BitMap tls_bitmap_; uint32_t ke_timestamp_bundle_ptr_ = 0; std::unique_ptr timestamp_timer_; + //fixed address referenced by dashboards. Data is currently unknown + uint32_t strange_hardcoded_page_ = 0x8E038634 & (~0xFFFF); + uint32_t strange_hardcoded_location_ = 0x8E038634; + friend class XObject; +public: + uint32_t dash_context_ = 0; }; } // namespace kernel diff --git a/src/xenia/kernel/util/kernel_fwd.h b/src/xenia/kernel/util/kernel_fwd.h new file mode 100644 index 000000000..4cae57a82 --- /dev/null +++ b/src/xenia/kernel/util/kernel_fwd.h @@ -0,0 +1,30 @@ +#ifndef XENIA_KERNEL_UTIL_KERNEL_FWD_H_ +#define XENIA_KERNEL_UTIL_KERNEL_FWD_H_ + +namespace xe::kernel { +class Dispatcher; +class XHostThread; +class KernelModule; +class XModule; +class XNotifyListener; +class XThread; +class UserModule; +struct ProcessInfoBlock; +struct TerminateNotification; +struct X_TIME_STAMP_BUNDLE; +class KernelState; +struct XAPC; + +struct X_KPCR; +struct X_KTHREAD; +struct X_OBJECT_HEADER; +struct X_OBJECT_CREATE_INFORMATION; +struct X_OBJECT_TYPE; + +} // namespace xe::kernel + +namespace xe::kernel::util { +class NativeList; +class ObjectTable; +} +#endif \ No newline at end of file diff --git a/src/xenia/kernel/util/shim_utils.cc b/src/xenia/kernel/util/shim_utils.cc index 4da37acc0..68c0773ae 100644 --- a/src/xenia/kernel/util/shim_utils.cc +++ b/src/xenia/kernel/util/shim_utils.cc @@ -8,7 +8,7 @@ */ #include "xenia/kernel/util/shim_utils.h" - +#include "xenia/kernel/xthread.h" namespace xe { namespace kernel { namespace shim { @@ -17,6 +17,10 @@ thread_local StringBuffer string_buffer_; StringBuffer* thread_local_string_buffer() { return &string_buffer_; } +XThread* ContextParam::CurrentXThread() const { + return XThread::GetCurrentThread(); +} + } // namespace shim } // namespace kernel } // namespace xe diff --git a/src/xenia/kernel/util/shim_utils.h b/src/xenia/kernel/util/shim_utils.h index 20c677f91..adb8bf450 100644 --- a/src/xenia/kernel/util/shim_utils.h +++ b/src/xenia/kernel/util/shim_utils.h @@ -203,8 +203,21 @@ class ContextParam : public Param { PPCContext* operator->() const { return ctx_; } + template + inline T TranslateVirtual(uint32_t guest_addr) const { + return ctx_->TranslateVirtual(guest_addr); + } + + template + inline T TranslateGPR(uint32_t which_gpr) const { + return ctx_->TranslateVirtualGPR(ctx_->r[which_gpr]); + } + + X_KPCR* GetPCR() const { return TranslateGPR(13); } + + XThread* CurrentXThread() const; protected: - PPCContext* ctx_; + PPCContext* XE_RESTRICT ctx_; }; class PointerParam : public ParamBase { diff --git a/src/xenia/kernel/xam/xam_content.cc b/src/xenia/kernel/xam/xam_content.cc index c6fe73d4b..1b0b9c844 100644 --- a/src/xenia/kernel/xam/xam_content.cc +++ b/src/xenia/kernel/xam/xam_content.cc @@ -475,7 +475,7 @@ dword_result_t XamSwapDisc_entry( completion_event(); return X_ERROR_SUCCESS; } - + auto filesystem = kernel_state()->file_system(); auto mount_path = "\\Device\\LauncherData"; @@ -498,6 +498,14 @@ dword_result_t XamSwapDisc_entry( } DECLARE_XAM_EXPORT1(XamSwapDisc, kContent, kSketchy); +dword_result_t XamLoaderGetMediaInfoEx_entry(dword_t unk1, dword_t unk2, + lpdword_t unk3) { + *unk3 = 0; + return 0; +} + +DECLARE_XAM_EXPORT1(XamLoaderGetMediaInfoEx, kContent, kStub); + } // namespace xam } // namespace kernel } // namespace xe diff --git a/src/xenia/kernel/xam/xam_ui.cc b/src/xenia/kernel/xam/xam_ui.cc index 11cd8faa7..30fb57bc6 100644 --- a/src/xenia/kernel/xam/xam_ui.cc +++ b/src/xenia/kernel/xam/xam_ui.cc @@ -529,6 +529,22 @@ dword_result_t XamShowCommunitySessionsUI_entry(unknown_t r3, unknown_t r4) { } DECLARE_XAM_EXPORT1(XamShowCommunitySessionsUI, kNone, kStub); +// this is supposed to do a lot more, calls another function that triggers some +// cbs +dword_result_t XamSetDashContext_entry(dword_t value, + const ppc_context_t& ctx) { + ctx->kernel_state->dash_context_ = value; + return 0; +} + +DECLARE_XAM_EXPORT1(XamSetDashContext, kNone, kImplemented); + +dword_result_t XamGetDashContext_entry(const ppc_context_t& ctx) { + return ctx->kernel_state->dash_context_; +} + +DECLARE_XAM_EXPORT1(XamGetDashContext, kNone, kImplemented); + } // namespace xam } // namespace kernel } // namespace xe diff --git a/src/xenia/kernel/xam/xam_user.cc b/src/xenia/kernel/xam/xam_user.cc index 32abc65fc..4ba177c38 100644 --- a/src/xenia/kernel/xam/xam_user.cc +++ b/src/xenia/kernel/xam/xam_user.cc @@ -808,6 +808,28 @@ dword_result_t XamSessionRefObjByHandle_entry(dword_t handle, } DECLARE_XAM_EXPORT1(XamSessionRefObjByHandle, kUserProfiles, kStub); +dword_result_t XamUserIsUnsafeProgrammingAllowed_entry(dword_t unk1, dword_t unk2, + lpdword_t unk3, dword_t unk4, + dword_t unk5, dword_t unk6) { + if (!unk3 || unk1 != 255 && unk1 >= 4) { + return 87; + } + *unk3 = 1; + return 0; +} +DECLARE_XAM_EXPORT1(XamUserIsUnsafeProgrammingAllowed, kUserProfiles, kStub); + +dword_result_t XamUserGetSubscriptionType_entry(dword_t user_index, dword_t unk2, + dword_t unk3, dword_t unk4, + dword_t unk5, dword_t unk6) { + if (!unk2 || !unk3 || user_index > 4) { + return 0x80070057; + } + + return 0; +} +DECLARE_XAM_EXPORT1(XamUserGetSubscriptionType, kUserProfiles, kStub); + } // namespace xam } // namespace kernel } // namespace xe diff --git a/src/xenia/kernel/xboxkrnl/xboxkrnl_memory.cc b/src/xenia/kernel/xboxkrnl/xboxkrnl_memory.cc index 53f48b2b5..692f56e89 100644 --- a/src/xenia/kernel/xboxkrnl/xboxkrnl_memory.cc +++ b/src/xenia/kernel/xboxkrnl/xboxkrnl_memory.cc @@ -632,9 +632,30 @@ void ExFreePool_entry(lpvoid_t base_address) { } DECLARE_XBOXKRNL_EXPORT1(ExFreePool, kMemory, kImplemented); -dword_result_t KeGetImagePageTableEntry_entry(lpvoid_t address) { - // Unknown - return 1; +// hv syscall 15, jumps into (bootloader function table??) alternative table ptr +// offset 224 +// this is not a correct implementation. i just wanted to get it to return a +// value thats in the same range as the hv's values that kind of reflects the +// pages index and heap +dword_result_t KeGetImagePageTableEntry_entry(dword_t address, + const ppc_context_t& ctx) { + auto kernel_state = ctx->kernel_state; + xe::BaseHeap* image_heap = kernel_state->memory()->LookupHeap(address); + if (image_heap->heap_type() != HeapType::kGuestXex) { + return 0; + } + uint32_t returned_value = address - image_heap->heap_base(); + + // todo: its always a power of two, should shift + returned_value /= image_heap->page_size(); + + if (image_heap->page_size() < 65536) { + returned_value |= 0x40000000; + } + + return returned_value & 0x400FFFFF; // this is actually the mask it applies + // to the final + // result before returning it } DECLARE_XBOXKRNL_EXPORT1(KeGetImagePageTableEntry, kMemory, kStub); diff --git a/src/xenia/kernel/xboxkrnl/xboxkrnl_ob.cc b/src/xenia/kernel/xboxkrnl/xboxkrnl_ob.cc index f7f0308e8..01700c3ad 100644 --- a/src/xenia/kernel/xboxkrnl/xboxkrnl_ob.cc +++ b/src/xenia/kernel/xboxkrnl/xboxkrnl_ob.cc @@ -83,12 +83,25 @@ dword_result_t ObLookupThreadByThreadId_entry(dword_t thread_id, return X_STATUS_SUCCESS; } DECLARE_XBOXKRNL_EXPORT1(ObLookupThreadByThreadId, kNone, kImplemented); + +template +static constexpr uint32_t object_type_id_for_ordinal_v = + 0xD000BEEF | (ordinal << 16); // These values come from how Xenia handles uninitialized kernel data exports. // D###BEEF where ### is the ordinal. const static std::unordered_map object_types = { - {XObject::Type::Event, 0xD00EBEEF}, - {XObject::Type::Semaphore, 0xD017BEEF}, - {XObject::Type::Thread, 0xD01BBEEF}}; + {XObject::Type::Event, + object_type_id_for_ordinal_v}, + {XObject::Type::Semaphore, + object_type_id_for_ordinal_v}, + {XObject::Type::Thread, + object_type_id_for_ordinal_v}, + {XObject::Type::File, + object_type_id_for_ordinal_v}, + {XObject::Type::Mutant, + object_type_id_for_ordinal_v}, + {XObject::Type::Device, + object_type_id_for_ordinal_v}}; dword_result_t ObReferenceObjectByHandle_entry(dword_t handle, dword_t object_type_ptr, lpdword_t out_object_ptr) { @@ -113,6 +126,8 @@ dword_result_t ObReferenceObjectByHandle_entry(dword_t handle, // Caller takes the reference. // It's released in ObDereferenceObject. object->RetainHandle(); + + xenia_assert(native_ptr != 0); if (out_object_ptr.guest_address()) { *out_object_ptr = native_ptr; } @@ -120,14 +135,17 @@ dword_result_t ObReferenceObjectByHandle_entry(dword_t handle, } DECLARE_XBOXKRNL_EXPORT1(ObReferenceObjectByHandle, kNone, kImplemented); -dword_result_t ObReferenceObjectByName_entry(lpstring_t name, +dword_result_t ObReferenceObjectByName_entry(pointer_t name, dword_t attributes, dword_t object_type_ptr, lpvoid_t parse_context, - lpdword_t out_object_ptr) { + lpdword_t out_object_ptr, + const ppc_context_t& ctx) { X_HANDLE handle = X_INVALID_HANDLE_VALUE; + + char* name_str = ctx.TranslateVirtual(name->pointer); X_STATUS result = - kernel_state()->object_table()->GetObjectByName(name.value(), &handle); + kernel_state()->object_table()->GetObjectByName(name_str, &handle); if (XSUCCEEDED(result)) { return ObReferenceObjectByHandle_entry(handle, object_type_ptr, out_object_ptr); @@ -142,6 +160,10 @@ void ObDereferenceObject_entry(dword_t native_ptr, const ppc_context_t& ctx) { if (native_ptr == 0xDEADF00D) { return; } + if (!native_ptr) { + XELOGE("Null native ptr in ObDereferenceObject!"); + return; + } auto object = XObject::GetNativeObject( kernel_state(), kernel_memory()->TranslateVirtual(native_ptr)); diff --git a/src/xenia/kernel/xboxkrnl/xboxkrnl_threading.cc b/src/xenia/kernel/xboxkrnl/xboxkrnl_threading.cc index 6fbf2b0be..104b6bbf5 100644 --- a/src/xenia/kernel/xboxkrnl/xboxkrnl_threading.cc +++ b/src/xenia/kernel/xboxkrnl/xboxkrnl_threading.cc @@ -245,7 +245,7 @@ void KeSetCurrentStackPointers_entry(lpvoid_t stack_ptr, pcr->stack_base_ptr = stack_base.guest_address(); pcr->stack_end_ptr = stack_limit.guest_address(); context->r[1] = stack_ptr.guest_address(); - + // If a fiber is set, and the thread matches, reenter to avoid issues with // host stack overflowing. if (thread->fiber_ptr && @@ -337,8 +337,8 @@ DECLARE_XBOXKRNL_EXPORT2(KeQueryPerformanceFrequency, kThreading, kImplemented, kHighFrequency); uint32_t KeDelayExecutionThread(uint32_t processor_mode, - uint32_t alertable, - uint64_t* interval_ptr) { + uint32_t alertable, + uint64_t* interval_ptr) { XThread* thread = XThread::GetCurrentThread(); X_STATUS result = thread->Delay(processor_mode, alertable, *interval_ptr); @@ -521,7 +521,7 @@ uint32_t xeNtSetEvent(uint32_t handle, xe::be* previous_state_ptr) { //d3 ros does this if (ev->type() != XObject::Type::Event) { return X_STATUS_OBJECT_TYPE_MISMATCH; - } + } int32_t was_signalled = ev->Set(0, false); if (previous_state_ptr) { *previous_state_ptr = static_cast(was_signalled); @@ -746,7 +746,7 @@ dword_result_t NtReleaseMutant_entry(dword_t mutant_handle, dword_t unknown) { auto mutant = kernel_state()->object_table()->LookupObject(mutant_handle); if (mutant) { - result = mutant->ReleaseMutant(priority_increment, abandon, wait); + mutant->ReleaseMutant(priority_increment, abandon, wait); } else { result = X_STATUS_INVALID_HANDLE; } @@ -992,11 +992,7 @@ dword_result_t NtSignalAndWaitForSingleObjectEx_entry(dword_t signal_handle, DECLARE_XBOXKRNL_EXPORT3(NtSignalAndWaitForSingleObjectEx, kThreading, kImplemented, kBlocking, kHighFrequency); -static void PrefetchForCAS(const void* value) { - if (amd64::GetFeatureFlags() & amd64::kX64EmitPrefetchW) { - swcache::PrefetchW(value); - } -} +static void PrefetchForCAS(const void* value) { swcache::PrefetchW(value); } uint32_t xeKeKfAcquireSpinLock(uint32_t* lock, uint64_t r13 = 1) { // XELOGD( @@ -1111,21 +1107,58 @@ void KeLeaveCriticalRegion_entry() { DECLARE_XBOXKRNL_EXPORT2(KeLeaveCriticalRegion, kThreading, kImplemented, kHighFrequency); -dword_result_t KeRaiseIrqlToDpcLevel_entry() { - auto old_value = kernel_state()->processor()->RaiseIrql(cpu::Irql::DPC); - return (uint32_t)old_value; +dword_result_t KeRaiseIrqlToDpcLevel_entry(const ppc_context_t& ctx) { + auto pcr = ctx.GetPCR(); + uint32_t old_irql = pcr->current_irql; + + if (old_irql > 2) { + XELOGE("KeRaiseIrqlToDpcLevel - old_irql > 2"); + } + + pcr->current_irql = 2; + + return old_irql; } DECLARE_XBOXKRNL_EXPORT2(KeRaiseIrqlToDpcLevel, kThreading, kImplemented, kHighFrequency); -void KfLowerIrql_entry(dword_t old_value) { - kernel_state()->processor()->LowerIrql( - static_cast((uint32_t)old_value)); +// irql is supposed to be per thread afaik... +void KfLowerIrql_entry(dword_t new_irql, const ppc_context_t& ctx) { + X_KPCR* kpcr = ctx.GetPCR(); - XThread::GetCurrentThread()->CheckApcs(); + if (new_irql > kpcr->current_irql) { + XELOGE("KfLowerIrql : new_irql > kpcr->current_irql!"); + } + kpcr->current_irql = new_irql; + if (new_irql < 2) { + { + // this actually calls a function that eventually calls checkapcs. + // the called function does a ton of other stuff including changing the + // irql and interrupt_related + ctx.CurrentXThread()->CheckApcs(); + } + } } DECLARE_XBOXKRNL_EXPORT2(KfLowerIrql, kThreading, kImplemented, kHighFrequency); +// used by aurora's nova plugin +// like the other irql related functions, writes to an unknown mmio range ( +// 0x7FFF ). The range is indexed by the low 16 bits of the KPCR's pointer (so +// r13) +dword_result_t KfRaiseIrql_entry(dword_t new_irql, const ppc_context_t& ctx) { + X_KPCR* v1 = ctx.GetPCR(); + + uint32_t old_irql = v1->current_irql; + v1->current_irql = new_irql; + + if (old_irql > (unsigned int)new_irql) { + XELOGE("KfRaiseIrql - old_irql > new_irql!"); + } + return old_irql; +} + +DECLARE_XBOXKRNL_EXPORT2(KfRaiseIrql, kThreading, kImplemented, kHighFrequency); + void NtQueueApcThread_entry(dword_t thread_handle, lpvoid_t apc_routine, lpvoid_t apc_routine_context, lpvoid_t arg1, lpvoid_t arg2) { diff --git a/src/xenia/kernel/xobject.h b/src/xenia/kernel/xobject.h index ad693fa79..b42c0ffbd 100644 --- a/src/xenia/kernel/xobject.h +++ b/src/xenia/kernel/xobject.h @@ -134,6 +134,7 @@ class XObject { SymbolicLink, Thread, Timer, + Device }; XObject(Type type); diff --git a/src/xenia/kernel/xthread.h b/src/xenia/kernel/xthread.h index 15c5d8a0e..7f72a7e14 100644 --- a/src/xenia/kernel/xthread.h +++ b/src/xenia/kernel/xthread.h @@ -71,7 +71,10 @@ struct XAPC { struct X_KPCR { xe::be tls_ptr; // 0x0 xe::be msr_mask; // 0x4 - uint8_t unk_08[0x28]; // 0x8 + xe::be interrupt_related; // 0x8 + uint8_t unk_08[0xE]; // 0xA + uint8_t current_irql; // 0x18 + uint8_t unk_19[0x17]; // 0x19 xe::be pcr_ptr; // 0x30 uint8_t unk_34[0x38]; // 0x34 xe::be use_alternative_stack; //0x6C