[Kernel] Implement ObCreateObject

This commit is contained in:
disjtqz 2023-10-15 12:33:54 -04:00 committed by Radosław Gliński
parent d8aa14da73
commit 275454089e
8 changed files with 298 additions and 21 deletions

View File

@ -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<volatile int32_t*>(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<volatile int32_t*>(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<volatile int32_t*>(guest_address),
xe::byte_swap(mask));
xe::byte_swap(mask)));
}
bool Processor::GuestAtomicCAS32(ppc::PPCContext* context, uint32_t old_value,

View File

@ -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

View File

@ -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<string_key_case, X_HANDLE> name_table_;
std::unordered_map<uint32_t, X_HANDLE> guest_to_host_handle_;
std::map<uint32_t, X_HANDLE> guest_to_host_handle_;
};
// Generic lookup

View File

@ -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<uint8_t*>(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<int32_t>(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<uint16_t>(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<uint16_t>(
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 = &current_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<uint32_t>(context->r[3]);
if (allocation) {
X_OBJECT_HEADER* new_object_header =
context->TranslateVirtual<X_OBJECT_HEADER*>(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<X_ANSI_STRING*>(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<char*>(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<uint32_t>(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<uint32_t>(context->r[3]);
if (!named_object_allocation) {
return X_STATUS_INSUFFICIENT_RESOURCES;
}
X_OBJECT_HEADER_NAME_INFO* nameinfo =
context->TranslateVirtual<X_OBJECT_HEADER_NAME_INFO*>(
named_object_allocation);
nameinfo->next_in_directory = 0;
nameinfo->object_directory = 0;
X_OBJECT_HEADER* header_for_named_object =
reinterpret_cast<X_OBJECT_HEADER*>(nameinfo + 1);
char* name_string_memory_for_named_object = &reinterpret_cast<char*>(
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<char*>(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<X_OBJECT_TYPE> object_factory,
pointer_t<X_OBJECT_ATTRIBUTES> 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

View File

@ -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

View File

@ -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<T*>(CreateNative(sizeof(T)));
}
static uint32_t TimeoutTicksToMs(int64_t timeout_ticks);
KernelState* kernel_state_;

View File

@ -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() {

View File

@ -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