[Kernel/VFS] Cleanup info query/set+sector size.

[VFS] Device now exposes name, attributes, component name max length.
[VFS] Fix STFS device to return 0x200 sector size. XCTD compression
      userland code appears to always expect a sector size of 0x200.
[Kernel] Move X_FILE_*_INFORMATION structs to new files.
[Kernel] Move NtQueryInformationFile, NtSetInformationFile,
         NtQueryVolumeInformationFile to new file.
[Kernel] Cleanup implementation of NtQueryInformationFile,
         NetSetInformationFile, NtQueryVolumeInformationFile.
[Kernel] Properly validate arguments to NtQueryInformationFile,
         NetSetInformationFile, NtQueryVolumeInformationFile.
[Kernel] Properly implement query of XFileFsVolumeInformation.
[Kernel] Properly implement query of XFileFsSizeInformation.
[Kernel] Properly implement query of XFileFsAttributeInformation.
This commit is contained in:
gibbed
2020-04-20 14:54:04 -05:00
committed by Rick Gibbed
parent 087247184d
commit cf0251cd9f
16 changed files with 620 additions and 401 deletions

View File

@@ -11,6 +11,7 @@
#include "xenia/base/memory.h"
#include "xenia/base/mutex.h"
#include "xenia/cpu/processor.h"
#include "xenia/kernel/info/file.h"
#include "xenia/kernel/kernel_state.h"
#include "xenia/kernel/util/shim_utils.h"
#include "xenia/kernel/xboxkrnl/xboxkrnl_private.h"
@@ -26,37 +27,6 @@ namespace xe {
namespace kernel {
namespace xboxkrnl {
// https://msdn.microsoft.com/en-us/library/windows/hardware/ff540287.aspx
struct X_FILE_FS_VOLUME_INFORMATION {
// FILE_FS_VOLUME_INFORMATION
xe::be<uint64_t> creation_time;
xe::be<uint32_t> serial_number;
xe::be<uint32_t> label_length;
xe::be<uint32_t> supports_objects;
char label[1];
};
static_assert_size(X_FILE_FS_VOLUME_INFORMATION, 24);
// https://msdn.microsoft.com/en-us/library/windows/hardware/ff540282.aspx
struct X_FILE_FS_SIZE_INFORMATION {
// FILE_FS_SIZE_INFORMATION
xe::be<uint64_t> total_allocation_units;
xe::be<uint64_t> available_allocation_units;
xe::be<uint32_t> sectors_per_allocation_unit;
xe::be<uint32_t> bytes_per_sector;
};
static_assert_size(X_FILE_FS_SIZE_INFORMATION, 24);
// https://msdn.microsoft.com/en-us/library/windows/hardware/ff540251(v=vs.85).aspx
struct X_FILE_FS_ATTRIBUTE_INFORMATION {
// FILE_FS_ATTRIBUTE_INFORMATION
xe::be<uint32_t> attributes;
xe::be<int32_t> maximum_component_name_length;
xe::be<uint32_t> fs_name_length;
char fs_name[1];
};
static_assert_size(X_FILE_FS_ATTRIBUTE_INFORMATION, 16);
struct CreateOptions {
// https://processhacker.sourceforge.io/doc/ntioapi_8h.html
static const uint32_t FILE_DIRECTORY_FILE = 0x00000001;
@@ -355,207 +325,6 @@ dword_result_t NtRemoveIoCompletion(
}
DECLARE_XBOXKRNL_EXPORT1(NtRemoveIoCompletion, kFileSystem, kImplemented);
dword_result_t NtSetInformationFile(
dword_t file_handle, pointer_t<X_IO_STATUS_BLOCK> 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<XFile>(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 =
(xe::load_and_swap<uint8_t>(file_info)) ? true : false;
XELOGW("NtSetInformationFile ignoring delete on close: {}",
delete_on_close);
break;
}
case XFilePositionInformation:
// struct FILE_POSITION_INFORMATION {
// LARGE_INTEGER CurrentByteOffset;
// };
assert_true(length == 8);
info = 8;
file->set_position(xe::load_and_swap<uint64_t>(file_info));
break;
case XFileAllocationInformation:
assert_true(length == 8);
info = 8;
XELOGW("NtSetInformationFile ignoring alloc");
break;
case XFileEndOfFileInformation: {
assert_true(length == 8);
auto eof = xe::load_and_swap<uint64_t>(file_info);
result = file->SetLength(eof);
// Update the files vfs::Entry information
file->entry()->update();
break;
}
case XFileCompletionInformation: {
// Info contains IO Completion handle and completion key
assert_true(length == 8);
auto handle = xe::load_and_swap<uint32_t>(file_info + 0x0);
auto key = xe::load_and_swap<uint32_t>(file_info + 0x4);
auto port =
kernel_state()->object_table()->LookupObject<XIOCompletion>(handle);
if (!port) {
result = X_STATUS_INVALID_HANDLE;
break;
}
file->RegisterIOCompletionPort(key, port);
break;
}
default:
// Unsupported, for now.
assert_always();
info = 0;
break;
}
}
if (io_status_block) {
io_status_block->status = result;
io_status_block->information = info;
}
return result;
}
DECLARE_XBOXKRNL_EXPORT2(NtSetInformationFile, kFileSystem, kImplemented,
kHighFrequency);
struct X_IO_STATUS_BLOCK {
union {
xe::be<uint32_t> status;
xe::be<uint32_t> pointer;
};
xe::be<uint32_t> information;
};
dword_result_t NtQueryInformationFile(
dword_t file_handle, pointer_t<X_IO_STATUS_BLOCK> io_status_block_ptr,
lpvoid_t file_info_ptr, 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<XFile>(file_handle);
if (file) {
switch (file_info_class) {
case XFileInternalInformation:
// Internal unique file pointer. Not sure why anyone would want this.
assert_true(length == 8);
info = 8;
// TODO(benvanik): use pointer to fs:: entry?
xe::store_and_swap<uint64_t>(file_info_ptr,
xe::memory::hash_combine(0, file->path()));
break;
case XFilePositionInformation:
// struct FILE_POSITION_INFORMATION {
// LARGE_INTEGER CurrentByteOffset;
// };
assert_true(length == 8);
info = 8;
xe::store_and_swap<uint64_t>(file_info_ptr, file->position());
break;
case XFileNetworkOpenInformation: {
// struct FILE_NETWORK_OPEN_INFORMATION {
// LARGE_INTEGER CreationTime;
// LARGE_INTEGER LastAccessTime;
// LARGE_INTEGER LastWriteTime;
// LARGE_INTEGER ChangeTime;
// LARGE_INTEGER AllocationSize;
// LARGE_INTEGER EndOfFile;
// ULONG FileAttributes;
// ULONG Unknown;
// };
assert_true(length == 56);
// Make sure we're working with up-to-date information, just in case the
// file size has changed via something other than NtSetInfoFile
// (eg. seems NtWriteFile might extend the file in some cases)
file->entry()->update();
auto file_info = file_info_ptr.as<X_FILE_NETWORK_OPEN_INFORMATION*>();
file_info->creation_time = file->entry()->create_timestamp();
file_info->last_access_time = file->entry()->access_timestamp();
file_info->last_write_time = file->entry()->write_timestamp();
file_info->change_time = file->entry()->write_timestamp();
file_info->allocation_size = file->entry()->allocation_size();
file_info->end_of_file = file->entry()->size();
file_info->attributes = file->entry()->attributes();
info = 56;
break;
}
case XFileXctdCompressionInformation: {
assert_true(length == 4);
XELOGE(
"NtQueryInformationFile(XFileXctdCompressionInformation) "
"unimplemented");
// This is wrong and puts files into wrong states for games that use
// XctdDecompression.
/*
uint32_t magic;
uint32_t bytes_read;
uint64_t cur_pos = file->position();
file->set_position(0);
// FIXME(Triang3l): For now, XFile can be read only to guest buffers -
// this line won't work, implement reading to host buffers if needed.
result = file->Read(&magic, sizeof(magic), 0, &bytes_read);
if (XSUCCEEDED(result)) {
if (bytes_read == sizeof(magic)) {
info = 4;
*file_info_ptr.as<xe::be<uint32_t>*>() =
magic == xe::byte_swap(0x0FF512ED) ? 1 : 0;
} else {
result = X_STATUS_UNSUCCESSFUL;
}
}
file->set_position(cur_pos);
info = 4;
*/
xe::store_and_swap<uint32_t>(file_info_ptr, 0);
result = X_STATUS_UNSUCCESSFUL;
info = 0;
} break;
case XFileSectorInformation:
// TODO(benvanik): return sector this file's on.
assert_true(length == 4);
XELOGE("NtQueryInformationFile(XFileSectorInformation) unimplemented");
result = X_STATUS_UNSUCCESSFUL;
info = 0;
break;
default:
// Unsupported, for now.
assert_always();
info = 0;
result = X_STATUS_UNSUCCESSFUL;
break;
}
} else {
result = X_STATUS_INVALID_HANDLE;
}
if (io_status_block_ptr) {
io_status_block_ptr->status = result;
io_status_block_ptr->information = info; // # bytes written
}
return result;
}
DECLARE_XBOXKRNL_EXPORT1(NtQueryInformationFile, kFileSystem, kImplemented);
dword_result_t NtQueryFullAttributesFile(
pointer_t<X_OBJECT_ATTRIBUTES> obj_attribs,
pointer_t<X_FILE_NETWORK_OPEN_INFORMATION> file_info) {
@@ -592,82 +361,6 @@ dword_result_t NtQueryFullAttributesFile(
}
DECLARE_XBOXKRNL_EXPORT1(NtQueryFullAttributesFile, kFileSystem, kImplemented);
dword_result_t NtQueryVolumeInformationFile(
dword_t file_handle, pointer_t<X_IO_STATUS_BLOCK> io_status_block_ptr,
lpvoid_t fs_info_ptr, dword_t length, dword_t fs_info_class) {
X_STATUS result = X_STATUS_SUCCESS;
uint32_t info = 0;
// Grab file.
auto file = kernel_state()->object_table()->LookupObject<XFile>(file_handle);
if (file) {
switch (fs_info_class) {
case 1: { // FileFsVolumeInformation
// TODO(gibbed): actual value
std::string name = "test";
X_FILE_FS_VOLUME_INFORMATION* volume_info =
fs_info_ptr.as<X_FILE_FS_VOLUME_INFORMATION*>();
volume_info->creation_time = 0;
volume_info->serial_number = 12345678;
volume_info->supports_objects = 0;
volume_info->label_length = uint32_t(name.size());
std::memcpy(volume_info->label, name.data(), name.size());
info = length;
break;
}
case 3: { // FileFsSizeInformation
X_FILE_FS_SIZE_INFORMATION* fs_size_info =
fs_info_ptr.as<X_FILE_FS_SIZE_INFORMATION*>();
fs_size_info->total_allocation_units =
file->device()->total_allocation_units();
fs_size_info->available_allocation_units =
file->device()->available_allocation_units();
fs_size_info->sectors_per_allocation_unit =
file->device()->sectors_per_allocation_unit();
fs_size_info->bytes_per_sector = file->device()->bytes_per_sector();
info = length;
break;
}
case 5: { // FileFsAttributeInformation
// TODO(gibbed): actual value
std::string name = "test";
X_FILE_FS_ATTRIBUTE_INFORMATION* fs_attribute_info =
fs_info_ptr.as<X_FILE_FS_ATTRIBUTE_INFORMATION*>();
fs_attribute_info->attributes = 0;
fs_attribute_info->maximum_component_name_length = 255;
fs_attribute_info->fs_name_length = uint32_t(name.size());
std::memcpy(fs_attribute_info->fs_name, name.data(), name.size());
info = length;
break;
}
case 2: // FileFsLabelInformation
case 4: // FileFsDeviceInformation
case 6: // FileFsControlInformation
case 7: // FileFsFullSizeInformation
case 8: // FileFsObjectIdInformation
default:
// Unsupported, for now.
assert_always();
info = 0;
break;
}
} else {
result = X_STATUS_NO_SUCH_FILE;
}
if (XFAILED(result)) {
info = 0;
}
if (io_status_block_ptr) {
io_status_block_ptr->status = result;
io_status_block_ptr->information = info;
}
return result;
}
DECLARE_XBOXKRNL_EXPORT1(NtQueryVolumeInformationFile, kFileSystem,
kImplemented);
dword_result_t NtQueryDirectoryFile(
dword_t file_handle, dword_t event_handle, function_t apc_routine,
lpvoid_t apc_context, pointer_t<X_IO_STATUS_BLOCK> io_status_block,

View File

@@ -0,0 +1,358 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2020 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include "xenia/base/logging.h"
#include "xenia/base/memory.h"
#include "xenia/base/mutex.h"
#include "xenia/cpu/processor.h"
#include "xenia/kernel/info/file.h"
#include "xenia/kernel/info/volume.h"
#include "xenia/kernel/kernel_state.h"
#include "xenia/kernel/util/shim_utils.h"
#include "xenia/kernel/xboxkrnl/xboxkrnl_private.h"
#include "xenia/kernel/xevent.h"
#include "xenia/kernel/xfile.h"
#include "xenia/kernel/xiocompletion.h"
#include "xenia/kernel/xsymboliclink.h"
#include "xenia/kernel/xthread.h"
#include "xenia/vfs/device.h"
#include "xenia/xbox.h"
namespace xe {
namespace kernel {
namespace xboxkrnl {
uint32_t GetQueryFileInfoMinimumLength(uint32_t info_class) {
switch (info_class) {
case XFileInternalInformation:
return sizeof(X_FILE_INTERNAL_INFORMATION);
case XFilePositionInformation:
return sizeof(X_FILE_POSITION_INFORMATION);
case XFileXctdCompressionInformation:
return sizeof(X_FILE_XCTD_COMPRESSION_INFORMATION);
case XFileNetworkOpenInformation:
return sizeof(X_FILE_NETWORK_OPEN_INFORMATION);
// TODO(gibbed): structures to get the size of.
case XFileModeInformation:
case XFileAlignmentInformation:
case XFileSectorInformation:
case XFileIoPriorityInformation:
return 4;
case XFileNameInformation:
case XFileAllocationInformation:
return 8;
case XFileBasicInformation:
return 40;
default:
return 0;
}
}
dword_result_t NtQueryInformationFile(
dword_t file_handle, pointer_t<X_IO_STATUS_BLOCK> io_status_block_ptr,
lpvoid_t info_ptr, dword_t info_length, dword_t info_class) {
uint32_t minimum_length = GetQueryFileInfoMinimumLength(info_class);
if (!minimum_length) {
return X_STATUS_INVALID_INFO_CLASS;
}
if (info_length < minimum_length) {
return X_STATUS_INFO_LENGTH_MISMATCH;
}
auto file = kernel_state()->object_table()->LookupObject<XFile>(file_handle);
if (!file) {
return X_STATUS_INVALID_HANDLE;
}
info_ptr.Zero(info_length);
X_STATUS status = X_STATUS_SUCCESS;
uint32_t out_length;
switch (info_class) {
case XFileInternalInformation: {
// Internal unique file pointer. Not sure why anyone would want this.
// TODO(benvanik): use pointer to fs::entry?
auto info = info_ptr.as<X_FILE_INTERNAL_INFORMATION*>();
info->index_number = xe::memory::hash_combine(0, file->path());
out_length = sizeof(*info);
break;
}
case XFilePositionInformation: {
auto info = info_ptr.as<X_FILE_POSITION_INFORMATION*>();
info->current_byte_offset = file->position();
out_length = sizeof(*info);
break;
}
case XFileSectorInformation: {
// TODO(benvanik): return sector this file's on.
XELOGE("NtQueryInformationFile(XFileSectorInformation) unimplemented");
status = X_STATUS_INVALID_PARAMETER;
out_length = 0;
break;
}
case XFileXctdCompressionInformation: {
XELOGE(
"NtQueryInformationFile(XFileXctdCompressionInformation) "
"unimplemented");
// Files that are XCTD compressed begin with the magic 0x0FF512ED but we
// shouldn't detect this that way. There's probably a flag somewhere
// (attributes?) that defines if it's compressed or not.
status = X_STATUS_INVALID_PARAMETER;
out_length = 0;
break;
};
case XFileNetworkOpenInformation: {
// Make sure we're working with up-to-date information, just in case the
// file size has changed via something other than NtSetInfoFile
// (eg. seems NtWriteFile might extend the file in some cases)
file->entry()->update();
auto info = info_ptr.as<X_FILE_NETWORK_OPEN_INFORMATION*>();
info->creation_time = file->entry()->create_timestamp();
info->last_access_time = file->entry()->access_timestamp();
info->last_write_time = file->entry()->write_timestamp();
info->change_time = file->entry()->write_timestamp();
info->allocation_size = file->entry()->allocation_size();
info->end_of_file = file->entry()->size();
info->attributes = file->entry()->attributes();
out_length = sizeof(*info);
break;
}
default: {
// Unsupported, for now.
assert_always();
status = X_STATUS_INVALID_PARAMETER;
out_length = 0;
break;
}
}
if (io_status_block_ptr) {
io_status_block_ptr->status = status;
io_status_block_ptr->information = out_length;
}
return status;
}
DECLARE_XBOXKRNL_EXPORT1(NtQueryInformationFile, kFileSystem, kImplemented);
uint32_t GetSetFileInfoMinimumLength(uint32_t info_class) {
switch (info_class) {
case XFileDispositionInformation:
return sizeof(X_FILE_DISPOSITION_INFORMATION);
case XFilePositionInformation:
return sizeof(X_FILE_POSITION_INFORMATION);
case XFileCompletionInformation:
return sizeof(X_FILE_COMPLETION_INFORMATION);
// TODO(gibbed): structures to get the size of.
case XFileModeInformation:
case XFileIoPriorityInformation:
return 4;
case XFileAllocationInformation:
case XFileEndOfFileInformation:
case XFileMountPartitionInformation:
return 8;
case XFileRenameInformation:
case XFileLinkInformation:
return 16;
case XFileBasicInformation:
return 40;
case XFileMountPartitionsInformation:
return 152;
default:
return 0;
}
}
dword_result_t NtSetInformationFile(
dword_t file_handle, pointer_t<X_IO_STATUS_BLOCK> io_status_block,
lpvoid_t info_ptr, dword_t info_length, dword_t info_class) {
uint32_t minimum_length = GetSetFileInfoMinimumLength(info_class);
if (!minimum_length) {
return X_STATUS_INVALID_INFO_CLASS;
}
if (info_length < minimum_length) {
return X_STATUS_INFO_LENGTH_MISMATCH;
}
auto file = kernel_state()->object_table()->LookupObject<XFile>(file_handle);
if (!file) {
return X_STATUS_INVALID_HANDLE;
}
X_STATUS result = X_STATUS_SUCCESS;
uint32_t out_length;
switch (info_class) {
case XFileDispositionInformation: {
// Used to set deletion flag. Which we don't support. Probably?
auto info = info_ptr.as<X_FILE_DISPOSITION_INFORMATION*>();
bool delete_on_close = info->delete_file ? true : false;
out_length = 0;
XELOGW("NtSetInformationFile ignoring delete on close: {}",
delete_on_close);
break;
}
case XFilePositionInformation: {
auto info = info_ptr.as<X_FILE_POSITION_INFORMATION*>();
file->set_position(info->current_byte_offset);
out_length = sizeof(*info);
break;
}
case XFileAllocationInformation: {
XELOGW("NtSetInformationFile ignoring alloc");
out_length = 8;
break;
}
case XFileEndOfFileInformation: {
auto info = info_ptr.as<X_FILE_END_OF_FILE_INFORMATION*>();
result = file->SetLength(info->end_of_file);
out_length = sizeof(*info);
// Update the files vfs::Entry information
file->entry()->update();
break;
}
case XFileCompletionInformation: {
// Info contains IO Completion handle and completion key
auto info = info_ptr.as<X_FILE_COMPLETION_INFORMATION*>();
auto handle = uint32_t(info->handle);
auto key = uint32_t(info->key);
out_length = sizeof(*info);
auto port =
kernel_state()->object_table()->LookupObject<XIOCompletion>(handle);
if (!port) {
result = X_STATUS_INVALID_HANDLE;
} else {
file->RegisterIOCompletionPort(key, port);
}
break;
}
default:
// Unsupported, for now.
assert_always();
out_length = 0;
break;
}
if (io_status_block) {
io_status_block->status = result;
io_status_block->information = out_length;
}
return result;
}
DECLARE_XBOXKRNL_EXPORT2(NtSetInformationFile, kFileSystem, kImplemented,
kHighFrequency);
uint32_t GetQueryVolumeInfoMinimumLength(uint32_t info_class) {
switch (info_class) {
case XFileFsVolumeInformation:
return sizeof(X_FILE_FS_VOLUME_INFORMATION);
case XFileFsSizeInformation:
return sizeof(X_FILE_FS_SIZE_INFORMATION);
case XFileFsAttributeInformation:
return sizeof(X_FILE_FS_ATTRIBUTE_INFORMATION);
// TODO(gibbed): structures to get the size of.
case XFileFsDeviceInformation:
return 8;
default:
return 0;
}
}
dword_result_t NtQueryVolumeInformationFile(
dword_t file_handle, pointer_t<X_IO_STATUS_BLOCK> io_status_block_ptr,
lpvoid_t info_ptr, dword_t info_length, dword_t info_class) {
uint32_t minimum_length = GetQueryVolumeInfoMinimumLength(info_class);
if (!minimum_length) {
return X_STATUS_INVALID_INFO_CLASS;
}
if (info_length < minimum_length) {
return X_STATUS_INFO_LENGTH_MISMATCH;
}
auto file = kernel_state()->object_table()->LookupObject<XFile>(file_handle);
if (!file) {
return X_STATUS_INVALID_HANDLE;
}
info_ptr.Zero(info_length);
X_STATUS status = X_STATUS_SUCCESS;
uint32_t out_length;
switch (info_class) {
case XFileFsVolumeInformation: {
auto info = info_ptr.as<X_FILE_FS_VOLUME_INFORMATION*>();
info->creation_time = 0;
info->serial_number = 0; // set for FATX, but we don't do that currently
info->supports_objects = 0;
info->label_length = 0;
out_length = offsetof(X_FILE_FS_VOLUME_INFORMATION, label);
break;
}
case XFileFsSizeInformation: {
auto device = file->device();
auto info = info_ptr.as<X_FILE_FS_SIZE_INFORMATION*>();
info->total_allocation_units = device->total_allocation_units();
info->available_allocation_units = device->available_allocation_units();
info->sectors_per_allocation_unit = device->sectors_per_allocation_unit();
info->bytes_per_sector = device->bytes_per_sector();
// TODO(gibbed): sanity check, XCTD userland code seems to require this.
assert_true(info->bytes_per_sector == 0x200);
out_length = sizeof(*info);
break;
}
case XFileFsAttributeInformation: {
auto device = file->device();
const auto& name = device->name();
auto info = info_ptr.as<X_FILE_FS_ATTRIBUTE_INFORMATION*>();
info->attributes = device->attributes();
info->component_name_max_length = device->component_name_max_length();
info->name_length = uint32_t(name.size());
if (info_length >= 12 + name.size()) {
std::memcpy(info->name, name.data(), name.size());
out_length =
offsetof(X_FILE_FS_ATTRIBUTE_INFORMATION, name) + info->name_length;
} else {
status = X_STATUS_BUFFER_OVERFLOW;
out_length = offsetof(X_FILE_FS_ATTRIBUTE_INFORMATION, name);
}
break;
}
case XFileFsDeviceInformation:
default: {
// Unsupported, for now.
assert_always();
out_length = 0;
break;
}
}
if (io_status_block_ptr) {
io_status_block_ptr->status = status;
io_status_block_ptr->information = out_length;
}
return status;
}
DECLARE_XBOXKRNL_EXPORT1(NtQueryVolumeInformationFile, kFileSystem,
kImplemented);
void RegisterIoInfoExports(xe::cpu::ExportResolver* export_resolver,
KernelState* kernel_state) {}
} // namespace xboxkrnl
} // namespace kernel
} // namespace xe

View File

@@ -91,6 +91,7 @@ XboxkrnlModule::XboxkrnlModule(Emulator* emulator, KernelState* kernel_state)
RegisterHalExports(export_resolver_, kernel_state_);
RegisterHidExports(export_resolver_, kernel_state_);
RegisterIoExports(export_resolver_, kernel_state_);
RegisterIoInfoExports(export_resolver_, kernel_state_);
RegisterMemoryExports(export_resolver_, kernel_state_);
RegisterMiscExports(export_resolver_, kernel_state_);
RegisterModuleExports(export_resolver_, kernel_state_);

View File

@@ -2,7 +2,7 @@
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2013 Ben Vanik. All rights reserved. *
* Copyright 2020 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
@@ -32,6 +32,7 @@ DECLARE_REGISTER_EXPORTS(Error);
DECLARE_REGISTER_EXPORTS(Hal);
DECLARE_REGISTER_EXPORTS(Hid);
DECLARE_REGISTER_EXPORTS(Io);
DECLARE_REGISTER_EXPORTS(IoInfo);
DECLARE_REGISTER_EXPORTS(Memory);
DECLARE_REGISTER_EXPORTS(Misc);
DECLARE_REGISTER_EXPORTS(Module);