From ee424ae14a18c130c8038ea7bb402c900c9cdd9d Mon Sep 17 00:00:00 2001 From: disjtqz Date: Fri, 13 Oct 2023 15:04:01 -0400 Subject: [PATCH] [Kernel] nonintrusive guest to host object mapping --- src/xenia/kernel/util/kernel_fwd.h | 2 - src/xenia/kernel/util/object_table.cc | 25 +++++++++ src/xenia/kernel/util/object_table.h | 4 ++ src/xenia/kernel/xobject.cc | 46 ++++++++-------- src/xenia/kernel/xobject.h | 38 +------------- .../xcontent_devices/stfs_container_device.cc | 2 +- src/xenia/xbox.h | 52 ++++++++++++++++++- 7 files changed, 106 insertions(+), 63 deletions(-) diff --git a/src/xenia/kernel/util/kernel_fwd.h b/src/xenia/kernel/util/kernel_fwd.h index 4dff6c2ac..7e1ed788a 100644 --- a/src/xenia/kernel/util/kernel_fwd.h +++ b/src/xenia/kernel/util/kernel_fwd.h @@ -17,9 +17,7 @@ struct XAPC; struct X_KPCR; struct X_KTHREAD; -struct X_OBJECT_HEADER; struct X_OBJECT_CREATE_INFORMATION; -struct X_OBJECT_TYPE; } // namespace xe::kernel diff --git a/src/xenia/kernel/util/object_table.cc b/src/xenia/kernel/util/object_table.cc index 4568c72d1..ad3652e16 100644 --- a/src/xenia/kernel/util/object_table.cc +++ b/src/xenia/kernel/util/object_table.cc @@ -479,6 +479,31 @@ X_STATUS ObjectTable::RestoreHandle(X_HANDLE handle, XObject* object) { return X_STATUS_SUCCESS; } +void ObjectTable::MapGuestObjectToHostHandle(uint32_t guest_object, + X_HANDLE host_handle) { + auto global_lock = global_critical_region_.Acquire(); + guest_to_host_handle_[guest_object] = host_handle; +} +bool ObjectTable::HostHandleForGuestObject(uint32_t guest_object, X_HANDLE& out) { + auto global_lock = global_critical_region_.Acquire(); + auto gobj_iter = guest_to_host_handle_.find(guest_object); + if (gobj_iter == guest_to_host_handle_.end()) { + return false; + } + out = gobj_iter->second; + return true; +} + +void ObjectTable::UnmapGuestObjectHostHandle(uint32_t guest_object) { + auto global_lock = global_critical_region_.Acquire(); + auto iter = guest_to_host_handle_.find(guest_object); + if (iter == guest_to_host_handle_.end()) { + return; + } else { + guest_to_host_handle_.erase(iter); + } +} + } // namespace util } // namespace kernel } // namespace xe diff --git a/src/xenia/kernel/util/object_table.h b/src/xenia/kernel/util/object_table.h index ddeaa8a7b..7223f1548 100644 --- a/src/xenia/kernel/util/object_table.h +++ b/src/xenia/kernel/util/object_table.h @@ -80,6 +80,9 @@ class ObjectTable { std::vector> GetAllObjects(); void PurgeAllObjects(); // Purges the object table of all guest objects + void MapGuestObjectToHostHandle(uint32_t guest_object, X_HANDLE host_handle); + void UnmapGuestObjectHostHandle(uint32_t guest_object); + bool HostHandleForGuestObject(uint32_t guest_object, X_HANDLE& out); private: struct ObjectTableEntry { int handle_ref_count = 0; @@ -107,6 +110,7 @@ class ObjectTable { uint32_t last_free_entry_ = 0; uint32_t last_free_host_entry_ = 0; std::unordered_map name_table_; + std::unordered_map guest_to_host_handle_; }; // Generic lookup diff --git a/src/xenia/kernel/xobject.cc b/src/xenia/kernel/xobject.cc index cee06c07a..c32384db8 100644 --- a/src/xenia/kernel/xobject.cc +++ b/src/xenia/kernel/xobject.cc @@ -25,6 +25,7 @@ #include "xenia/kernel/xsemaphore.h" #include "xenia/kernel/xsymboliclink.h" #include "xenia/kernel/xthread.h" +#include "xenia/xbox.h" namespace xe { namespace kernel { @@ -328,14 +329,11 @@ uint8_t* XObject::CreateNative(uint32_t size) { SetNativePointer(mem + sizeof(X_OBJECT_HEADER), true); auto header = memory()->TranslateVirtual(mem); - - auto object_type = memory()->SystemHeapAlloc(sizeof(X_OBJECT_TYPE)); - if (object_type) { - // Set it up in the header. - // Some kernel method is accessing this struct and dereferencing a member - // @ offset 0x14 - header->object_type_ptr = object_type; - } + // todo: should check whether + header->flags = OBJECT_HEADER_IS_TITLE_OBJECT; + header->pointer_count = 1; + header->handle_count = 0; + header->object_type_ptr = 0; return memory()->TranslateVirtual(guest_object_ptr_); } @@ -346,17 +344,11 @@ void XObject::SetNativePointer(uint32_t native_ptr, bool uninitialized) { // If hit: We've already setup the native ptr with CreateNative! assert_zero(guest_object_ptr_); - auto header = - kernel_state_->memory()->TranslateVirtual(native_ptr); - - // Memory uninitialized, so don't bother with the check. - if (!uninitialized) { - assert_true(!(header->wait_list_blink & 0x1)); - } - // Stash pointer in struct. // FIXME: This assumes the object has a dispatch header (some don't!) - StashHandle(header, handle()); + //StashHandle(header, handle()); + kernel_state()->object_table()->MapGuestObjectToHostHandle(native_ptr, + handle()); guest_object_ptr_ = native_ptr; } @@ -375,22 +367,30 @@ object_ref XObject::GetNativeObject(KernelState* kernel_state, // We identify this by setting wait_list_flink to a magic value. When set, // wait_list_blink will hold a handle to our object. + auto guest_ptr = kernel_state->memory()->HostToGuestVirtual(native_ptr); if (!already_locked) { global_critical_region::mutex().lock(); } - auto header = reinterpret_cast(native_ptr); XObject* result; + + auto header = reinterpret_cast(native_ptr); if (as_type == -1) { as_type = header->type; } + auto true_object_header = + kernel_state->memory()->TranslateVirtual(guest_ptr-sizeof(X_OBJECT_HEADER)); - if (header->wait_list_flink == kXObjSignature) { + X_HANDLE host_handle; + + + if (kernel_state->object_table()->HostHandleForGuestObject(guest_ptr, host_handle)) { // Already initialized. // TODO: assert if the type of the object != as_type - uint32_t handle = header->wait_list_blink; + + result = kernel_state->object_table() - ->LookupObject(handle, true) + ->LookupObject(host_handle, true) .release(); goto return_result; // TODO(benvanik): assert nothing has been changed in the struct. @@ -444,7 +444,9 @@ object_ref XObject::GetNativeObject(KernelState* kernel_state, // Stash pointer in struct. // FIXME: This assumes the object contains a dispatch header (some don't!) - StashHandle(header, object->handle()); + // StashHandle(header, object->handle()); + kernel_state->object_table()->MapGuestObjectToHostHandle(guest_ptr, + object->handle()); result = object; return_result: diff --git a/src/xenia/kernel/xobject.h b/src/xenia/kernel/xobject.h index b42c0ffbd..e44dc1ea2 100644 --- a/src/xenia/kernel/xobject.h +++ b/src/xenia/kernel/xobject.h @@ -62,28 +62,6 @@ typedef struct { } X_DISPATCH_HEADER; static_assert_size(X_DISPATCH_HEADER, 0x10); -// https://www.nirsoft.net/kernel_struct/vista/OBJECT_HEADER.html -struct X_OBJECT_HEADER { - xe::be pointer_count; - union { - xe::be handle_count; - xe::be next_to_free; - }; - uint8_t name_info_offset; - uint8_t handle_info_offset; - uint8_t quota_info_offset; - uint8_t flags; - union { - xe::be object_create_info; // X_OBJECT_CREATE_INFORMATION - xe::be quota_block_charged; - }; - xe::be object_type_ptr; // -0x8 POBJECT_TYPE - xe::be unk_04; // -0x4 - - // Object lives after this header. - // (There's actually a body field here which is the object itself) -}; - // https://www.nirsoft.net/kernel_struct/vista/OBJECT_CREATE_INFORMATION.html struct X_OBJECT_CREATE_INFORMATION { xe::be attributes; // 0x0 @@ -99,16 +77,6 @@ struct X_OBJECT_CREATE_INFORMATION { // Security QoS here (SECURITY_QUALITY_OF_SERVICE) too! }; -struct X_OBJECT_TYPE { - xe::be constructor; // 0x0 - xe::be destructor; // 0x4 - xe::be unk_08; // 0x8 - xe::be unk_0C; // 0xC - xe::be unk_10; // 0x10 - xe::be unk_14; // 0x14 probably offset from ntobject to keobject - xe::be pool_tag; // 0x18 -}; - class XObject { public: // 45410806 needs proper handle value for certain calculations @@ -221,11 +189,7 @@ class XObject { return reinterpret_cast(CreateNative(sizeof(T))); } - // Stash native pointer into X_DISPATCH_HEADER - static void StashHandle(X_DISPATCH_HEADER* header, uint32_t handle) { - header->wait_list_flink = kXObjSignature; - header->wait_list_blink = handle; - } + static uint32_t TimeoutTicksToMs(int64_t timeout_ticks); diff --git a/src/xenia/vfs/devices/xcontent_devices/stfs_container_device.cc b/src/xenia/vfs/devices/xcontent_devices/stfs_container_device.cc index c241c2c01..7a37807d2 100644 --- a/src/xenia/vfs/devices/xcontent_devices/stfs_container_device.cc +++ b/src/xenia/vfs/devices/xcontent_devices/stfs_container_device.cc @@ -250,7 +250,7 @@ void StfsContainerDevice::UpdateCachedHashTable( xe::filesystem::Seek(file, hash_offset + secondary_table_offset, SEEK_SET); StfsHashTable table; if (fread(&table, sizeof(StfsHashTable), 1, file) != 1) { - XELOGE("GetBlockHash failed to read level{} hash table at 0x{X}", + XELOGE("GetBlockHash failed to read level{} hash table at 0x{:08X}", hash_level, hash_offset + secondary_table_offset); return; } diff --git a/src/xenia/xbox.h b/src/xenia/xbox.h index 893436fa1..70ef8486d 100644 --- a/src/xenia/xbox.h +++ b/src/xenia/xbox.h @@ -312,12 +312,62 @@ struct X_EX_TITLE_TERMINATE_REGISTRATION { }; static_assert_size(X_EX_TITLE_TERMINATE_REGISTRATION, 16); + +enum X_OBJECT_HEADER_FLAGS : uint16_t { + OBJECT_HEADER_FLAG_NAMED_OBJECT = + 1, // if set, has X_OBJECT_HEADER_NAME_INFO prior to X_OBJECT_HEADER + OBJECT_HEADER_FLAG_IS_PERMANENT = 2, + OBJECT_HEADER_FLAG_CONTAINED_IN_DIRECTORY = + 4, // this object resides in an X_OBJECT_DIRECTORY + OBJECT_HEADER_IS_TITLE_OBJECT = 0x10, // used in obcreateobject + +}; + +// https://www.nirsoft.net/kernel_struct/vista/OBJECT_HEADER.html +struct X_OBJECT_HEADER { + xe::be pointer_count; + xe::be handle_count; + xe::be object_type_ptr; // -0x8 POBJECT_TYPE + xe::be flags; + uint8_t unknownE; + uint8_t unknownF; + // Object lives after this header. + // (There's actually a body field here which is the object itself) +}; +static_assert_size(X_OBJECT_HEADER, 0x10); + +struct X_OBJECT_DIRECTORY { + // each is a pointer to X_OBJECT_HEADER_NAME_INFO + // i believe offset 0 = pointer to next in bucket + xe::be name_buckets[13]; +}; +static_assert_size(X_OBJECT_DIRECTORY, 0x34); + +// https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/ntos/ob/object_header_name_info.htm +// quite different, though +struct X_OBJECT_HEADER_NAME_INFO { + // i think that this is the next link in an X_OBJECT_DIRECTORY's buckets + xe::be next_in_directory; + xe::be object_directory; // pointer to X_OBJECT_DIRECTORY + X_ANSI_STRING name; +}; struct X_OBJECT_ATTRIBUTES { xe::be root_directory; // 0x0 xe::be name_ptr; // 0x4 PANSI_STRING xe::be attributes; // 0xC }; - +struct X_OBJECT_TYPE { + xe::be allocate_proc; // 0x0 + xe::be free_proc; // 0x4 + xe::be close_proc; // 0x8 + xe::be delete_proc; // 0xC + xe::be unknown_proc; // 0x10 + xe::be + unknown_size_or_object_; // this seems to be a union, it can be a pointer + // or it can be the size of the object + xe::be pool_tag; // 0x18 +}; +static_assert_size(X_OBJECT_TYPE, 0x1C); // 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.