From 9b3601c6fa62922479076f0037300f7fd37f8e0c Mon Sep 17 00:00:00 2001 From: disjtqz Date: Sat, 14 Oct 2023 15:48:32 -0400 Subject: [PATCH] [Kernel] add object type stub functions, export object types --- src/xenia/kernel/kernel_state.cc | 182 ++++++++++++++++++- src/xenia/kernel/kernel_state.h | 46 ++++- src/xenia/kernel/xboxkrnl/xboxkrnl_module.cc | 17 ++ src/xenia/kernel/xboxkrnl/xboxkrnl_ob.cc | 30 +-- src/xenia/kernel/xboxkrnl/xboxkrnl_ob.h | 24 +++ src/xenia/xbox.h | 6 + 6 files changed, 277 insertions(+), 28 deletions(-) create mode 100644 src/xenia/kernel/xboxkrnl/xboxkrnl_ob.h diff --git a/src/xenia/kernel/kernel_state.cc b/src/xenia/kernel/kernel_state.cc index f22c9970e..b4d461fbd 100644 --- a/src/xenia/kernel/kernel_state.cc +++ b/src/xenia/kernel/kernel_state.cc @@ -22,7 +22,9 @@ #include "xenia/kernel/user_module.h" #include "xenia/kernel/util/shim_utils.h" #include "xenia/kernel/xam/xam_module.h" +#include "xenia/kernel/xboxkrnl/xboxkrnl_memory.h" #include "xenia/kernel/xboxkrnl/xboxkrnl_module.h" +#include "xenia/kernel/xboxkrnl/xboxkrnl_ob.h" #include "xenia/kernel/xboxkrnl/xboxkrnl_threading.h" #include "xenia/kernel/xevent.h" #include "xenia/kernel/xmodule.h" @@ -48,7 +50,10 @@ KernelState::KernelState(Emulator* emulator) : emulator_(emulator), memory_(emulator->memory()), dispatch_thread_running_(false), - dpc_list_(emulator->memory()) { + dpc_list_(emulator->memory()), + kernel_trampoline_group_(emulator->processor()->backend()) { + assert_null(shared_kernel_state_); + shared_kernel_state_ = this; processor_ = emulator->processor(); file_system_ = emulator->file_system(); @@ -64,9 +69,6 @@ KernelState::KernelState(Emulator* emulator) } content_manager_ = std::make_unique(this, content_root); - assert_null(shared_kernel_state_); - shared_kernel_state_ = this; - // Hardcoded maximum of 2048 TLS slots. tls_bitmap_.Resize(2048); @@ -1148,6 +1150,64 @@ void KernelState::SetProcessTLSVars(X_KPROCESS* process, int num_slots, if (((num_slots + 3) & 0x1C) != 0) process->bitmap[count_div32] = -1 << (32 - ((num_slots + 3) & 0x1C)); } +void AllocateThread(PPCContext* context) { + uint32_t thread_mem_size = static_cast(context->r[3]); + uint32_t a2 = static_cast(context->r[4]); + uint32_t a3 = static_cast(context->r[5]); + if (thread_mem_size <= 0xFD8) thread_mem_size += 8; + uint32_t result = + xboxkrnl::xeAllocatePoolTypeWithTag(context, thread_mem_size, a2, a3); + if (((unsigned short)result & 0xFFF) != 0) { + result += 2; + } + + context->r[3] = static_cast(result); +} +void FreeThread(PPCContext* context) { + uint32_t thread_memory = static_cast(context->r[3]); + if ((thread_memory & 0xFFF) != 0) { + thread_memory -= 8; + } + xboxkrnl::xeFreePool(context, thread_memory); +} + +void SimpleForwardAllocatePoolTypeWithTag(PPCContext* context) { + uint32_t a1 = static_cast(context->r[3]); + uint32_t a2 = static_cast(context->r[4]); + uint32_t a3 = static_cast(context->r[5]); + context->r[3] = static_cast( + xboxkrnl::xeAllocatePoolTypeWithTag(context, a1, a2, a3)); +} +void SimpleForwardFreePool(PPCContext* context) { + xboxkrnl::xeFreePool(context, static_cast(context->r[3])); +} + +void DeleteMutant(PPCContext* context) { + // todo: this should call kereleasemutant with some specific args + + xe::FatalError("DeleteMutant - need KeReleaseMutant(mutant, 1, 1, 0) "); +} +void DeleteTimer(PPCContext* context) { + // todo: this should call KeCancelTimer + xe::FatalError("DeleteTimer - need KeCancelTimer(mutant, 1, 1, 0) "); +} + +void DeleteIoCompletion(PPCContext* context) {} + +void UnknownProcIoDevice(PPCContext* context) {} + +void CloseFileProc(PPCContext* context) {} + +void DeleteFileProc(PPCContext* context) {} + +void UnknownFileProc(PPCContext* context) {} + +void DeleteSymlink(PPCContext* context) { + X_KSYMLINK* lnk = context->TranslateVirtualGPR(context->r[3]); + + context->r[3] = lnk->refed_object_maybe; + xboxkrnl::xeObDereferenceObject(context, lnk->refed_object_maybe); +} void KernelState::InitializeKernelGuestGlobals() { kernel_guest_globals_ = memory_->SystemHeapAlloc(sizeof(KernelGuestGlobals)); @@ -1162,6 +1222,120 @@ void KernelState::InitializeKernelGuestGlobals() { memory()->TranslateVirtual(GetSystemProcess()); InitializeProcess(system_process, X_PROCTYPE_SYSTEM, 2, 5, 9); SetProcessTLSVars(system_process, 32, 0, 0); + + uint32_t oddobject_offset = + kernel_guest_globals_ + offsetof(KernelGuestGlobals, OddObj); + + // init unknown object + + block->OddObj.field0 = 0x1000000; + block->OddObj.field4 = 1; + block->OddObj.points_to_self = + oddobject_offset + offsetof(X_UNKNOWN_TYPE_REFED, points_to_self); + block->OddObj.points_to_prior = block->OddObj.points_to_self; + + // init thread object + block->ExThreadObjectType.pool_tag = 0x65726854; + block->ExThreadObjectType.allocate_proc = + kernel_trampoline_group_.NewLongtermTrampoline(AllocateThread); + + block->ExThreadObjectType.free_proc = + kernel_trampoline_group_.NewLongtermTrampoline(FreeThread); + + // several object types just call freepool/allocatepool + uint32_t trampoline_allocatepool = + kernel_trampoline_group_.NewLongtermTrampoline( + SimpleForwardAllocatePoolTypeWithTag); + uint32_t trampoline_freepool = + kernel_trampoline_group_.NewLongtermTrampoline(SimpleForwardFreePool); + + // init event object + block->ExEventObjectType.pool_tag = 0x76657645; + block->ExEventObjectType.allocate_proc = trampoline_allocatepool; + block->ExEventObjectType.free_proc = trampoline_freepool; + + // init mutant object + block->ExMutantObjectType.pool_tag = 0x6174754D; + block->ExMutantObjectType.allocate_proc = trampoline_allocatepool; + block->ExMutantObjectType.free_proc = trampoline_freepool; + + block->ExMutantObjectType.delete_proc = + kernel_trampoline_group_.NewLongtermTrampoline(DeleteMutant); + // init semaphore obj + block->ExSemaphoreObjectType.pool_tag = 0x616D6553; + block->ExSemaphoreObjectType.allocate_proc = trampoline_allocatepool; + block->ExSemaphoreObjectType.free_proc = trampoline_freepool; + // init timer obj + block->ExTimerObjectType.pool_tag = 0x656D6954; + block->ExTimerObjectType.allocate_proc = trampoline_allocatepool; + block->ExTimerObjectType.free_proc = trampoline_freepool; + block->ExTimerObjectType.delete_proc = + kernel_trampoline_group_.NewLongtermTrampoline(DeleteTimer); + // iocompletion object + block->IoCompletionObjectType.pool_tag = 0x706D6F43; + block->IoCompletionObjectType.allocate_proc = trampoline_allocatepool; + block->IoCompletionObjectType.free_proc = trampoline_freepool; + block->IoCompletionObjectType.delete_proc = + kernel_trampoline_group_.NewLongtermTrampoline(DeleteIoCompletion); + block->IoCompletionObjectType.unknown_size_or_object_ = oddobject_offset; + + // iodevice object + block->IoDeviceObjectType.pool_tag = 0x69766544; + block->IoDeviceObjectType.allocate_proc = trampoline_allocatepool; + block->IoDeviceObjectType.free_proc = trampoline_freepool; + block->IoDeviceObjectType.unknown_size_or_object_ = oddobject_offset; + block->IoDeviceObjectType.unknown_proc = + kernel_trampoline_group_.NewLongtermTrampoline(UnknownProcIoDevice); + + // file object + block->IoFileObjectType.pool_tag = 0x656C6946; + block->IoFileObjectType.allocate_proc = trampoline_allocatepool; + block->IoFileObjectType.free_proc = trampoline_freepool; + block->IoFileObjectType.unknown_size_or_object_ = + 0x38; // sizeof fileobject, i believe + block->IoFileObjectType.close_proc = + kernel_trampoline_group_.NewLongtermTrampoline(CloseFileProc); + block->IoFileObjectType.delete_proc = + kernel_trampoline_group_.NewLongtermTrampoline(DeleteFileProc); + block->IoFileObjectType.unknown_proc = + kernel_trampoline_group_.NewLongtermTrampoline(UnknownFileProc); + + // directory object + block->ObDirectoryObjectType.pool_tag = 0x65726944; + block->ObDirectoryObjectType.allocate_proc = trampoline_allocatepool; + block->ObDirectoryObjectType.free_proc = trampoline_freepool; + block->ObDirectoryObjectType.unknown_size_or_object_ = oddobject_offset; + + // symlink object + block->ObSymbolicLinkObjectType.pool_tag = 0x626D7953; + block->ObSymbolicLinkObjectType.allocate_proc = trampoline_allocatepool; + block->ObSymbolicLinkObjectType.free_proc = trampoline_freepool; + block->ObSymbolicLinkObjectType.unknown_size_or_object_ = oddobject_offset; + block->ObSymbolicLinkObjectType.delete_proc = + kernel_trampoline_group_.NewLongtermTrampoline(DeleteSymlink); + +#define offsetof32(s, m) static_cast( offsetof(s, m) ) + + host_object_type_enum_to_guest_object_type_ptr_ = { + {XObject::Type::Event, + kernel_guest_globals_ + + offsetof32(KernelGuestGlobals, ExEventObjectType)}, + {XObject::Type::Semaphore, + kernel_guest_globals_ + + offsetof32(KernelGuestGlobals, ExSemaphoreObjectType)}, + {XObject::Type::Thread, + kernel_guest_globals_ + + offsetof32(KernelGuestGlobals, ExThreadObjectType)}, + {XObject::Type::File, + kernel_guest_globals_ + + offsetof32(KernelGuestGlobals, IoFileObjectType)}, + {XObject::Type::Mutant, + kernel_guest_globals_ + + offsetof32(KernelGuestGlobals, ExMutantObjectType)}, + {XObject::Type::Device, + kernel_guest_globals_ + + offsetof32(KernelGuestGlobals, IoDeviceObjectType)}}; + xboxkrnl::xeKeSetEvent(&block->UsbdBootEnumerationDoneEvent, 1, 0); } } // namespace kernel } // namespace xe diff --git a/src/xenia/kernel/kernel_state.h b/src/xenia/kernel/kernel_state.h index 61ab21dc0..dde6bd02b 100644 --- a/src/xenia/kernel/kernel_state.h +++ b/src/xenia/kernel/kernel_state.h @@ -21,6 +21,7 @@ #include "xenia/base/bit_map.h" #include "xenia/base/cvar.h" #include "xenia/base/mutex.h" +#include "xenia/cpu/backend/backend.h" #include "xenia/cpu/export_resolver.h" #include "xenia/kernel/util/kernel_fwd.h" #include "xenia/kernel/util/native_list.h" @@ -29,6 +30,7 @@ #include "xenia/kernel/xam/app_manager.h" #include "xenia/kernel/xam/content_manager.h" #include "xenia/kernel/xam/user_profile.h" +#include "xenia/kernel/xevent.h" #include "xenia/memory.h" #include "xenia/vfs/virtual_file_system.h" #include "xenia/xbox.h" @@ -83,7 +85,6 @@ struct X_KPROCESS { }; static_assert_size(X_KPROCESS, 0x60); - struct TerminateNotification { uint32_t guest_routine; uint32_t priority; @@ -99,13 +100,46 @@ struct X_TIME_STAMP_BUNDLE { uint32_t tick_count; uint32_t padding; }; - +struct X_UNKNOWN_TYPE_REFED { + xe::be field0; + xe::be field4; + // this is definitely a LIST_ENTRY? + xe::be points_to_self; // this field points to itself + xe::be + points_to_prior; // points to the previous field, which points to itself +}; +static_assert_size(X_UNKNOWN_TYPE_REFED, 16); struct KernelGuestGlobals { - X_KPROCESS idle_process; // X_PROCTYPE_IDLE. runs in interrupt contexts. is also the context the kernel starts in? + X_OBJECT_TYPE ExThreadObjectType; + X_OBJECT_TYPE ExEventObjectType; + X_OBJECT_TYPE ExMutantObjectType; + X_OBJECT_TYPE ExSemaphoreObjectType; + X_OBJECT_TYPE ExTimerObjectType; + X_OBJECT_TYPE IoCompletionObjectType; + X_OBJECT_TYPE IoDeviceObjectType; + X_OBJECT_TYPE IoFileObjectType; + X_OBJECT_TYPE ObDirectoryObjectType; + X_OBJECT_TYPE ObSymbolicLinkObjectType; + // a constant buffer that some object types' "unknown_size_or_object" field + // points to + X_UNKNOWN_TYPE_REFED OddObj; + X_KPROCESS idle_process; // X_PROCTYPE_IDLE. runs in interrupt contexts. is + // also the context the kernel starts in? X_KPROCESS title_process; // X_PROCTYPE_TITLE X_KPROCESS system_process; // X_PROCTYPE_SYSTEM. no idea when this runs. can // create threads in this process with // ExCreateThread and the thread flag 0x2 + + // locks. + X_KSPINLOCK dispatcher_lock; // called the "dispatcher lock" in nt 3.5 ppc + // .dbg file. Used basically everywhere that + // DISPATCHER_HEADER'd objects appear + // this lock is only used in some Ob functions. It's odd that it is used at + // all, as each table already has its own spinlock. + X_KSPINLOCK ob_lock; + + // if LLE emulating Xam, this is needed or you get an immediate freeze + X_KEVENT UsbdBootEnumerationDoneEvent; }; struct DPCImpersonationScope { uint8_t previous_irql_; @@ -318,13 +352,17 @@ class KernelState { BitMap tls_bitmap_; uint32_t ke_timestamp_bundle_ptr_ = 0; std::unique_ptr timestamp_timer_; + cpu::backend::GuestTrampolineGroup kernel_trampoline_group_; //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: + public: uint32_t dash_context_ = 0; + std::unordered_map + host_object_type_enum_to_guest_object_type_ptr_; + uint32_t GetKernelGuestGlobals() const { return kernel_guest_globals_; } }; } // namespace kernel diff --git a/src/xenia/kernel/xboxkrnl/xboxkrnl_module.cc b/src/xenia/kernel/xboxkrnl/xboxkrnl_module.cc index fd4fe805b..78f82db06 100644 --- a/src/xenia/kernel/xboxkrnl/xboxkrnl_module.cc +++ b/src/xenia/kernel/xboxkrnl/xboxkrnl_module.cc @@ -218,6 +218,23 @@ XboxkrnlModule::XboxkrnlModule(Emulator* emulator, KernelState* kernel_state) export_resolver_->SetVariableMapping("xboxkrnl.exe", ordinals::KeTimeStampBundle, kernel_state->GetKeTimestampBundle()); +#define EXPORT_KVAR(typ) \ + export_resolver_->SetVariableMapping("xboxkrnl.exe", ordinals::typ, \ + kernel_state->GetKernelGuestGlobals() + \ + offsetof(KernelGuestGlobals, typ)) + + EXPORT_KVAR(ExThreadObjectType); + EXPORT_KVAR(ExEventObjectType); + EXPORT_KVAR(ExMutantObjectType); + EXPORT_KVAR(ExSemaphoreObjectType); + EXPORT_KVAR(ExTimerObjectType); + EXPORT_KVAR(IoCompletionObjectType); + EXPORT_KVAR(IoDeviceObjectType); + EXPORT_KVAR(IoFileObjectType); + EXPORT_KVAR(ObDirectoryObjectType); + EXPORT_KVAR(ObSymbolicLinkObjectType); + EXPORT_KVAR(UsbdBootEnumerationDoneEvent); +#undef EXPORT_KVAR } static auto& get_xboxkrnl_exports() { diff --git a/src/xenia/kernel/xboxkrnl/xboxkrnl_ob.cc b/src/xenia/kernel/xboxkrnl/xboxkrnl_ob.cc index 3dbef4046..1f0753061 100644 --- a/src/xenia/kernel/xboxkrnl/xboxkrnl_ob.cc +++ b/src/xenia/kernel/xboxkrnl/xboxkrnl_ob.cc @@ -12,6 +12,7 @@ #include "xenia/kernel/kernel_state.h" #include "xenia/kernel/util/shim_utils.h" #include "xenia/kernel/xboxkrnl/xboxkrnl_private.h" +#include "xenia/kernel/xboxkrnl/xboxkrnl_ob.h" #include "xenia/kernel/xobject.h" #include "xenia/kernel/xsemaphore.h" #include "xenia/kernel/xthread.h" @@ -90,24 +91,6 @@ dword_result_t ObLookupAnyThreadByThreadId_entry(dword_t thread_id, } DECLARE_XBOXKRNL_EXPORT1(ObLookupAnyThreadByThreadId, 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, - 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) { @@ -120,6 +103,8 @@ dword_result_t ObReferenceObjectByHandle_entry(dword_t handle, } uint32_t native_ptr = object->guest_object(); + auto& object_types = + kernel_state()->host_object_type_enum_to_guest_object_type_ptr_; auto object_type = object_types.find(object->type()); if (object_type != object_types.end()) { if (object_type_ptr && object_type_ptr != object_type->second) { @@ -161,7 +146,7 @@ dword_result_t ObReferenceObjectByName_entry(pointer_t name, } DECLARE_XBOXKRNL_EXPORT1(ObReferenceObjectByName, kNone, kImplemented); -void ObDereferenceObject_entry(dword_t native_ptr, const ppc_context_t& ctx) { +void xeObDereferenceObject(PPCContext* context, uint32_t native_ptr) { // Check if a dummy value from ObReferenceObjectByHandle. if (native_ptr == 0xDEADF00D) { return; @@ -179,11 +164,16 @@ void ObDereferenceObject_entry(dword_t native_ptr, const ppc_context_t& ctx) { } else { if (native_ptr) { XELOGW("Unregistered guest object provided to ObDereferenceObject {:08X}", - native_ptr.value()); + native_ptr); } } return; } + + +void ObDereferenceObject_entry(dword_t native_ptr, const ppc_context_t& ctx) { + xeObDereferenceObject(ctx, native_ptr); +} DECLARE_XBOXKRNL_EXPORT1(ObDereferenceObject, kNone, kImplemented); void ObReferenceObject_entry(dword_t native_ptr) { diff --git a/src/xenia/kernel/xboxkrnl/xboxkrnl_ob.h b/src/xenia/kernel/xboxkrnl/xboxkrnl_ob.h new file mode 100644 index 000000000..7d5afb4d9 --- /dev/null +++ b/src/xenia/kernel/xboxkrnl/xboxkrnl_ob.h @@ -0,0 +1,24 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2023 Xenia Canary. All rights reserved. * Released under the BSD + *license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef XENIA_KERNEL_XBOXKRNL_XBOXKRNL_OB_H_ +#define XENIA_KERNEL_XBOXKRNL_XBOXKRNL_OB_H_ + +#include "xenia/kernel/util/shim_utils.h" + +namespace xe { +namespace kernel { +namespace xboxkrnl { +void xeObDereferenceObject(PPCContext* context, uint32_t native_ptr); + +} // namespace xboxkrnl +} // namespace kernel +} // namespace xe + +#endif // XENIA_KERNEL_XBOXKRNL_XBOXKRNL_OB_H_ diff --git a/src/xenia/xbox.h b/src/xenia/xbox.h index 70ef8486d..ccf88faff 100644 --- a/src/xenia/xbox.h +++ b/src/xenia/xbox.h @@ -368,6 +368,12 @@ struct X_OBJECT_TYPE { xe::be pool_tag; // 0x18 }; static_assert_size(X_OBJECT_TYPE, 0x1C); + +struct X_KSYMLINK { + xe::be refed_object_maybe; + X_ANSI_STRING refed_object_name_maybe; +}; +static_assert_size(X_KSYMLINK, 0xC); // https://msdn.microsoft.com/en-us/library/windows/desktop/aa363082.aspx typedef struct { // Renamed due to a collision with exception_code from Windows excpt.h.