diff --git a/src/xenia/kernel/kernel_state.h b/src/xenia/kernel/kernel_state.h index dde6bd02b..8324d51e7 100644 --- a/src/xenia/kernel/kernel_state.h +++ b/src/xenia/kernel/kernel_state.h @@ -109,6 +109,7 @@ struct X_UNKNOWN_TYPE_REFED { points_to_prior; // points to the previous field, which points to itself }; static_assert_size(X_UNKNOWN_TYPE_REFED, 16); + struct KernelGuestGlobals { X_OBJECT_TYPE ExThreadObjectType; X_OBJECT_TYPE ExEventObjectType; diff --git a/src/xenia/kernel/util/kernel_fwd.h b/src/xenia/kernel/util/kernel_fwd.h index 7e1ed788a..af647fb97 100644 --- a/src/xenia/kernel/util/kernel_fwd.h +++ b/src/xenia/kernel/util/kernel_fwd.h @@ -17,6 +17,7 @@ struct XAPC; struct X_KPCR; struct X_KTHREAD; +struct X_OBJECT_HEADER; struct X_OBJECT_CREATE_INFORMATION; } // namespace xe::kernel diff --git a/src/xenia/kernel/util/object_table.cc b/src/xenia/kernel/util/object_table.cc index a56aabd7e..4568c72d1 100644 --- a/src/xenia/kernel/util/object_table.cc +++ b/src/xenia/kernel/util/object_table.cc @@ -479,44 +479,6 @@ 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); - } -} -void ObjectTable::FlushGuestToHostMapping(uint32_t base_address, - uint32_t length) { - auto global_lock = global_critical_region_.Acquire(); - auto iterator = guest_to_host_handle_.lower_bound(base_address); - - while (iterator !=guest_to_host_handle_.end() && iterator->first >= base_address && iterator->first < (base_address + length)) { - auto old_mapping = iterator; - - iterator++; - auto node_handle = guest_to_host_handle_.extract(old_mapping); - - } -} - } // 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 54bf4fbdc..ddeaa8a7b 100644 --- a/src/xenia/kernel/util/object_table.h +++ b/src/xenia/kernel/util/object_table.h @@ -80,10 +80,6 @@ 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); - void FlushGuestToHostMapping(uint32_t base_address, uint32_t length); private: struct ObjectTableEntry { int handle_ref_count = 0; @@ -111,7 +107,6 @@ class ObjectTable { uint32_t last_free_entry_ = 0; uint32_t last_free_host_entry_ = 0; std::unordered_map name_table_; - std::map guest_to_host_handle_; }; // Generic lookup diff --git a/src/xenia/kernel/xobject.cc b/src/xenia/kernel/xobject.cc index f52bc2859..1a0d7be21 100644 --- a/src/xenia/kernel/xobject.cc +++ b/src/xenia/kernel/xobject.cc @@ -55,10 +55,14 @@ XObject::~XObject() { assert_zero(pointer_ref_count_); if (allocated_guest_object_) { - kernel_state()->object_table()->UnmapGuestObjectHostHandle( - guest_object_ptr_); + uint32_t ptr = guest_object_ptr_ - sizeof(X_OBJECT_HEADER); + auto header = memory()->TranslateVirtual(ptr); + + // Free the object creation info + if (header->object_type_ptr) { + memory()->SystemHeapFree(header->object_type_ptr); + } - const uint32_t ptr = guest_object_ptr_ - sizeof(X_OBJECT_HEADER); memory()->SystemHeapFree(ptr); } } @@ -323,14 +327,12 @@ uint8_t* XObject::CreateNative(uint32_t size) { SetNativePointer(mem + sizeof(X_OBJECT_HEADER), true); auto header = memory()->TranslateVirtual(mem); - header->flags = OBJECT_HEADER_IS_TITLE_OBJECT; - header->pointer_count = 1; - header->handle_count = 0; - // Added to prevent having nullptr crashes on semaphore. - // This should probably work differently, but for now it is good enough (hopefully). 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; } @@ -343,8 +345,17 @@ 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_); - kernel_state()->object_table()->MapGuestObjectToHostHandle(native_ptr, - handle()); + 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()); guest_object_ptr_ = native_ptr; } @@ -362,8 +373,6 @@ object_ref XObject::GetNativeObject(KernelState* kernel_state, // each time. // 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(); } @@ -375,14 +384,11 @@ object_ref XObject::GetNativeObject(KernelState* kernel_state, as_type = header->type; } - X_HANDLE host_handle; - - if (kernel_state->object_table()->HostHandleForGuestObject(guest_ptr, host_handle)) { + if (header->wait_list_flink == kXObjSignature) { // Already initialized. // TODO: assert if the type of the object != as_type - result = kernel_state->object_table() - ->LookupObject(host_handle, true) - .release(); + uint32_t handle = header->wait_list_blink; + result = kernel_state->object_table()->LookupObject(handle, true).release(); } else { // First use, create new. // https://www.nirsoft.net/kernel_struct/vista/KOBJECTS.html @@ -426,12 +432,10 @@ object_ref XObject::GetNativeObject(KernelState* kernel_state, assert_always(); result = nullptr; } - - if (object) { - kernel_state->object_table()->MapGuestObjectToHostHandle( - guest_ptr, object->handle()); - result = object; - } + // Stash pointer in struct. + // FIXME: This assumes the object contains a dispatch header (some don't!) + StashHandle(header, object->handle()); + result = object; } if (!already_locked) { diff --git a/src/xenia/kernel/xobject.h b/src/xenia/kernel/xobject.h index 8f9993263..1d19e8bec 100644 --- a/src/xenia/kernel/xobject.h +++ b/src/xenia/kernel/xobject.h @@ -62,6 +62,28 @@ 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 @@ -219,6 +241,12 @@ 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); KernelState* kernel_state_; diff --git a/src/xenia/xbox.h b/src/xenia/xbox.h index ccf88faff..cd77acc7d 100644 --- a/src/xenia/xbox.h +++ b/src/xenia/xbox.h @@ -323,19 +323,6 @@ enum X_OBJECT_HEADER_FLAGS : uint16_t { }; -// 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 @@ -351,11 +338,13 @@ struct X_OBJECT_HEADER_NAME_INFO { 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