From 275454089ec7c9034a5f9b3051f8ec2736cd66fb Mon Sep 17 00:00:00 2001 From: disjtqz Date: Sun, 15 Oct 2023 12:33:54 -0400 Subject: [PATCH] [Kernel] Implement ObCreateObject --- src/xenia/cpu/processor.cc | 20 +- src/xenia/kernel/util/object_table.cc | 13 ++ src/xenia/kernel/util/object_table.h | 3 +- src/xenia/kernel/xboxkrnl/xboxkrnl_ob.cc | 233 ++++++++++++++++++++++- src/xenia/kernel/xboxkrnl/xboxkrnl_ob.h | 10 +- src/xenia/kernel/xobject.h | 34 +++- src/xenia/memory.cc | 4 +- src/xenia/memory.h | 2 +- 8 files changed, 298 insertions(+), 21 deletions(-) diff --git a/src/xenia/cpu/processor.cc b/src/xenia/cpu/processor.cc index ce69c6b70..c8ac45793 100644 --- a/src/xenia/cpu/processor.cc +++ b/src/xenia/cpu/processor.cc @@ -1300,12 +1300,12 @@ uint32_t Processor::GuestAtomicIncrement32(ppc::PPCContext* context, result = *host_address; // todo: should call a processor->backend function that acquires a // reservation instead of using host atomics - if (xe::atomic_cas(xe::byte_swap(result), xe::byte_swap(result + 1), + if (xe::atomic_cas(result, xe::byte_swap(xe::byte_swap(result)+1), host_address)) { break; } } - return result; + return xe::byte_swap(result); } uint32_t Processor::GuestAtomicDecrement32(ppc::PPCContext* context, uint32_t guest_address) { @@ -1316,31 +1316,31 @@ uint32_t Processor::GuestAtomicDecrement32(ppc::PPCContext* context, result = *host_address; // todo: should call a processor->backend function that acquires a // reservation instead of using host atomics - if (xe::atomic_cas(xe::byte_swap(result), xe::byte_swap(result - 1), + if (xe::atomic_cas(result,xe::byte_swap( xe::byte_swap(result)-1), host_address)) { break; } } - return result; + return xe::byte_swap(result); } uint32_t Processor::GuestAtomicOr32(ppc::PPCContext* context, uint32_t guest_address, uint32_t mask) { - return xe::atomic_or( + return xe::byte_swap(xe::atomic_or( context->TranslateVirtual(guest_address), - xe::byte_swap(mask)); + xe::byte_swap(mask))); } uint32_t Processor::GuestAtomicXor32(ppc::PPCContext* context, uint32_t guest_address, uint32_t mask) { - return xe::atomic_xor( + return xe::byte_swap(xe::atomic_xor( context->TranslateVirtual(guest_address), - xe::byte_swap(mask)); + xe::byte_swap(mask))); } uint32_t Processor::GuestAtomicAnd32(ppc::PPCContext* context, uint32_t guest_address, uint32_t mask) { - return xe::atomic_and( + return xe::byte_swap(xe::atomic_and( context->TranslateVirtual(guest_address), - xe::byte_swap(mask)); + xe::byte_swap(mask))); } bool Processor::GuestAtomicCAS32(ppc::PPCContext* context, uint32_t old_value, diff --git a/src/xenia/kernel/util/object_table.cc b/src/xenia/kernel/util/object_table.cc index ad3652e16..a56aabd7e 100644 --- a/src/xenia/kernel/util/object_table.cc +++ b/src/xenia/kernel/util/object_table.cc @@ -503,6 +503,19 @@ void ObjectTable::UnmapGuestObjectHostHandle(uint32_t guest_object) { 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 diff --git a/src/xenia/kernel/util/object_table.h b/src/xenia/kernel/util/object_table.h index 7223f1548..54bf4fbdc 100644 --- a/src/xenia/kernel/util/object_table.h +++ b/src/xenia/kernel/util/object_table.h @@ -83,6 +83,7 @@ class ObjectTable { 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; @@ -110,7 +111,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_; + std::map guest_to_host_handle_; }; // Generic lookup diff --git a/src/xenia/kernel/xboxkrnl/xboxkrnl_ob.cc b/src/xenia/kernel/xboxkrnl/xboxkrnl_ob.cc index 1f0753061..2f9bba31c 100644 --- a/src/xenia/kernel/xboxkrnl/xboxkrnl_ob.cc +++ b/src/xenia/kernel/xboxkrnl/xboxkrnl_ob.cc @@ -7,21 +7,234 @@ ****************************************************************************** */ +#include "xenia/kernel/xboxkrnl/xboxkrnl_ob.h" #include "xenia/base/assert.h" +#include "xenia/base/atomic.h" #include "xenia/base/logging.h" +#include "xenia/cpu/processor.h" #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/xboxkrnl/xboxkrnl_threading.h" #include "xenia/kernel/xobject.h" #include "xenia/kernel/xsemaphore.h" #include "xenia/kernel/xthread.h" #include "xenia/xbox.h" - namespace xe { namespace kernel { namespace xboxkrnl { +void xeObSplitName(X_ANSI_STRING input_string, + X_ANSI_STRING* leading_path_component, + X_ANSI_STRING* remaining_path_components, + PPCContext* context) { + leading_path_component->length = 0; + leading_path_component->maximum_length = 0; + leading_path_component->pointer = 0; + remaining_path_components->length = 0; + remaining_path_components->maximum_length = 0; + remaining_path_components->pointer = 0; + uint32_t input_length32 = input_string.length; + if (!input_length32) { + return; + } + unsigned char* input_string_buffer = + context->TranslateVirtual(input_string.pointer); + unsigned char first_char = *input_string_buffer; + // if it begins with a sep, start iterating at index 1 + + uint32_t starting_index = first_char == '\\' ? 1U : 0U; + // if the string is just a single sep and nothing else, set leading component + // to empty string w/ valid pointer and terminate + if (starting_index >= input_length32) { + leading_path_component->length = 0U; + leading_path_component->maximum_length = 0U; + leading_path_component->pointer = + context->HostToGuestVirtual(&input_string_buffer[starting_index]); + return; + } + + int32_t decrementer = (-static_cast(starting_index)) -1; + unsigned char* current_character_ptr = &input_string_buffer[starting_index]; + uint32_t leading_path_component_length = 0; + uint16_t full_possible_length = + static_cast(input_length32 - starting_index); + while (*current_character_ptr != '\\') { + ++leading_path_component_length; + ++current_character_ptr; + int32_t check_done = input_length32 + decrementer - 1; + decrementer--; + if (check_done == -1) { + // hit the end of the string! no remaining path components + + leading_path_component->length = full_possible_length; + leading_path_component->maximum_length = full_possible_length; + leading_path_component->pointer = + context->HostToGuestVirtual(&input_string_buffer[starting_index]); + return; + } + } + // hit the end of the current components, but more components remain + leading_path_component->length = leading_path_component_length; + leading_path_component->maximum_length = leading_path_component_length; + leading_path_component->pointer = + context->HostToGuestVirtual(&input_string_buffer[starting_index]); + uint16_t remainder_length = static_cast( + input_length32 - (first_char == '\\') + ~leading_path_component_length); + remaining_path_components->length = remainder_length; + remaining_path_components->pointer = + context->HostToGuestVirtual(&input_string_buffer[-decrementer]); + remaining_path_components->maximum_length = remainder_length; +} + +uint32_t xeObHashObjectName(X_ANSI_STRING* ElementName, PPCContext* context) { + uint8_t* current_character_ptr = + context->TranslateVirtual(ElementName->pointer); + uint32_t result = 0; + uint8_t* name_span_end = ¤t_character_ptr[ElementName->length]; + while (current_character_ptr < name_span_end) { + uint32_t current_character = *current_character_ptr++; + if (current_character < 0x80) { + result = (current_character | 0x20) + (result >> 1) + 3 * result; + } + } + return result % 0xD; +} + +uint32_t xeObCreateObject(X_OBJECT_TYPE* object_factory, + X_OBJECT_ATTRIBUTES* optional_attributes, + uint32_t object_size_sans_headers, + uint32_t* out_object, cpu::ppc::PPCContext* context) { + unsigned int resulting_header_flags = 0; + *out_object = 0; + unsigned int poolarg = 0; + + if (!optional_attributes) { + uint32_t process_type = xboxkrnl::xeKeGetCurrentProcessType(context); + if (process_type == X_PROCTYPE_TITLE) { + poolarg = 1; + resulting_header_flags = OBJECT_HEADER_IS_TITLE_OBJECT; + } else { + poolarg = 2; + } + } + + else if ((optional_attributes->attributes & 0x1000) == 0) { + if ((optional_attributes->attributes & 0x2000) != 0) { + poolarg = 2; + } else { + uint32_t process_type = xboxkrnl::xeKeGetCurrentProcessType(context); + if (process_type == X_PROCTYPE_TITLE) { + poolarg = 1; + resulting_header_flags = OBJECT_HEADER_IS_TITLE_OBJECT; + } else { + poolarg = 2; + } + } + } else { + poolarg = 1; + resulting_header_flags = OBJECT_HEADER_IS_TITLE_OBJECT; + } + uint32_t desired_object_path_ptr; + + if (!optional_attributes || + (desired_object_path_ptr = optional_attributes->name_ptr) == 0) { + /* + object has no name provided, just allocate an object with a basic header + */ + uint64_t allocate_args[] = { + object_size_sans_headers + sizeof(X_OBJECT_HEADER), + object_factory->pool_tag, poolarg}; + context->processor->Execute( + context->thread_state, object_factory->allocate_proc, allocate_args, 3); + + uint32_t allocation = static_cast(context->r[3]); + + if (allocation) { + X_OBJECT_HEADER* new_object_header = + context->TranslateVirtual(allocation); + new_object_header->pointer_count = 1; + new_object_header->handle_count = 0; + new_object_header->object_type_ptr = + context->HostToGuestVirtual(object_factory); + new_object_header->flags = resulting_header_flags; + + *out_object = allocation + sizeof(X_OBJECT_HEADER); + return X_STATUS_SUCCESS; + } + return X_STATUS_INSUFFICIENT_RESOURCES; + } + /* + iterate through all path components until we obtain the final one, which is + the objects actual name + */ + X_ANSI_STRING trailing_path_component; + X_ANSI_STRING remaining_path; + X_ANSI_STRING loaded_object_name; + loaded_object_name = + *context->TranslateVirtual(desired_object_path_ptr); + trailing_path_component.pointer = 0; + trailing_path_component.length = 0; + remaining_path = loaded_object_name; + while (remaining_path.length) { + xeObSplitName(remaining_path, &trailing_path_component, &remaining_path, + context); + if (remaining_path.length) { + if (*context->TranslateVirtual(remaining_path.pointer) == '\\') { + return X_STATUS_OBJECT_NAME_INVALID; + } + } + } + if (!trailing_path_component.length) { + return X_STATUS_OBJECT_NAME_INVALID; + } + // the object and its name are all created in a single allocation + + unsigned int aligned_object_size = + xe::align(object_size_sans_headers, 4); + { + uint64_t allocate_args[] = { + trailing_path_component.length + aligned_object_size + + sizeof(X_OBJECT_HEADER_NAME_INFO) + sizeof(X_OBJECT_HEADER), + object_factory->pool_tag, poolarg}; + + context->processor->Execute( + context->thread_state, object_factory->allocate_proc, allocate_args, 3); + } + uint32_t named_object_allocation = static_cast(context->r[3]); + if (!named_object_allocation) { + return X_STATUS_INSUFFICIENT_RESOURCES; + } + + X_OBJECT_HEADER_NAME_INFO* nameinfo = + context->TranslateVirtual( + named_object_allocation); + nameinfo->next_in_directory = 0; + nameinfo->object_directory = 0; + + X_OBJECT_HEADER* header_for_named_object = + reinterpret_cast(nameinfo + 1); + + char* name_string_memory_for_named_object = &reinterpret_cast( + header_for_named_object + 1)[aligned_object_size]; + nameinfo->name.pointer = + context->HostToGuestVirtual(name_string_memory_for_named_object); + nameinfo->name.length = trailing_path_component.length; + nameinfo->name.maximum_length = trailing_path_component.length; + + memcpy(name_string_memory_for_named_object, + context->TranslateVirtual(trailing_path_component.pointer), + trailing_path_component.length); + + header_for_named_object->pointer_count = 1; + header_for_named_object->handle_count = 0; + header_for_named_object->object_type_ptr = + context->HostToGuestVirtual(object_factory); + header_for_named_object->flags = + resulting_header_flags & 0xFFFE | OBJECT_HEADER_FLAG_NAMED_OBJECT; + *out_object = context->HostToGuestVirtual(&header_for_named_object[1]); + return X_STATUS_SUCCESS; +} dword_result_t ObOpenObjectByName_entry(lpunknown_t obj_attributes_ptr, lpunknown_t object_type_ptr, dword_t unk, lpdword_t handle_ptr) { @@ -170,7 +383,6 @@ void xeObDereferenceObject(PPCContext* context, uint32_t native_ptr) { return; } - void ObDereferenceObject_entry(dword_t native_ptr, const ppc_context_t& ctx) { xeObDereferenceObject(ctx, native_ptr); } @@ -253,6 +465,21 @@ uint32_t NtClose(uint32_t handle) { dword_result_t NtClose_entry(dword_t handle) { return NtClose(handle); } DECLARE_XBOXKRNL_EXPORT1(NtClose, kNone, kImplemented); +dword_result_t ObCreateObject_entry( + pointer_t object_factory, + pointer_t optional_attributes, + dword_t object_size_sans_headers, lpdword_t out_object, + const ppc_context_t& context) { + uint32_t out_object_tmp = 0; + + uint32_t result = + xeObCreateObject(object_factory, optional_attributes, + object_size_sans_headers, &out_object_tmp, context); + *out_object = out_object_tmp; + return result; +} +DECLARE_XBOXKRNL_EXPORT1(ObCreateObject, kNone, kImplemented); + } // namespace xboxkrnl } // namespace kernel } // namespace xe diff --git a/src/xenia/kernel/xboxkrnl/xboxkrnl_ob.h b/src/xenia/kernel/xboxkrnl/xboxkrnl_ob.h index 7d5afb4d9..e8b320418 100644 --- a/src/xenia/kernel/xboxkrnl/xboxkrnl_ob.h +++ b/src/xenia/kernel/xboxkrnl/xboxkrnl_ob.h @@ -16,7 +16,15 @@ namespace xe { namespace kernel { namespace xboxkrnl { void xeObDereferenceObject(PPCContext* context, uint32_t native_ptr); - +void xeObSplitName(X_ANSI_STRING input_string, + X_ANSI_STRING* leading_path_component, + X_ANSI_STRING* remaining_path_components, + PPCContext* context); +uint32_t xeObHashObjectName(X_ANSI_STRING* ElementName, PPCContext* context); +uint32_t xeObCreateObject(X_OBJECT_TYPE* object_factory, + X_OBJECT_ATTRIBUTES* optional_attributes, + uint32_t object_size_sans_headers, + uint32_t* out_object, cpu::ppc::PPCContext* context); } // namespace xboxkrnl } // namespace kernel } // namespace xe diff --git a/src/xenia/kernel/xobject.h b/src/xenia/kernel/xobject.h index e44dc1ea2..8f9993263 100644 --- a/src/xenia/kernel/xobject.h +++ b/src/xenia/kernel/xobject.h @@ -102,9 +102,39 @@ class XObject { SymbolicLink, Thread, Timer, - Device + Device }; + static bool HasDispatcherHeader(Type type) { + switch (type) { + case Type::Event: + case Type::Mutant: + case Type::Semaphore: + case Type::Thread: + case Type::Timer: + return true; + } + return false; + } + + static Type MapGuestTypeToHost(uint16_t type) { + // todo: this is not fully filled in + switch (type) { + case 0: + case 1: + return Type::Event; + case 2: + return Type::Mutant; + case 5: + return Type::Semaphore; + case 6: + return Type::Thread; + case 8: + case 9: + return Type::Timer; + } + return Type::Undefined; + } XObject(Type type); XObject(KernelState* kernel_state, Type type, bool host_object = false); virtual ~XObject(); @@ -189,8 +219,6 @@ class XObject { return reinterpret_cast(CreateNative(sizeof(T))); } - - static uint32_t TimeoutTicksToMs(int64_t timeout_ticks); KernelState* kernel_state_; diff --git a/src/xenia/memory.cc b/src/xenia/memory.cc index 1109a7a23..dfb4fad19 100644 --- a/src/xenia/memory.cc +++ b/src/xenia/memory.cc @@ -608,13 +608,13 @@ uint32_t Memory::SystemHeapAlloc(uint32_t size, uint32_t alignment, return address; } -void Memory::SystemHeapFree(uint32_t address) { +void Memory::SystemHeapFree(uint32_t address, uint32_t* out_region_size) { if (!address) { return; } // TODO(benvanik): lightweight pool. auto heap = LookupHeap(address); - heap->Release(address); + heap->Release(address, out_region_size); } void Memory::DumpMap() { diff --git a/src/xenia/memory.h b/src/xenia/memory.h index 185b46cd7..e9966b56c 100644 --- a/src/xenia/memory.h +++ b/src/xenia/memory.h @@ -511,7 +511,7 @@ class Memory { uint32_t system_heap_flags = kSystemHeapDefault); // Frees memory allocated with SystemHeapAlloc. - void SystemHeapFree(uint32_t address); + void SystemHeapFree(uint32_t address, uint32_t* out_region_size=nullptr); // Gets the heap for the address space containing the given address. XE_NOALIAS