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