diff --git a/src/xenia/kernel/objects/xfile.h b/src/xenia/kernel/objects/xfile.h index 8a1685d62..c4b09ed1a 100644 --- a/src/xenia/kernel/objects/xfile.h +++ b/src/xenia/kernel/objects/xfile.h @@ -39,17 +39,17 @@ struct X_FILE_NETWORK_OPEN_INFORMATION { class X_FILE_DIRECTORY_INFORMATION { public: // FILE_DIRECTORY_INFORMATION - uint32_t next_entry_offset; - uint32_t file_index; - uint64_t creation_time; - uint64_t last_access_time; - uint64_t last_write_time; - uint64_t change_time; - uint64_t end_of_file; // size in bytes - uint64_t allocation_size; - uint32_t attributes; // X_FILE_ATTRIBUTES - uint32_t file_name_length; - char file_name[1]; + xe::be next_entry_offset; // 0x0 + xe::be file_index; // 0x4 + xe::be creation_time; // 0x8 + xe::be last_access_time; // 0x10 + xe::be last_write_time; // 0x18 + xe::be change_time; // 0x20 + xe::be end_of_file; // 0x28 size in bytes + xe::be allocation_size; // 0x30 + xe::be attributes; // 0x38 X_FILE_ATTRIBUTES + xe::be file_name_length; // 0x3C + char file_name[1]; // 0x40 void Write(uint8_t* base, uint32_t p) { uint8_t* dst = base + p; @@ -68,6 +68,7 @@ class X_FILE_DIRECTORY_INFORMATION { xe::store_and_swap(dst + 56, info->attributes); xe::store_and_swap(dst + 60, info->file_name_length); memcpy(dst + 64, info->file_name, info->file_name_length); + dst += info->next_entry_offset; src += info->next_entry_offset; } while (info->next_entry_offset != 0); diff --git a/src/xenia/kernel/objects/xthread.cc b/src/xenia/kernel/objects/xthread.cc index 008f2947b..0b3828439 100644 --- a/src/xenia/kernel/objects/xthread.cc +++ b/src/xenia/kernel/objects/xthread.cc @@ -321,7 +321,8 @@ X_STATUS XThread::Create() { // Set the thread name based on host ID (for easier debugging) char thread_name[32]; - snprintf(thread_name, xe::countof(thread_name), "XThread%04X (%04X)", handle(), thread_->id()); + snprintf(thread_name, xe::countof(thread_name), "XThread%04X (%04X)", + handle(), thread_->id()); set_name(thread_name); if (creation_params_.creation_flags & 0x60) { @@ -340,8 +341,6 @@ X_STATUS XThread::Exit(int exit_code) { // This may only be called on the thread itself. assert_true(XThread::GetCurrentThread() == this); - // TODO(benvanik): set exit code in thread state block - // TODO(benvanik); dispatch events? waiters? etc? RundownAPCs(); @@ -351,6 +350,11 @@ X_STATUS XThread::Exit(int exit_code) { current_thread_tls = nullptr; xe::Profiler::ThreadExit(); + // Set exit code + X_KTHREAD* thread = guest_object(); + thread->header.signal_state = 1; + thread->exit_status = exit_code; + running_ = false; Release(); ReleaseHandle(); @@ -363,6 +367,11 @@ X_STATUS XThread::Exit(int exit_code) { X_STATUS XThread::Terminate(int exit_code) { // TODO: Inform the profiler that this thread is exiting. + // Set exit code + X_KTHREAD* thread = guest_object(); + thread->header.signal_state = 1; + thread->exit_status = exit_code; + running_ = false; Release(); ReleaseHandle(); diff --git a/src/xenia/kernel/objects/xthread.h b/src/xenia/kernel/objects/xthread.h index 153e36ee0..d052b53a0 100644 --- a/src/xenia/kernel/objects/xthread.h +++ b/src/xenia/kernel/objects/xthread.h @@ -82,14 +82,20 @@ struct X_KPCR { }; struct X_KTHREAD { - X_DISPATCH_HEADER header; // 0x0 - char unk_10[0xAC]; // 0x10 - uint8_t suspend_count; // 0xBC - char unk_BD[0x8F]; // 0xBD - xe::be thread_id; // 0x14C - char unk_150[0x10]; // 0x150 - xe::be last_error; // 0x160 - char unk_164[0x94C]; // 0x164 + X_DISPATCH_HEADER header; // 0x0 + char unk_10[0xAC]; // 0x10 + uint8_t suspend_count; // 0xBC + uint8_t unk_BD; // 0xBD + uint16_t unk_BE; // 0xBE + char unk_C0[0x70]; // 0xC0 + xe::be create_time; // 0x130 + xe::be exit_time; // 0x138 + xe::be exit_status; // 0x140 + char unk_144[0x8]; // 0x144 + xe::be thread_id; // 0x14C + char unk_150[0x10]; // 0x150 + xe::be last_error; // 0x160 + char unk_164[0x94C]; // 0x164 // This struct is actually quite long... so uh, not filling this out! }; diff --git a/src/xenia/kernel/util/shim_utils.h b/src/xenia/kernel/util/shim_utils.h index 60189b913..2a1411bf1 100644 --- a/src/xenia/kernel/util/shim_utils.h +++ b/src/xenia/kernel/util/shim_utils.h @@ -113,7 +113,7 @@ class Param { *out_value = V(init.ppc_context->r[3 + ordinal_]); } else { uint32_t stack_ptr = - uint32_t(init.ppc_context->r[1]) + 0x54 + (ordinal_ - 7) * 8; + uint32_t(init.ppc_context->r[1]) + 0x54 + (ordinal_ - 8) * 8; *out_value = xe::load_and_swap(init.ppc_context->virtual_membase + stack_ptr); } @@ -190,7 +190,9 @@ class PrimitivePointerParam : public ParamBase { init.ppc_context->virtual_membase + value_) : nullptr; } - PrimitivePointerParam(T* host_ptr) : ParamBase(), host_ptr_(host_ptr) {} + PrimitivePointerParam(T* host_ptr) : ParamBase() { + host_ptr_ = reinterpret_cast*>(host_ptr); + } PrimitivePointerParam& operator=(const T*& other) { host_ptr_ = other; return *this; diff --git a/src/xenia/kernel/xboxkrnl_io.cc b/src/xenia/kernel/xboxkrnl_io.cc index 26d52e6b6..a275d559d 100644 --- a/src/xenia/kernel/xboxkrnl_io.cc +++ b/src/xenia/kernel/xboxkrnl_io.cc @@ -25,74 +25,6 @@ namespace kernel { using namespace xe::vfs; -// TODO(benvanik): replace X_OBJECT_ATTRIBUTES with new style and remove this. -class X_ANSI_STRING_OLD { - private: - uint16_t length; - uint16_t maximum_length; - const char* buffer; - - public: - X_ANSI_STRING_OLD() { Zero(); } - X_ANSI_STRING_OLD(const uint8_t* base, uint32_t p) { Read(base, p); } - void Read(const uint8_t* base, uint32_t p) { - length = xe::load_and_swap(base + p); - maximum_length = xe::load_and_swap(base + p + 2); - if (maximum_length) { - buffer = (const char*)(base + xe::load_and_swap(base + p + 4)); - } else { - buffer = 0; - } - } - void Zero() { - length = maximum_length = 0; - buffer = 0; - } - char* Duplicate() { - if (!buffer || !length) { - return nullptr; - } - auto copy = (char*)calloc(length + 1, sizeof(char)); - std::strncpy(copy, buffer, length); - return copy; - } - std::string to_string() { - if (!buffer || !length) { - return ""; - } - std::string result(buffer, length); - return result; - } -}; -// static_assert_size(X_ANSI_STRING, 8); - -class X_OBJECT_ATTRIBUTES { - public: - uint32_t root_directory; - uint32_t object_name_ptr; - X_ANSI_STRING_OLD object_name; - uint32_t attributes; - - X_OBJECT_ATTRIBUTES() { Zero(); } - X_OBJECT_ATTRIBUTES(const uint8_t* base, uint32_t p) { Read(base, p); } - void Read(const uint8_t* base, uint32_t p) { - root_directory = xe::load_and_swap(base + p); - object_name_ptr = xe::load_and_swap(base + p + 4); - if (object_name_ptr) { - object_name.Read(base, object_name_ptr); - } else { - object_name.Zero(); - } - attributes = xe::load_and_swap(base + p + 8); - } - void Zero() { - root_directory = 0; - object_name_ptr = 0; - object_name.Zero(); - attributes = 0; - } -}; - // http://msdn.microsoft.com/en-us/library/windows/hardware/ff540287.aspx class X_FILE_FS_VOLUME_INFORMATION { public: @@ -152,23 +84,33 @@ class X_FILE_FS_ATTRIBUTE_INFORMATION { }; static_assert_size(X_FILE_FS_ATTRIBUTE_INFORMATION, 16); -X_STATUS NtCreateFile(PPCContext* ppc_context, KernelState* kernel_state, - uint32_t handle_ptr, uint32_t desired_access, - X_OBJECT_ATTRIBUTES* object_attrs, - const char* object_name, uint32_t io_status_block_ptr, - uint32_t allocation_size_ptr, uint32_t file_attributes, - uint32_t share_access, - FileDisposition creation_disposition) { +dword_result_t NtCreateFile(lpdword_t handle_out, dword_t desired_access, + pointer_t object_attrs, + pointer_t io_status_block, + lpqword_t allocation_size_ptr, + dword_t file_attributes, dword_t share_access, + dword_t creation_disposition, + dword_t create_options) { uint64_t allocation_size = 0; // is this correct??? - if (allocation_size_ptr != 0) { - allocation_size = SHIM_MEM_64(allocation_size_ptr); + if (allocation_size_ptr) { + allocation_size = *allocation_size_ptr; } + if (!object_attrs) { + // ..? Some games do this. This parameter is not optional. + return X_STATUS_INVALID_PARAMETER; + } + assert_not_null(handle_out); + + auto object_name = + kernel_memory()->TranslateVirtual(object_attrs->name_ptr); + // Compute path, possibly attrs relative. - std::string target_path = object_name; + std::string target_path = + object_name->to_string(kernel_memory()->virtual_membase()); if (object_attrs->root_directory != 0xFFFFFFFD && // ObDosDevices object_attrs->root_directory != 0) { - auto root_file = kernel_state->object_table()->LookupObject( + auto root_file = kernel_state()->object_table()->LookupObject( object_attrs->root_directory); assert_not_null(root_file); assert_true(root_file->type() == XObject::Type::kTypeFile); @@ -176,16 +118,16 @@ X_STATUS NtCreateFile(PPCContext* ppc_context, KernelState* kernel_state, // Resolve the file using the device the root directory is part of. auto device = root_file->device(); target_path = xe::join_paths( - device->mount_path(), xe::join_paths(root_file->path(), object_name)); + device->mount_path(), xe::join_paths(root_file->path(), target_path)); } // Attempt open (or create). object_ref file; FileAction file_action; - X_STATUS result = kernel_state->file_system()->OpenFile( - kernel_state, target_path, creation_disposition, desired_access, &file, - &file_action); - uint32_t info = uint32_t(file_action); + X_STATUS result = kernel_state()->file_system()->OpenFile( + kernel_state(), target_path, + xe::vfs::FileDisposition((uint32_t)creation_disposition), desired_access, + &file, &file_action); X_HANDLE handle = X_INVALID_HANDLE_VALUE; if (XSUCCEEDED(result)) { @@ -193,70 +135,26 @@ X_STATUS NtCreateFile(PPCContext* ppc_context, KernelState* kernel_state, handle = file->handle(); } - if (io_status_block_ptr) { - SHIM_SET_MEM_32(io_status_block_ptr, result); // Status - SHIM_SET_MEM_32(io_status_block_ptr + 4, info); // Information - } - if (XSUCCEEDED(result)) { - if (handle_ptr) { - SHIM_SET_MEM_32(handle_ptr, handle); - } + if (io_status_block) { + io_status_block->status = result; + io_status_block->information = (uint32_t)file_action; } + *handle_out = handle; + return result; } +DECLARE_XBOXKRNL_EXPORT(NtCreateFile, ExportTag::kImplemented); -SHIM_CALL NtCreateFile_shim(PPCContext* ppc_context, - KernelState* kernel_state) { - uint32_t handle_ptr = SHIM_GET_ARG_32(0); - uint32_t desired_access = SHIM_GET_ARG_32(1); - uint32_t object_attributes_ptr = SHIM_GET_ARG_32(2); - uint32_t io_status_block_ptr = SHIM_GET_ARG_32(3); - uint32_t allocation_size_ptr = SHIM_GET_ARG_32(4); - uint32_t file_attributes = SHIM_GET_ARG_32(5); - uint32_t share_access = SHIM_GET_ARG_32(6); - uint32_t creation_disposition = SHIM_GET_ARG_32(7); - - X_OBJECT_ATTRIBUTES object_attrs(SHIM_MEM_BASE, object_attributes_ptr); - char* object_name = object_attrs.object_name.Duplicate(); - - XELOGD("NtCreateFile(%.8X, %.8X, %.8X(%s), %.8X, %.8X, %.8X, %d, %d)", - handle_ptr, desired_access, object_attributes_ptr, - !object_name ? "(null)" : object_name, io_status_block_ptr, - allocation_size_ptr, file_attributes, share_access, - creation_disposition); - - auto result = NtCreateFile( - ppc_context, kernel_state, handle_ptr, desired_access, &object_attrs, - object_name, io_status_block_ptr, allocation_size_ptr, file_attributes, - share_access, FileDisposition(creation_disposition)); - - free(object_name); - SHIM_SET_RETURN_32(result); -} - -SHIM_CALL NtOpenFile_shim(PPCContext* ppc_context, KernelState* kernel_state) { - uint32_t handle_ptr = SHIM_GET_ARG_32(0); - uint32_t desired_access = SHIM_GET_ARG_32(1); - uint32_t object_attributes_ptr = SHIM_GET_ARG_32(2); - uint32_t io_status_block_ptr = SHIM_GET_ARG_32(3); - uint32_t open_options = SHIM_GET_ARG_32(4); - - X_OBJECT_ATTRIBUTES object_attrs(SHIM_MEM_BASE, object_attributes_ptr); - char* object_name = object_attrs.object_name.Duplicate(); - - XELOGD("NtOpenFile(%.8X, %.8X, %.8X(%s), %.8X, %d)", handle_ptr, - desired_access, object_attributes_ptr, - !object_name ? "(null)" : object_name, io_status_block_ptr, - open_options); - - auto result = NtCreateFile( - ppc_context, kernel_state, handle_ptr, desired_access, &object_attrs, - object_name, io_status_block_ptr, 0, 0, 0, FileDisposition::kOpen); - - free(object_name); - SHIM_SET_RETURN_32(result); +dword_result_t NtOpenFile(lpdword_t handle_out, dword_t desired_access, + pointer_t object_attributes, + pointer_t io_status_block, + dword_t open_options) { + return NtCreateFile(handle_out, desired_access, object_attributes, + io_status_block, nullptr, 0, 0, + (uint32_t)FileDisposition::kOpen, open_options); } +DECLARE_XBOXKRNL_EXPORT(NtOpenFile, ExportTag::kImplemented); class xeNtReadFileState { public: @@ -268,159 +166,118 @@ void xeNtReadFileCompleted(XAsyncRequest* request, xeNtReadFileState* state) { delete state; } -SHIM_CALL NtReadFile_shim(PPCContext* ppc_context, KernelState* kernel_state) { - uint32_t file_handle = SHIM_GET_ARG_32(0); - uint32_t event_handle = SHIM_GET_ARG_32(1); - uint32_t apc_routine_ptr = SHIM_GET_ARG_32(2); - uint32_t apc_context = SHIM_GET_ARG_32(3); - uint32_t io_status_block_ptr = SHIM_GET_ARG_32(4); - uint32_t buffer = SHIM_GET_ARG_32(5); - uint32_t buffer_length = SHIM_GET_ARG_32(6); - uint32_t byte_offset_ptr = SHIM_GET_ARG_32(7); - size_t byte_offset = byte_offset_ptr ? SHIM_MEM_64(byte_offset_ptr) : 0; - - XELOGD("NtReadFile(%.8X, %.8X, %.8X, %.8X, %.8X, %.8X, %d, %.8X(%llu))", - file_handle, event_handle, apc_routine_ptr, apc_context, - io_status_block_ptr, buffer, buffer_length, byte_offset_ptr, - byte_offset); - +dword_result_t NtReadFile(dword_t file_handle, dword_t event_handle, + lpvoid_t apc_routine_ptr, lpvoid_t apc_context, + pointer_t io_status_block, + lpvoid_t buffer, dword_t buffer_length, + lpqword_t byte_offset_ptr) { X_STATUS result = X_STATUS_SUCCESS; - uint32_t info = 0; - // Grab event to signal. bool signal_event = false; - auto ev = - event_handle - ? kernel_state->object_table()->LookupObject(event_handle) - : object_ref(); + auto ev = kernel_state()->object_table()->LookupObject(event_handle); if (event_handle && !ev) { result = X_STATUS_INVALID_HANDLE; } - // Grab file. - auto file = kernel_state->object_table()->LookupObject(file_handle); + auto file = kernel_state()->object_table()->LookupObject(file_handle); if (!file) { result = X_STATUS_INVALID_HANDLE; } - // Execute read. if (XSUCCEEDED(result)) { - // Reset event before we begin. - if (ev) { - ev->Reset(); - } - - // TODO(benvanik): async path. if (true) { - // Synchronous request. - if (!byte_offset_ptr || byte_offset == 0xFFFFFFFFfffffffe) { - // FILE_USE_FILE_POINTER_POSITION - byte_offset = -1; - } - - // Read now. + // Synchronous. size_t bytes_read = 0; - result = file->Read(SHIM_MEM_ADDR(buffer), buffer_length, byte_offset, - &bytes_read); - if (XSUCCEEDED(result)) { - info = (int32_t)bytes_read; + result = file->Read(buffer, buffer_length, + byte_offset_ptr ? *byte_offset_ptr : -1, &bytes_read); + if (io_status_block) { + io_status_block->status = result; + io_status_block->information = (uint32_t)bytes_read; } // Queue the APC callback. It must be delivered via the APC mechanism even // though were are completing immediately. - if (apc_routine_ptr & ~1) { - auto thread = XThread::GetCurrentThread(); - thread->EnqueueApc(apc_routine_ptr & ~1, apc_context, - io_status_block_ptr, 0); + if ((uint32_t)apc_routine_ptr & ~1) { + // Bejeweled 3 calls ReadFileEx with a NULL completion routine! + assert_not_zero((uint32_t)apc_context); + + if (apc_context) { + auto thread = XThread::GetCurrentThread(); + thread->EnqueueApc((uint32_t)apc_routine_ptr & ~1, apc_context, + io_status_block, 0); + } } // Mark that we should signal the event now. We do this after // we have written the info out. signal_event = true; } else { + // TODO: Async. + // X_STATUS_PENDING if not returning immediately. // XFile is waitable and signalled after each async req completes. // reset the input event (->Reset()) /*xeNtReadFileState* call_state = new xeNtReadFileState(); XAsyncRequest* request = new XAsyncRequest( - state, file, - (XAsyncRequest::CompletionCallback)xeNtReadFileCompleted, - call_state);*/ + state, file, + (XAsyncRequest::CompletionCallback)xeNtReadFileCompleted, + call_state);*/ // result = file->Read(buffer, buffer_length, byte_offset, request); + if (io_status_block) { + io_status_block->status = X_STATUS_PENDING; + io_status_block->information = 0; + } + result = X_STATUS_PENDING; - info = 0; } } - if (io_status_block_ptr) { - SHIM_SET_MEM_32(io_status_block_ptr, result); // Status - SHIM_SET_MEM_32(io_status_block_ptr + 4, info); // Information + if (XFAILED(result) && io_status_block) { + io_status_block->status = result; + io_status_block->information = 0; } if (ev && signal_event) { ev->Set(0, false); } - SHIM_SET_RETURN_32(result); + return result; } +DECLARE_XBOXKRNL_EXPORT(NtReadFile, ExportTag::kImplemented); -SHIM_CALL NtWriteFile_shim(PPCContext* ppc_context, KernelState* kernel_state) { - uint32_t file_handle = SHIM_GET_ARG_32(0); - uint32_t event_handle = SHIM_GET_ARG_32(1); - uint32_t apc_routine_ptr = SHIM_GET_ARG_32(2); - uint32_t apc_context = SHIM_GET_ARG_32(3); - uint32_t io_status_block_ptr = SHIM_GET_ARG_32(4); - uint32_t buffer = SHIM_GET_ARG_32(5); - uint32_t buffer_length = SHIM_GET_ARG_32(6); - uint32_t byte_offset_ptr = SHIM_GET_ARG_32(7); - size_t byte_offset = byte_offset_ptr ? SHIM_MEM_64(byte_offset_ptr) : 0; - - XELOGD("NtWriteFile(%.8X, %.8X, %.8X, %.8X, %.8X, %.8X, %d, %.8X(%d))", - file_handle, event_handle, apc_routine_ptr, apc_context, - io_status_block_ptr, buffer, buffer_length, byte_offset_ptr, - byte_offset); - +dword_result_t NtWriteFile(dword_t file_handle, dword_t event_handle, + function_t apc_routine, lpvoid_t apc_context, + pointer_t io_status_block, + lpvoid_t buffer, dword_t buffer_length, + lpqword_t byte_offset_ptr) { // Async not supported yet. - assert_zero(apc_routine_ptr); + assert_zero(apc_routine); X_STATUS result = X_STATUS_SUCCESS; uint32_t info = 0; // Grab event to signal. bool signal_event = false; - auto ev = - event_handle - ? kernel_state->object_table()->LookupObject(event_handle) - : object_ref(); + auto ev = kernel_state()->object_table()->LookupObject(event_handle); if (event_handle && !ev) { result = X_STATUS_INVALID_HANDLE; } // Grab file. - auto file = kernel_state->object_table()->LookupObject(file_handle); + auto file = kernel_state()->object_table()->LookupObject(file_handle); if (!file) { result = X_STATUS_INVALID_HANDLE; } // Execute write. if (XSUCCEEDED(result)) { - // Reset event before we begin. - if (ev) { - ev->Reset(); - } - // TODO(benvanik): async path. if (true) { // Synchronous request. - if (!byte_offset_ptr || byte_offset == 0xFFFFFFFFfffffffe) { - // FILE_USE_FILE_POINTER_POSITION - byte_offset = -1; - } - - // Write now. size_t bytes_written = 0; - result = file->Write(SHIM_MEM_ADDR(buffer), buffer_length, byte_offset, - &bytes_written); + result = + file->Write(buffer, buffer_length, + byte_offset_ptr ? *byte_offset_ptr : -1, &bytes_written); if (XSUCCEEDED(result)) { info = (int32_t)bytes_written; } @@ -435,17 +292,18 @@ SHIM_CALL NtWriteFile_shim(PPCContext* ppc_context, KernelState* kernel_state) { } } - if (io_status_block_ptr) { - SHIM_SET_MEM_32(io_status_block_ptr, result); // Status - SHIM_SET_MEM_32(io_status_block_ptr + 4, info); // Information + if (io_status_block) { + io_status_block->status = result; + io_status_block->information = info; } if (ev && signal_event) { ev->Set(0, false); } - SHIM_SET_RETURN_32(result); + return result; } +DECLARE_XBOXKRNL_EXPORT(NtWriteFile, ExportTag::kImplemented); dword_result_t NtCreateIoCompletion(lpvoid_t out_handle, dword_t desired_access, lpvoid_t object_attribs, @@ -454,28 +312,25 @@ dword_result_t NtCreateIoCompletion(lpvoid_t out_handle, dword_t desired_access, } DECLARE_XBOXKRNL_EXPORT(NtCreateIoCompletion, ExportTag::kStub); -SHIM_CALL NtSetInformationFile_shim(PPCContext* ppc_context, - KernelState* kernel_state) { - uint32_t file_handle = SHIM_GET_ARG_32(0); - uint32_t io_status_block_ptr = SHIM_GET_ARG_32(1); - uint32_t file_info_ptr = SHIM_GET_ARG_32(2); - uint32_t length = SHIM_GET_ARG_32(3); - uint32_t file_info_class = SHIM_GET_ARG_32(4); - - XELOGD("NtSetInformationFile(%.8X, %.8X, %.8X, %.8X, %.8X)", file_handle, - io_status_block_ptr, file_info_ptr, length, file_info_class); - +dword_result_t NtSetInformationFile( + dword_t file_handle, pointer_t io_status_block, + lpvoid_t file_info, dword_t length, dword_t file_info_class) { X_STATUS result = X_STATUS_SUCCESS; uint32_t info = 0; // Grab file. - auto file = kernel_state->object_table()->LookupObject(file_handle); - if (file) { + auto file = kernel_state()->object_table()->LookupObject(file_handle); + if (!file) { + result = X_STATUS_INVALID_HANDLE; + } + + if (XSUCCEEDED(result)) { switch (file_info_class) { case XFileDispositionInformation: { // Used to set deletion flag. Which we don't support. Probably? info = 0; - bool delete_on_close = SHIM_MEM_8(file_info_ptr) ? true : false; + bool delete_on_close = + (xe::load_and_swap(file_info)) ? true : false; XELOGW("NtSetInformationFile ignoring delete on close: %d", delete_on_close); break; @@ -486,7 +341,7 @@ SHIM_CALL NtSetInformationFile_shim(PPCContext* ppc_context, // }; assert_true(length == 8); info = 8; - file->set_position(SHIM_MEM_64(file_info_ptr)); + file->set_position(xe::load_and_swap(file_info)); break; case XFileAllocationInformation: case XFileEndOfFileInformation: @@ -503,17 +358,16 @@ SHIM_CALL NtSetInformationFile_shim(PPCContext* ppc_context, info = 0; break; } - } else { - result = X_STATUS_INVALID_HANDLE; } - if (io_status_block_ptr) { - SHIM_SET_MEM_32(io_status_block_ptr, result); // Status - SHIM_SET_MEM_32(io_status_block_ptr + 4, info); // Information + if (io_status_block) { + io_status_block->status = result; + io_status_block->information = info; } - SHIM_SET_RETURN_32(result); + return result; } +DECLARE_XBOXKRNL_EXPORT(NtSetInformationFile, ExportTag::kImplemented); struct X_IO_STATUS_BLOCK { union { @@ -575,26 +429,29 @@ dword_result_t NtQueryInformationFile( info = 56; break; } - case XFileXctdCompressionInformation: + case XFileXctdCompressionInformation: { assert_true(length == 4); - /* // This is wrong and puts files into wrong states for games that use // XctdDecompression. uint32_t magic; size_t bytes_read; + size_t cur_pos = file->position(); + + file->set_position(0); result = file->Read(&magic, sizeof(magic), 0, &bytes_read); if (XSUCCEEDED(result)) { if (bytes_read == sizeof(magic)) { info = 4; - SHIM_SET_MEM_32(file_info_ptr, magic == xe::byte_swap(0x0FF512ED) ? - 1 : 0); + *file_info_ptr.as*>() = + magic == xe::byte_swap(0x0FF512ED) ? 1 : 0; } else { result = X_STATUS_UNSUCCESSFUL; } } - */ - result = X_STATUS_UNSUCCESSFUL; - break; + file->set_position(cur_pos); + info = 4; + + } break; case XFileSectorInformation: // TODO: Return sector this file's on. assert_true(length == 4); @@ -623,41 +480,27 @@ dword_result_t NtQueryInformationFile( DECLARE_XBOXKRNL_EXPORT(NtQueryInformationFile, ExportTag::kImplemented | ExportTag::kFileSystem); -SHIM_CALL NtQueryFullAttributesFile_shim(PPCContext* ppc_context, - KernelState* kernel_state) { - uint32_t object_attributes_ptr = SHIM_GET_ARG_32(0); - uint32_t file_info_ptr = SHIM_GET_ARG_32(1); - - X_OBJECT_ATTRIBUTES attrs(SHIM_MEM_BASE, object_attributes_ptr); - - char* object_name = attrs.object_name.Duplicate(); - - XELOGD("NtQueryFullAttributesFile(%.8X(%s), %.8X)", object_attributes_ptr, - !object_name ? "(null)" : object_name, file_info_ptr); - - X_STATUS result = X_STATUS_NO_SUCH_FILE; +dword_result_t NtQueryFullAttributesFile( + pointer_t obj_attribs, + pointer_t file_info) { + auto object_name = + kernel_memory()->TranslateVirtual(obj_attribs->name_ptr); object_ref root_file; - if (attrs.root_directory != 0xFFFFFFFD && // ObDosDevices - attrs.root_directory != 0) { - root_file = - kernel_state->object_table()->LookupObject(attrs.root_directory); + if (obj_attribs->root_directory != 0xFFFFFFFD && // ObDosDevices + obj_attribs->root_directory != 0) { + root_file = kernel_state()->object_table()->LookupObject( + obj_attribs->root_directory); assert_not_null(root_file); assert_true(root_file->type() == XObject::Type::kTypeFile); assert_always(); } // Resolve the file using the virtual file system. - auto fs = kernel_state->file_system(); - auto entry = fs->ResolvePath(object_name); + auto entry = kernel_state()->file_system()->ResolvePath( + object_name->to_string(kernel_memory()->virtual_membase())); if (entry) { // Found. - result = X_STATUS_SUCCESS; - - auto file_info = - kernel_memory()->TranslateVirtual( - file_info_ptr); - file_info->creation_time = entry->create_timestamp(); file_info->last_access_time = entry->access_timestamp(); file_info->last_write_time = entry->write_timestamp(); @@ -665,11 +508,13 @@ SHIM_CALL NtQueryFullAttributesFile_shim(PPCContext* ppc_context, file_info->allocation_size = entry->allocation_size(); file_info->end_of_file = entry->size(); file_info->attributes = entry->attributes(); + + return X_STATUS_SUCCESS; } - free(object_name); - SHIM_SET_RETURN_32(result); + return X_STATUS_NO_SUCH_FILE; } +DECLARE_XBOXKRNL_EXPORT(NtQueryFullAttributesFile, ExportTag::kImplemented); SHIM_CALL NtQueryVolumeInformationFile_shim(PPCContext* ppc_context, KernelState* kernel_state) { @@ -753,43 +598,26 @@ SHIM_CALL NtQueryVolumeInformationFile_shim(PPCContext* ppc_context, SHIM_SET_RETURN_32(result); } -SHIM_CALL NtQueryDirectoryFile_shim(PPCContext* ppc_context, - KernelState* kernel_state) { - uint32_t file_handle = SHIM_GET_ARG_32(0); - uint32_t event_handle = SHIM_GET_ARG_32(1); - uint32_t apc_routine = SHIM_GET_ARG_32(2); - uint32_t apc_context = SHIM_GET_ARG_32(3); - uint32_t io_status_block_ptr = SHIM_GET_ARG_32(4); - uint32_t file_info_ptr = SHIM_GET_ARG_32(5); - uint32_t length = SHIM_GET_ARG_32(6); - uint32_t file_name_ptr = SHIM_GET_ARG_32(7); - uint32_t restart_scan = SHIM_GET_ARG_32(8); - - auto file_name = X_ANSI_STRING::to_string(SHIM_MEM_BASE, file_name_ptr); - - XELOGD( - "NtQueryDirectoryFile(%.8X, %.8X, %.8X, %.8X, %.8X, %.8X, %d, %.8X(%s), " - "%d)", - file_handle, event_handle, apc_routine, apc_context, io_status_block_ptr, - file_info_ptr, length, file_name_ptr, - !file_name.empty() ? file_name.c_str() : "(null)", restart_scan); - +dword_result_t NtQueryDirectoryFile( + dword_t file_handle, dword_t event_handle, function_t apc_routine, + lpvoid_t apc_context, pointer_t io_status_block, + pointer_t file_info_ptr, dword_t length, + pointer_t file_name, dword_t restart_scan) { if (length < 72) { - SHIM_SET_RETURN_32(X_STATUS_INFO_LENGTH_MISMATCH); - return; + return X_STATUS_INFO_LENGTH_MISMATCH; } X_STATUS result = X_STATUS_UNSUCCESSFUL; uint32_t info = 0; - auto file = kernel_state->object_table()->LookupObject(file_handle); + auto file = kernel_state()->object_table()->LookupObject(file_handle); + auto name = file_name->to_string(kernel_memory()->virtual_membase()); if (file) { X_FILE_DIRECTORY_INFORMATION dir_info = {0}; result = file->QueryDirectory( - &dir_info, length, !file_name.empty() ? file_name.c_str() : nullptr, + file_info_ptr, length, !name.empty() ? name.c_str() : nullptr, restart_scan != 0); if (XSUCCEEDED(result)) { - dir_info.Write(SHIM_MEM_BASE, file_info_ptr); info = length; } } else { @@ -799,13 +627,15 @@ SHIM_CALL NtQueryDirectoryFile_shim(PPCContext* ppc_context, if (XFAILED(result)) { info = 0; } - if (io_status_block_ptr) { - SHIM_SET_MEM_32(io_status_block_ptr, result); // Status - SHIM_SET_MEM_32(io_status_block_ptr + 4, info); // Information + + if (io_status_block) { + io_status_block->status = result; + io_status_block->information = info; } - SHIM_SET_RETURN_32(result); + return result; } +DECLARE_XBOXKRNL_EXPORT(NtQueryDirectoryFile, ExportTag::kImplemented); SHIM_CALL NtFlushBuffersFile_shim(PPCContext* ppc_context, KernelState* kernel_state) { @@ -844,14 +674,7 @@ SHIM_CALL FscSetCacheElementCount_shim(PPCContext* ppc_context, void xe::kernel::xboxkrnl::RegisterIoExports( xe::cpu::ExportResolver* export_resolver, KernelState* kernel_state) { - SHIM_SET_MAPPING("xboxkrnl.exe", NtCreateFile, state); - SHIM_SET_MAPPING("xboxkrnl.exe", NtOpenFile, state); - SHIM_SET_MAPPING("xboxkrnl.exe", NtReadFile, state); - SHIM_SET_MAPPING("xboxkrnl.exe", NtWriteFile, state); - SHIM_SET_MAPPING("xboxkrnl.exe", NtSetInformationFile, state); - SHIM_SET_MAPPING("xboxkrnl.exe", NtQueryFullAttributesFile, state); SHIM_SET_MAPPING("xboxkrnl.exe", NtQueryVolumeInformationFile, state); - SHIM_SET_MAPPING("xboxkrnl.exe", NtQueryDirectoryFile, state); SHIM_SET_MAPPING("xboxkrnl.exe", NtFlushBuffersFile, state); SHIM_SET_MAPPING("xboxkrnl.exe", FscSetCacheElementCount, state); diff --git a/src/xenia/kernel/xboxkrnl_modules.cc b/src/xenia/kernel/xboxkrnl_modules.cc index 93ec98442..ebb0f60a5 100644 --- a/src/xenia/kernel/xboxkrnl_modules.cc +++ b/src/xenia/kernel/xboxkrnl_modules.cc @@ -226,7 +226,7 @@ SHIM_CALL XexLoadImage_shim(PPCContext* ppc_context, // Not found; attempt to load as a user module. auto user_module = kernel_state->LoadUserModule(module_name); if (user_module) { - user_module->RetainHandle(); + user_module->Retain(); hmodule = user_module->hmodule_ptr(); result = X_STATUS_SUCCESS; } @@ -263,6 +263,7 @@ SHIM_CALL XexUnloadImage_shim(PPCContext* ppc_context, hmodule); if (--ldr_data->load_count == 0) { // No more references, free it. + module->Release(); kernel_state->object_table()->RemoveHandle(module->handle()); } } diff --git a/src/xenia/xbox.h b/src/xenia/xbox.h index 62c35c4c1..aa2724913 100644 --- a/src/xenia/xbox.h +++ b/src/xenia/xbox.h @@ -44,6 +44,7 @@ typedef uint32_t X_STATUS; #define X_STATUS_NO_MORE_FILES ((X_STATUS)0x80000006L) #define X_STATUS_UNSUCCESSFUL ((X_STATUS)0xC0000001L) #define X_STATUS_NOT_IMPLEMENTED ((X_STATUS)0xC0000002L) +#define X_STATUS_INVALID_INFO_CLASS ((X_STATUS)0xC0000003L) #define X_STATUS_INFO_LENGTH_MISMATCH ((X_STATUS)0xC0000004L) #define X_STATUS_ACCESS_VIOLATION ((X_STATUS)0xC0000005L) #define X_STATUS_INVALID_HANDLE ((X_STATUS)0xC0000008L) @@ -278,6 +279,7 @@ struct X_ANSI_STRING { length); } }; +static_assert_size(X_ANSI_STRING, 8); struct X_UNICODE_STRING { xe::be length; // 0x0 @@ -360,6 +362,12 @@ struct X_EX_TITLE_TERMINATE_REGISTRATION { }; static_assert_size(X_EX_TITLE_TERMINATE_REGISTRATION, 16); +struct X_OBJECT_ATTRIBUTES { + xe::be root_directory; // 0x0 + xe::be name_ptr; // 0x4 PANSI_STRING + xe::be attributes; // 0xC +}; + #pragma pack(pop) } // namespace xe