Merge branch 'master' into d3d12
This commit is contained in:
commit
83da671bb4
|
@ -50,7 +50,24 @@ namespace xe {
|
||||||
|
|
||||||
Emulator::Emulator(const std::wstring& command_line,
|
Emulator::Emulator(const std::wstring& command_line,
|
||||||
const std::wstring& content_root)
|
const std::wstring& content_root)
|
||||||
: command_line_(command_line), content_root_(content_root) {}
|
: on_launch(),
|
||||||
|
on_exit(),
|
||||||
|
command_line_(command_line),
|
||||||
|
content_root_(content_root),
|
||||||
|
game_title_(),
|
||||||
|
display_window_(nullptr),
|
||||||
|
memory_(),
|
||||||
|
audio_system_(),
|
||||||
|
graphics_system_(),
|
||||||
|
input_system_(),
|
||||||
|
export_resolver_(),
|
||||||
|
file_system_(),
|
||||||
|
kernel_state_(),
|
||||||
|
main_thread_(),
|
||||||
|
title_id_(0),
|
||||||
|
paused_(false),
|
||||||
|
restoring_(false),
|
||||||
|
restore_fence_() {}
|
||||||
|
|
||||||
Emulator::~Emulator() {
|
Emulator::~Emulator() {
|
||||||
// Note that we delete things in the reverse order they were initialized.
|
// Note that we delete things in the reverse order they were initialized.
|
||||||
|
@ -184,10 +201,13 @@ X_STATUS Emulator::Setup(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define LOAD_KERNEL_MODULE(t) \
|
||||||
|
static_cast<void>(kernel_state_->LoadKernelModule<kernel::t>())
|
||||||
// HLE kernel modules.
|
// HLE kernel modules.
|
||||||
kernel_state_->LoadKernelModule<kernel::xboxkrnl::XboxkrnlModule>();
|
LOAD_KERNEL_MODULE(xboxkrnl::XboxkrnlModule);
|
||||||
kernel_state_->LoadKernelModule<kernel::xam::XamModule>();
|
LOAD_KERNEL_MODULE(xam::XamModule);
|
||||||
kernel_state_->LoadKernelModule<kernel::xbdm::XbdmModule>();
|
LOAD_KERNEL_MODULE(xbdm::XbdmModule);
|
||||||
|
#undef LOAD_KERNEL_MODULE
|
||||||
|
|
||||||
// Initialize emulator fallback exception handling last.
|
// Initialize emulator fallback exception handling last.
|
||||||
ExceptionHandler::Install(Emulator::ExceptionCallbackThunk, this);
|
ExceptionHandler::Install(Emulator::ExceptionCallbackThunk, this);
|
||||||
|
@ -455,7 +475,7 @@ bool Emulator::RestoreFromFile(const std::wstring& path) {
|
||||||
kernel_state_->object_table()->GetObjectsByType<kernel::XThread>();
|
kernel_state_->object_table()->GetObjectsByType<kernel::XThread>();
|
||||||
for (auto thread : threads) {
|
for (auto thread : threads) {
|
||||||
if (thread->main_thread()) {
|
if (thread->main_thread()) {
|
||||||
main_thread_ = thread->thread();
|
main_thread_ = thread;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -557,7 +577,7 @@ bool Emulator::ExceptionCallback(Exception* ex) {
|
||||||
|
|
||||||
void Emulator::WaitUntilExit() {
|
void Emulator::WaitUntilExit() {
|
||||||
while (true) {
|
while (true) {
|
||||||
xe::threading::Wait(main_thread_, false);
|
xe::threading::Wait(main_thread_->thread(), false);
|
||||||
|
|
||||||
if (restoring_) {
|
if (restoring_) {
|
||||||
restore_fence_.Wait();
|
restore_fence_.Wait();
|
||||||
|
@ -642,12 +662,12 @@ X_STATUS Emulator::CompleteLaunch(const std::wstring& path,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto main_xthread = kernel_state_->LaunchModule(module);
|
auto main_thread = kernel_state_->LaunchModule(module);
|
||||||
if (!main_xthread) {
|
if (!main_thread) {
|
||||||
return X_STATUS_UNSUCCESSFUL;
|
return X_STATUS_UNSUCCESSFUL;
|
||||||
}
|
}
|
||||||
|
|
||||||
main_thread_ = main_xthread->thread();
|
main_thread_ = main_thread;
|
||||||
on_launch();
|
on_launch();
|
||||||
|
|
||||||
return X_STATUS_SUCCESS;
|
return X_STATUS_SUCCESS;
|
||||||
|
|
|
@ -175,11 +175,11 @@ class Emulator {
|
||||||
std::unique_ptr<vfs::VirtualFileSystem> file_system_;
|
std::unique_ptr<vfs::VirtualFileSystem> file_system_;
|
||||||
|
|
||||||
std::unique_ptr<kernel::KernelState> kernel_state_;
|
std::unique_ptr<kernel::KernelState> kernel_state_;
|
||||||
threading::Thread* main_thread_ = nullptr;
|
kernel::object_ref<kernel::XThread> main_thread_;
|
||||||
uint32_t title_id_ = 0; // Currently running title ID
|
uint32_t title_id_; // Currently running title ID
|
||||||
|
|
||||||
bool paused_ = false;
|
bool paused_;
|
||||||
bool restoring_ = false;
|
bool restoring_;
|
||||||
threading::Fence restore_fence_; // Fired on restore finish.
|
threading::Fence restore_fence_; // Fired on restore finish.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -19,13 +19,13 @@
|
||||||
#include "xenia/base/string.h"
|
#include "xenia/base/string.h"
|
||||||
#include "xenia/cpu/processor.h"
|
#include "xenia/cpu/processor.h"
|
||||||
#include "xenia/emulator.h"
|
#include "xenia/emulator.h"
|
||||||
#include "xenia/kernel/notify_listener.h"
|
|
||||||
#include "xenia/kernel/user_module.h"
|
#include "xenia/kernel/user_module.h"
|
||||||
#include "xenia/kernel/util/shim_utils.h"
|
#include "xenia/kernel/util/shim_utils.h"
|
||||||
#include "xenia/kernel/xam/xam_module.h"
|
#include "xenia/kernel/xam/xam_module.h"
|
||||||
#include "xenia/kernel/xboxkrnl/xboxkrnl_module.h"
|
#include "xenia/kernel/xboxkrnl/xboxkrnl_module.h"
|
||||||
#include "xenia/kernel/xevent.h"
|
#include "xenia/kernel/xevent.h"
|
||||||
#include "xenia/kernel/xmodule.h"
|
#include "xenia/kernel/xmodule.h"
|
||||||
|
#include "xenia/kernel/xnotifylistener.h"
|
||||||
#include "xenia/kernel/xobject.h"
|
#include "xenia/kernel/xobject.h"
|
||||||
#include "xenia/kernel/xthread.h"
|
#include "xenia/kernel/xthread.h"
|
||||||
|
|
||||||
|
@ -573,7 +573,7 @@ object_ref<XThread> KernelState::GetThreadByID(uint32_t thread_id) {
|
||||||
return retain_object(thread);
|
return retain_object(thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
void KernelState::RegisterNotifyListener(NotifyListener* listener) {
|
void KernelState::RegisterNotifyListener(XNotifyListener* listener) {
|
||||||
auto global_lock = global_critical_region_.Acquire();
|
auto global_lock = global_critical_region_.Acquire();
|
||||||
notify_listeners_.push_back(retain_object(listener));
|
notify_listeners_.push_back(retain_object(listener));
|
||||||
|
|
||||||
|
@ -597,7 +597,7 @@ void KernelState::RegisterNotifyListener(NotifyListener* listener) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void KernelState::UnregisterNotifyListener(NotifyListener* listener) {
|
void KernelState::UnregisterNotifyListener(XNotifyListener* listener) {
|
||||||
auto global_lock = global_critical_region_.Acquire();
|
auto global_lock = global_critical_region_.Acquire();
|
||||||
for (auto it = notify_listeners_.begin(); it != notify_listeners_.end();
|
for (auto it = notify_listeners_.begin(); it != notify_listeners_.end();
|
||||||
++it) {
|
++it) {
|
||||||
|
|
|
@ -48,7 +48,7 @@ class Dispatcher;
|
||||||
class XHostThread;
|
class XHostThread;
|
||||||
class KernelModule;
|
class KernelModule;
|
||||||
class XModule;
|
class XModule;
|
||||||
class NotifyListener;
|
class XNotifyListener;
|
||||||
class XThread;
|
class XThread;
|
||||||
class UserModule;
|
class UserModule;
|
||||||
|
|
||||||
|
@ -158,8 +158,8 @@ class KernelState {
|
||||||
void OnThreadExit(XThread* thread);
|
void OnThreadExit(XThread* thread);
|
||||||
object_ref<XThread> GetThreadByID(uint32_t thread_id);
|
object_ref<XThread> GetThreadByID(uint32_t thread_id);
|
||||||
|
|
||||||
void RegisterNotifyListener(NotifyListener* listener);
|
void RegisterNotifyListener(XNotifyListener* listener);
|
||||||
void UnregisterNotifyListener(NotifyListener* listener);
|
void UnregisterNotifyListener(XNotifyListener* listener);
|
||||||
void BroadcastNotification(XNotificationID id, uint32_t data);
|
void BroadcastNotification(XNotificationID id, uint32_t data);
|
||||||
|
|
||||||
util::NativeList* dpc_list() { return &dpc_list_; }
|
util::NativeList* dpc_list() { return &dpc_list_; }
|
||||||
|
@ -196,7 +196,7 @@ class KernelState {
|
||||||
// Must be guarded by the global critical region.
|
// Must be guarded by the global critical region.
|
||||||
util::ObjectTable object_table_;
|
util::ObjectTable object_table_;
|
||||||
std::unordered_map<uint32_t, XThread*> threads_by_id_;
|
std::unordered_map<uint32_t, XThread*> threads_by_id_;
|
||||||
std::vector<object_ref<NotifyListener>> notify_listeners_;
|
std::vector<object_ref<XNotifyListener>> notify_listeners_;
|
||||||
bool has_notified_startup_ = false;
|
bool has_notified_startup_ = false;
|
||||||
|
|
||||||
uint32_t process_type_ = X_PROCTYPE_USER;
|
uint32_t process_type_ = X_PROCTYPE_USER;
|
||||||
|
|
|
@ -9,9 +9,9 @@
|
||||||
|
|
||||||
#include "xenia/base/logging.h"
|
#include "xenia/base/logging.h"
|
||||||
#include "xenia/kernel/kernel_state.h"
|
#include "xenia/kernel/kernel_state.h"
|
||||||
#include "xenia/kernel/notify_listener.h"
|
|
||||||
#include "xenia/kernel/util/shim_utils.h"
|
#include "xenia/kernel/util/shim_utils.h"
|
||||||
#include "xenia/kernel/xam/xam_private.h"
|
#include "xenia/kernel/xam/xam_private.h"
|
||||||
|
#include "xenia/kernel/xnotifylistener.h"
|
||||||
#include "xenia/xbox.h"
|
#include "xenia/xbox.h"
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
|
@ -23,7 +23,7 @@ dword_result_t XamNotifyCreateListenerInternal(qword_t mask, dword_t unk,
|
||||||
// r4=1 may indicate user process?
|
// r4=1 may indicate user process?
|
||||||
|
|
||||||
auto listener =
|
auto listener =
|
||||||
object_ref<NotifyListener>(new NotifyListener(kernel_state()));
|
object_ref<XNotifyListener>(new XNotifyListener(kernel_state()));
|
||||||
listener->Initialize(mask);
|
listener->Initialize(mask);
|
||||||
|
|
||||||
// Handle ref is incremented, so return that.
|
// Handle ref is incremented, so return that.
|
||||||
|
@ -48,7 +48,7 @@ dword_result_t XNotifyGetNext(dword_t handle, dword_t match_id,
|
||||||
|
|
||||||
// Grab listener.
|
// Grab listener.
|
||||||
auto listener =
|
auto listener =
|
||||||
kernel_state()->object_table()->LookupObject<NotifyListener>(handle);
|
kernel_state()->object_table()->LookupObject<XNotifyListener>(handle);
|
||||||
if (!listener) {
|
if (!listener) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include "xenia/kernel/xevent.h"
|
#include "xenia/kernel/xevent.h"
|
||||||
#include "xenia/kernel/xfile.h"
|
#include "xenia/kernel/xfile.h"
|
||||||
#include "xenia/kernel/xiocompletion.h"
|
#include "xenia/kernel/xiocompletion.h"
|
||||||
|
#include "xenia/kernel/xsymboliclink.h"
|
||||||
#include "xenia/kernel/xthread.h"
|
#include "xenia/kernel/xthread.h"
|
||||||
#include "xenia/vfs/device.h"
|
#include "xenia/vfs/device.h"
|
||||||
#include "xenia/xbox.h"
|
#include "xenia/xbox.h"
|
||||||
|
@ -717,6 +718,64 @@ dword_result_t NtFlushBuffersFile(
|
||||||
}
|
}
|
||||||
DECLARE_XBOXKRNL_EXPORT1(NtFlushBuffersFile, kFileSystem, kStub);
|
DECLARE_XBOXKRNL_EXPORT1(NtFlushBuffersFile, kFileSystem, kStub);
|
||||||
|
|
||||||
|
// https://docs.microsoft.com/en-us/windows/win32/devnotes/ntopensymboliclinkobject
|
||||||
|
dword_result_t NtOpenSymbolicLinkObject(
|
||||||
|
lpdword_t handle_out, pointer_t<X_OBJECT_ATTRIBUTES> object_attrs) {
|
||||||
|
if (!object_attrs) {
|
||||||
|
return X_STATUS_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
assert_not_null(handle_out);
|
||||||
|
|
||||||
|
assert_true(object_attrs->attributes == 64); // case insensitive
|
||||||
|
|
||||||
|
auto object_name =
|
||||||
|
kernel_memory()->TranslateVirtual<X_ANSI_STRING*>(object_attrs->name_ptr);
|
||||||
|
|
||||||
|
std::string target_path =
|
||||||
|
object_name->to_string(kernel_memory()->virtual_membase());
|
||||||
|
if (object_attrs->root_directory != 0) {
|
||||||
|
assert_always();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto pos = target_path.find("\\??\\");
|
||||||
|
if (pos != target_path.npos && pos == 0) {
|
||||||
|
target_path = target_path.substr(4); // Strip the full qualifier
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string link_path;
|
||||||
|
if (!kernel_state()->file_system()->FindSymbolicLink(target_path,
|
||||||
|
link_path)) {
|
||||||
|
return X_STATUS_NO_SUCH_FILE;
|
||||||
|
}
|
||||||
|
|
||||||
|
object_ref<XSymbolicLink> symlink(new XSymbolicLink(kernel_state()));
|
||||||
|
symlink->Initialize(target_path, link_path);
|
||||||
|
|
||||||
|
*handle_out = symlink->handle();
|
||||||
|
|
||||||
|
return X_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
DECLARE_XBOXKRNL_EXPORT1(NtOpenSymbolicLinkObject, kFileSystem, kImplemented);
|
||||||
|
|
||||||
|
// https://docs.microsoft.com/en-us/windows/win32/devnotes/ntquerysymboliclinkobject
|
||||||
|
dword_result_t NtQuerySymbolicLinkObject(dword_t handle,
|
||||||
|
pointer_t<X_ANSI_STRING> target) {
|
||||||
|
auto symlink =
|
||||||
|
kernel_state()->object_table()->LookupObject<XSymbolicLink>(handle);
|
||||||
|
if (!symlink) {
|
||||||
|
return X_STATUS_NO_SUCH_FILE;
|
||||||
|
}
|
||||||
|
auto length = std::min(static_cast<size_t>(target->maximum_length),
|
||||||
|
symlink->target().size());
|
||||||
|
if (length > 0) {
|
||||||
|
auto target_buf = kernel_memory()->TranslateVirtual(target->pointer);
|
||||||
|
std::memcpy(target_buf, symlink->target().c_str(), length);
|
||||||
|
}
|
||||||
|
target->length = static_cast<uint16_t>(length);
|
||||||
|
return X_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
DECLARE_XBOXKRNL_EXPORT1(NtQuerySymbolicLinkObject, kFileSystem, kImplemented);
|
||||||
|
|
||||||
dword_result_t FscGetCacheElementCount(dword_t r3) { return 0; }
|
dword_result_t FscGetCacheElementCount(dword_t r3) { return 0; }
|
||||||
DECLARE_XBOXKRNL_EXPORT1(FscGetCacheElementCount, kFileSystem, kStub);
|
DECLARE_XBOXKRNL_EXPORT1(FscGetCacheElementCount, kFileSystem, kStub);
|
||||||
|
|
||||||
|
|
|
@ -543,6 +543,12 @@ dword_result_t ExAllocatePoolTypeWithTag(dword_t size, dword_t tag,
|
||||||
}
|
}
|
||||||
DECLARE_XBOXKRNL_EXPORT1(ExAllocatePoolTypeWithTag, kMemory, kImplemented);
|
DECLARE_XBOXKRNL_EXPORT1(ExAllocatePoolTypeWithTag, kMemory, kImplemented);
|
||||||
|
|
||||||
|
dword_result_t ExAllocatePool(dword_t size) {
|
||||||
|
const uint32_t none = 0x656E6F4E; // 'None'
|
||||||
|
return ExAllocatePoolTypeWithTag(size, none, 0);
|
||||||
|
}
|
||||||
|
DECLARE_XBOXKRNL_EXPORT1(ExAllocatePool, kMemory, kImplemented);
|
||||||
|
|
||||||
void ExFreePool(lpvoid_t base_address) {
|
void ExFreePool(lpvoid_t base_address) {
|
||||||
kernel_state()->memory()->SystemHeapFree(base_address);
|
kernel_state()->memory()->SystemHeapFree(base_address);
|
||||||
}
|
}
|
||||||
|
|
|
@ -312,6 +312,30 @@ dword_result_t RtlUnicodeToMultiByteN(pointer_t<uint8_t> destination_ptr,
|
||||||
DECLARE_XBOXKRNL_EXPORT3(RtlUnicodeToMultiByteN, kNone, kImplemented,
|
DECLARE_XBOXKRNL_EXPORT3(RtlUnicodeToMultiByteN, kNone, kImplemented,
|
||||||
kHighFrequency, kSketchy);
|
kHighFrequency, kSketchy);
|
||||||
|
|
||||||
|
// https://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/Executable%20Images/RtlImageNtHeader.html
|
||||||
|
pointer_result_t RtlImageNtHeader(lpvoid_t module) {
|
||||||
|
if (!module) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Little-endian! no swapping!
|
||||||
|
|
||||||
|
auto dos_header = module.as<const uint8_t*>();
|
||||||
|
auto dos_magic = *reinterpret_cast<const uint16_t*>(&dos_header[0x00]);
|
||||||
|
if (dos_magic != 0x5A4D) { // 'MZ'
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
auto dos_lfanew = *reinterpret_cast<const int32_t*>(&dos_header[0x3C]);
|
||||||
|
|
||||||
|
auto nt_header = &dos_header[dos_lfanew];
|
||||||
|
auto nt_magic = *reinterpret_cast<const uint32_t*>(&nt_header[0x00]);
|
||||||
|
if (nt_magic != 0x4550) { // 'PE'
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return static_cast<uint32_t>(nt_header - kernel_memory()->virtual_membase());
|
||||||
|
}
|
||||||
|
DECLARE_XBOXKRNL_EXPORT1(RtlImageNtHeader, kNone, kImplemented);
|
||||||
|
|
||||||
pointer_result_t RtlImageXexHeaderField(pointer_t<xex2_header> xex_header,
|
pointer_result_t RtlImageXexHeaderField(pointer_t<xex2_header> xex_header,
|
||||||
dword_t field_dword) {
|
dword_t field_dword) {
|
||||||
uint32_t field_value = 0;
|
uint32_t field_value = 0;
|
||||||
|
|
|
@ -14,7 +14,7 @@ namespace kernel {
|
||||||
|
|
||||||
XEnumerator::XEnumerator(KernelState* kernel_state, size_t items_per_enumerate,
|
XEnumerator::XEnumerator(KernelState* kernel_state, size_t items_per_enumerate,
|
||||||
size_t item_size)
|
size_t item_size)
|
||||||
: XObject(kernel_state, kTypeEnumerator),
|
: XObject(kernel_state, kType),
|
||||||
items_per_enumerate_(items_per_enumerate),
|
items_per_enumerate_(items_per_enumerate),
|
||||||
item_size_(item_size) {}
|
item_size_(item_size) {}
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace kernel {
|
namespace kernel {
|
||||||
|
|
||||||
XEvent::XEvent(KernelState* kernel_state) : XObject(kernel_state, kTypeEvent) {}
|
XEvent::XEvent(KernelState* kernel_state) : XObject(kernel_state, kType) {}
|
||||||
|
|
||||||
XEvent::~XEvent() = default;
|
XEvent::~XEvent() = default;
|
||||||
|
|
||||||
|
|
|
@ -20,13 +20,11 @@ namespace xe {
|
||||||
namespace kernel {
|
namespace kernel {
|
||||||
|
|
||||||
XFile::XFile(KernelState* kernel_state, vfs::File* file, bool synchronous)
|
XFile::XFile(KernelState* kernel_state, vfs::File* file, bool synchronous)
|
||||||
: XObject(kernel_state, kTypeFile),
|
: XObject(kernel_state, kType), file_(file), is_synchronous_(synchronous) {
|
||||||
file_(file),
|
|
||||||
is_synchronous_(synchronous) {
|
|
||||||
async_event_ = threading::Event::CreateAutoResetEvent(false);
|
async_event_ = threading::Event::CreateAutoResetEvent(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
XFile::XFile() : XObject(kTypeFile) {
|
XFile::XFile() : XObject(kType) {
|
||||||
async_event_ = threading::Event::CreateAutoResetEvent(false);
|
async_event_ = threading::Event::CreateAutoResetEvent(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ namespace xe {
|
||||||
namespace kernel {
|
namespace kernel {
|
||||||
|
|
||||||
XIOCompletion::XIOCompletion(KernelState* kernel_state)
|
XIOCompletion::XIOCompletion(KernelState* kernel_state)
|
||||||
: XObject(kernel_state, kTypeIOCompletion) {
|
: XObject(kernel_state, kType) {
|
||||||
notification_semaphore_ = threading::Semaphore::Create(0, kMaxNotifications);
|
notification_semaphore_ = threading::Semaphore::Create(0, kMaxNotifications);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ namespace xe {
|
||||||
namespace kernel {
|
namespace kernel {
|
||||||
|
|
||||||
XModule::XModule(KernelState* kernel_state, ModuleType module_type)
|
XModule::XModule(KernelState* kernel_state, ModuleType module_type)
|
||||||
: XObject(kernel_state, kTypeModule),
|
: XObject(kernel_state, kType),
|
||||||
module_type_(module_type),
|
module_type_(module_type),
|
||||||
processor_module_(nullptr),
|
processor_module_(nullptr),
|
||||||
hmodule_ptr_(0) {
|
hmodule_ptr_(0) {
|
||||||
|
|
|
@ -17,10 +17,9 @@
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace kernel {
|
namespace kernel {
|
||||||
|
|
||||||
XMutant::XMutant() : XObject(kTypeMutant) {}
|
XMutant::XMutant() : XObject(kType) {}
|
||||||
|
|
||||||
XMutant::XMutant(KernelState* kernel_state)
|
XMutant::XMutant(KernelState* kernel_state) : XObject(kernel_state, kType) {}
|
||||||
: XObject(kernel_state, kTypeMutant) {}
|
|
||||||
|
|
||||||
XMutant::~XMutant() = default;
|
XMutant::~XMutant() = default;
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "xenia/kernel/notify_listener.h"
|
#include "xenia/kernel/xnotifylistener.h"
|
||||||
|
|
||||||
#include "xenia/base/byte_stream.h"
|
#include "xenia/base/byte_stream.h"
|
||||||
#include "xenia/kernel/kernel_state.h"
|
#include "xenia/kernel/kernel_state.h"
|
||||||
|
@ -15,12 +15,12 @@
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace kernel {
|
namespace kernel {
|
||||||
|
|
||||||
NotifyListener::NotifyListener(KernelState* kernel_state)
|
XNotifyListener::XNotifyListener(KernelState* kernel_state)
|
||||||
: XObject(kernel_state, kTypeNotifyListener) {}
|
: XObject(kernel_state, kType) {}
|
||||||
|
|
||||||
NotifyListener::~NotifyListener() {}
|
XNotifyListener::~XNotifyListener() {}
|
||||||
|
|
||||||
void NotifyListener::Initialize(uint64_t mask) {
|
void XNotifyListener::Initialize(uint64_t mask) {
|
||||||
assert_false(wait_handle_);
|
assert_false(wait_handle_);
|
||||||
|
|
||||||
wait_handle_ = xe::threading::Event::CreateManualResetEvent(false);
|
wait_handle_ = xe::threading::Event::CreateManualResetEvent(false);
|
||||||
|
@ -29,7 +29,7 @@ void NotifyListener::Initialize(uint64_t mask) {
|
||||||
kernel_state_->RegisterNotifyListener(this);
|
kernel_state_->RegisterNotifyListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NotifyListener::EnqueueNotification(XNotificationID id, uint32_t data) {
|
void XNotifyListener::EnqueueNotification(XNotificationID id, uint32_t data) {
|
||||||
// Ignore if the notification doesn't match our mask.
|
// Ignore if the notification doesn't match our mask.
|
||||||
if ((mask_ & uint64_t(1ULL << (id >> 25))) == 0) {
|
if ((mask_ & uint64_t(1ULL << (id >> 25))) == 0) {
|
||||||
return;
|
return;
|
||||||
|
@ -47,8 +47,8 @@ void NotifyListener::EnqueueNotification(XNotificationID id, uint32_t data) {
|
||||||
wait_handle_->Set();
|
wait_handle_->Set();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NotifyListener::DequeueNotification(XNotificationID* out_id,
|
bool XNotifyListener::DequeueNotification(XNotificationID* out_id,
|
||||||
uint32_t* out_data) {
|
uint32_t* out_data) {
|
||||||
auto global_lock = global_critical_region_.Acquire();
|
auto global_lock = global_critical_region_.Acquire();
|
||||||
bool dequeued = false;
|
bool dequeued = false;
|
||||||
if (notification_count_) {
|
if (notification_count_) {
|
||||||
|
@ -65,8 +65,8 @@ bool NotifyListener::DequeueNotification(XNotificationID* out_id,
|
||||||
return dequeued;
|
return dequeued;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NotifyListener::DequeueNotification(XNotificationID id,
|
bool XNotifyListener::DequeueNotification(XNotificationID id,
|
||||||
uint32_t* out_data) {
|
uint32_t* out_data) {
|
||||||
auto global_lock = global_critical_region_.Acquire();
|
auto global_lock = global_critical_region_.Acquire();
|
||||||
bool dequeued = false;
|
bool dequeued = false;
|
||||||
if (notification_count_) {
|
if (notification_count_) {
|
||||||
|
@ -84,7 +84,7 @@ bool NotifyListener::DequeueNotification(XNotificationID id,
|
||||||
return dequeued;
|
return dequeued;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NotifyListener::Save(ByteStream* stream) {
|
bool XNotifyListener::Save(ByteStream* stream) {
|
||||||
SaveObject(stream);
|
SaveObject(stream);
|
||||||
|
|
||||||
stream->Write(mask_);
|
stream->Write(mask_);
|
||||||
|
@ -99,9 +99,9 @@ bool NotifyListener::Save(ByteStream* stream) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
object_ref<NotifyListener> NotifyListener::Restore(KernelState* kernel_state,
|
object_ref<XNotifyListener> XNotifyListener::Restore(KernelState* kernel_state,
|
||||||
ByteStream* stream) {
|
ByteStream* stream) {
|
||||||
auto notify = new NotifyListener(nullptr);
|
auto notify = new XNotifyListener(nullptr);
|
||||||
notify->kernel_state_ = kernel_state;
|
notify->kernel_state_ = kernel_state;
|
||||||
|
|
||||||
notify->RestoreObject(stream);
|
notify->RestoreObject(stream);
|
||||||
|
@ -115,7 +115,7 @@ object_ref<NotifyListener> NotifyListener::Restore(KernelState* kernel_state,
|
||||||
notify->notifications_.insert(pair);
|
notify->notifications_.insert(pair);
|
||||||
}
|
}
|
||||||
|
|
||||||
return object_ref<NotifyListener>(notify);
|
return object_ref<XNotifyListener>(notify);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace kernel
|
} // namespace kernel
|
|
@ -7,8 +7,8 @@
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef XENIA_KERNEL_NOTIFY_LISTENER_H_
|
#ifndef XENIA_KERNEL_XNOTIFYLISTENER_H_
|
||||||
#define XENIA_KERNEL_NOTIFY_LISTENER_H_
|
#define XENIA_KERNEL_XNOTIFYLISTENER_H_
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
@ -21,12 +21,12 @@
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace kernel {
|
namespace kernel {
|
||||||
|
|
||||||
class NotifyListener : public XObject {
|
class XNotifyListener : public XObject {
|
||||||
public:
|
public:
|
||||||
static const Type kType = kTypeNotifyListener;
|
static const Type kType = kTypeNotifyListener;
|
||||||
|
|
||||||
explicit NotifyListener(KernelState* kernel_state);
|
explicit XNotifyListener(KernelState* kernel_state);
|
||||||
~NotifyListener() override;
|
~XNotifyListener() override;
|
||||||
|
|
||||||
uint64_t mask() const { return mask_; }
|
uint64_t mask() const { return mask_; }
|
||||||
|
|
||||||
|
@ -37,8 +37,8 @@ class NotifyListener : public XObject {
|
||||||
bool DequeueNotification(XNotificationID id, uint32_t* out_data);
|
bool DequeueNotification(XNotificationID id, uint32_t* out_data);
|
||||||
|
|
||||||
bool Save(ByteStream* stream) override;
|
bool Save(ByteStream* stream) override;
|
||||||
static object_ref<NotifyListener> Restore(KernelState* kernel_state,
|
static object_ref<XNotifyListener> Restore(KernelState* kernel_state,
|
||||||
ByteStream* stream);
|
ByteStream* stream);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
xe::threading::WaitHandle* GetWaitHandle() override {
|
xe::threading::WaitHandle* GetWaitHandle() override {
|
||||||
|
@ -56,4 +56,4 @@ class NotifyListener : public XObject {
|
||||||
} // namespace kernel
|
} // namespace kernel
|
||||||
} // namespace xe
|
} // namespace xe
|
||||||
|
|
||||||
#endif // XENIA_KERNEL_NOTIFY_LISTENER_H_
|
#endif // XENIA_KERNEL_XNOTIFYLISTENER_H_
|
|
@ -14,14 +14,15 @@
|
||||||
#include "xenia/base/byte_stream.h"
|
#include "xenia/base/byte_stream.h"
|
||||||
#include "xenia/base/clock.h"
|
#include "xenia/base/clock.h"
|
||||||
#include "xenia/kernel/kernel_state.h"
|
#include "xenia/kernel/kernel_state.h"
|
||||||
#include "xenia/kernel/notify_listener.h"
|
|
||||||
#include "xenia/kernel/xboxkrnl/xboxkrnl_private.h"
|
#include "xenia/kernel/xboxkrnl/xboxkrnl_private.h"
|
||||||
#include "xenia/kernel/xenumerator.h"
|
#include "xenia/kernel/xenumerator.h"
|
||||||
#include "xenia/kernel/xevent.h"
|
#include "xenia/kernel/xevent.h"
|
||||||
#include "xenia/kernel/xfile.h"
|
#include "xenia/kernel/xfile.h"
|
||||||
#include "xenia/kernel/xmodule.h"
|
#include "xenia/kernel/xmodule.h"
|
||||||
#include "xenia/kernel/xmutant.h"
|
#include "xenia/kernel/xmutant.h"
|
||||||
|
#include "xenia/kernel/xnotifylistener.h"
|
||||||
#include "xenia/kernel/xsemaphore.h"
|
#include "xenia/kernel/xsemaphore.h"
|
||||||
|
#include "xenia/kernel/xsymboliclink.h"
|
||||||
#include "xenia/kernel/xthread.h"
|
#include "xenia/kernel/xthread.h"
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
|
@ -139,13 +140,15 @@ object_ref<XObject> XObject::Restore(KernelState* kernel_state, Type type,
|
||||||
case kTypeMutant:
|
case kTypeMutant:
|
||||||
return XMutant::Restore(kernel_state, stream);
|
return XMutant::Restore(kernel_state, stream);
|
||||||
case kTypeNotifyListener:
|
case kTypeNotifyListener:
|
||||||
return NotifyListener::Restore(kernel_state, stream);
|
return XNotifyListener::Restore(kernel_state, stream);
|
||||||
case kTypeSemaphore:
|
case kTypeSemaphore:
|
||||||
return XSemaphore::Restore(kernel_state, stream);
|
return XSemaphore::Restore(kernel_state, stream);
|
||||||
case kTypeSession:
|
case kTypeSession:
|
||||||
break;
|
break;
|
||||||
case kTypeSocket:
|
case kTypeSocket:
|
||||||
break;
|
break;
|
||||||
|
case kTypeSymbolicLink:
|
||||||
|
return XSymbolicLink::Restore(kernel_state, stream);
|
||||||
case kTypeThread:
|
case kTypeThread:
|
||||||
return XThread::Restore(kernel_state, stream);
|
return XThread::Restore(kernel_state, stream);
|
||||||
case kTypeTimer:
|
case kTypeTimer:
|
||||||
|
|
|
@ -121,6 +121,7 @@ class XObject {
|
||||||
kTypeSemaphore,
|
kTypeSemaphore,
|
||||||
kTypeSession,
|
kTypeSession,
|
||||||
kTypeSocket,
|
kTypeSocket,
|
||||||
|
kTypeSymbolicLink,
|
||||||
kTypeThread,
|
kTypeThread,
|
||||||
kTypeTimer,
|
kTypeTimer,
|
||||||
};
|
};
|
||||||
|
|
|
@ -31,12 +31,10 @@
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace kernel {
|
namespace kernel {
|
||||||
|
|
||||||
XSocket::XSocket(KernelState* kernel_state)
|
XSocket::XSocket(KernelState* kernel_state) : XObject(kernel_state, kType) {}
|
||||||
: XObject(kernel_state, XObject::kTypeSocket) {}
|
|
||||||
|
|
||||||
XSocket::XSocket(KernelState* kernel_state, uint64_t native_handle)
|
XSocket::XSocket(KernelState* kernel_state, uint64_t native_handle)
|
||||||
: XObject(kernel_state, XObject::kTypeSocket),
|
: XObject(kernel_state, kType), native_handle_(native_handle) {}
|
||||||
native_handle_(native_handle) {}
|
|
||||||
|
|
||||||
XSocket::~XSocket() { Close(); }
|
XSocket::~XSocket() { Close(); }
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* Xenia : Xbox 360 Emulator Research Project *
|
||||||
|
******************************************************************************
|
||||||
|
* Copyright 2013 Ben Vanik. All rights reserved. *
|
||||||
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "xenia/kernel/xsymboliclink.h"
|
||||||
|
|
||||||
|
#include "xenia/base/byte_stream.h"
|
||||||
|
#include "xenia/kernel/kernel_state.h"
|
||||||
|
|
||||||
|
namespace xe {
|
||||||
|
namespace kernel {
|
||||||
|
|
||||||
|
XSymbolicLink::XSymbolicLink(KernelState* kernel_state)
|
||||||
|
: XObject(kernel_state, kType), path_(), target_() {}
|
||||||
|
|
||||||
|
XSymbolicLink::XSymbolicLink() : XObject(kType), path_(), target_() {}
|
||||||
|
|
||||||
|
XSymbolicLink::~XSymbolicLink() {}
|
||||||
|
|
||||||
|
void XSymbolicLink::Initialize(const std::string& path,
|
||||||
|
const std::string& target) {
|
||||||
|
path_ = path;
|
||||||
|
target_ = target;
|
||||||
|
// TODO(gibbed): kernel_state_->RegisterSymbolicLink(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool XSymbolicLink::Save(ByteStream* stream) {
|
||||||
|
if (!SaveObject(stream)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
stream->Write(path_);
|
||||||
|
stream->Write(target_);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
object_ref<XSymbolicLink> XSymbolicLink::Restore(KernelState* kernel_state,
|
||||||
|
ByteStream* stream) {
|
||||||
|
auto symlink = new XSymbolicLink();
|
||||||
|
symlink->kernel_state_ = kernel_state;
|
||||||
|
if (!symlink->RestoreObject(stream)) {
|
||||||
|
delete symlink;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto path = stream->Read<std::string>();
|
||||||
|
auto target = stream->Read<std::string>();
|
||||||
|
symlink->Initialize(path, target);
|
||||||
|
|
||||||
|
return object_ref<XSymbolicLink>(symlink);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace kernel
|
||||||
|
} // namespace xe
|
|
@ -0,0 +1,50 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* Xenia : Xbox 360 Emulator Research Project *
|
||||||
|
******************************************************************************
|
||||||
|
* Copyright 2013 Ben Vanik. All rights reserved. *
|
||||||
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef XENIA_KERNEL_XSYMBOLICLINK_H_
|
||||||
|
#define XENIA_KERNEL_XSYMBOLICLINK_H_
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
#include "xenia/base/mutex.h"
|
||||||
|
#include "xenia/base/threading.h"
|
||||||
|
#include "xenia/kernel/xobject.h"
|
||||||
|
#include "xenia/xbox.h"
|
||||||
|
|
||||||
|
namespace xe {
|
||||||
|
namespace kernel {
|
||||||
|
|
||||||
|
class XSymbolicLink : public XObject {
|
||||||
|
public:
|
||||||
|
static const Type kType = kTypeSymbolicLink;
|
||||||
|
|
||||||
|
explicit XSymbolicLink(KernelState* kernel_state);
|
||||||
|
~XSymbolicLink() override;
|
||||||
|
|
||||||
|
void Initialize(const std::string& path, const std::string& target);
|
||||||
|
|
||||||
|
bool Save(ByteStream* stream) override;
|
||||||
|
static object_ref<XSymbolicLink> Restore(KernelState* kernel_state,
|
||||||
|
ByteStream* stream);
|
||||||
|
|
||||||
|
const std ::string& path() const { return path_; }
|
||||||
|
const std ::string& target() const { return target_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
XSymbolicLink();
|
||||||
|
|
||||||
|
std::string path_;
|
||||||
|
std::string target_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace kernel
|
||||||
|
} // namespace xe
|
||||||
|
|
||||||
|
#endif // XENIA_KERNEL_XSYMBOLICLINK_H_
|
|
@ -49,13 +49,13 @@ using xe::cpu::ppc::PPCOpcode;
|
||||||
uint32_t next_xthread_id_ = 0;
|
uint32_t next_xthread_id_ = 0;
|
||||||
|
|
||||||
XThread::XThread(KernelState* kernel_state)
|
XThread::XThread(KernelState* kernel_state)
|
||||||
: XObject(kernel_state, kTypeThread), guest_thread_(true) {}
|
: XObject(kernel_state, kType), guest_thread_(true) {}
|
||||||
|
|
||||||
XThread::XThread(KernelState* kernel_state, uint32_t stack_size,
|
XThread::XThread(KernelState* kernel_state, uint32_t stack_size,
|
||||||
uint32_t xapi_thread_startup, uint32_t start_address,
|
uint32_t xapi_thread_startup, uint32_t start_address,
|
||||||
uint32_t start_context, uint32_t creation_flags,
|
uint32_t start_context, uint32_t creation_flags,
|
||||||
bool guest_thread, bool main_thread)
|
bool guest_thread, bool main_thread)
|
||||||
: XObject(kernel_state, kTypeThread),
|
: XObject(kernel_state, kType),
|
||||||
thread_id_(++next_xthread_id_),
|
thread_id_(++next_xthread_id_),
|
||||||
guest_thread_(guest_thread),
|
guest_thread_(guest_thread),
|
||||||
main_thread_(main_thread),
|
main_thread_(main_thread),
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace kernel {
|
namespace kernel {
|
||||||
|
|
||||||
XTimer::XTimer(KernelState* kernel_state) : XObject(kernel_state, kTypeTimer) {}
|
XTimer::XTimer(KernelState* kernel_state) : XObject(kernel_state, kType) {}
|
||||||
|
|
||||||
XTimer::~XTimer() = default;
|
XTimer::~XTimer() = default;
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ class Device {
|
||||||
virtual bool is_read_only() const { return true; }
|
virtual bool is_read_only() const { return true; }
|
||||||
|
|
||||||
virtual void Dump(StringBuffer* string_buffer) = 0;
|
virtual void Dump(StringBuffer* string_buffer) = 0;
|
||||||
virtual Entry* ResolvePath(std::string path) = 0;
|
virtual Entry* ResolvePath(const std::string& path) = 0;
|
||||||
|
|
||||||
virtual uint32_t total_allocation_units() const = 0;
|
virtual uint32_t total_allocation_units() const = 0;
|
||||||
virtual uint32_t available_allocation_units() const = 0;
|
virtual uint32_t available_allocation_units() const = 0;
|
||||||
|
|
|
@ -54,7 +54,7 @@ void DiscImageDevice::Dump(StringBuffer* string_buffer) {
|
||||||
root_entry_->Dump(string_buffer, 0);
|
root_entry_->Dump(string_buffer, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Entry* DiscImageDevice::ResolvePath(std::string path) {
|
Entry* DiscImageDevice::ResolvePath(const std::string& path) {
|
||||||
// The filesystem will have stripped our prefix off already, so the path will
|
// The filesystem will have stripped our prefix off already, so the path will
|
||||||
// be in the form:
|
// be in the form:
|
||||||
// some\PATH.foo
|
// some\PATH.foo
|
||||||
|
|
|
@ -29,7 +29,7 @@ class DiscImageDevice : public Device {
|
||||||
|
|
||||||
bool Initialize() override;
|
bool Initialize() override;
|
||||||
void Dump(StringBuffer* string_buffer) override;
|
void Dump(StringBuffer* string_buffer) override;
|
||||||
Entry* ResolvePath(std::string path) override;
|
Entry* ResolvePath(const std::string& path) override;
|
||||||
|
|
||||||
uint32_t total_allocation_units() const override {
|
uint32_t total_allocation_units() const override {
|
||||||
return uint32_t(mmap_->size() / sectors_per_allocation_unit() /
|
return uint32_t(mmap_->size() / sectors_per_allocation_unit() /
|
||||||
|
|
|
@ -48,7 +48,7 @@ void HostPathDevice::Dump(StringBuffer* string_buffer) {
|
||||||
root_entry_->Dump(string_buffer, 0);
|
root_entry_->Dump(string_buffer, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Entry* HostPathDevice::ResolvePath(std::string path) {
|
Entry* HostPathDevice::ResolvePath(const std::string& path) {
|
||||||
// The filesystem will have stripped our prefix off already, so the path will
|
// The filesystem will have stripped our prefix off already, so the path will
|
||||||
// be in the form:
|
// be in the form:
|
||||||
// some\PATH.foo
|
// some\PATH.foo
|
||||||
|
|
|
@ -27,7 +27,7 @@ class HostPathDevice : public Device {
|
||||||
|
|
||||||
bool Initialize() override;
|
bool Initialize() override;
|
||||||
void Dump(StringBuffer* string_buffer) override;
|
void Dump(StringBuffer* string_buffer) override;
|
||||||
Entry* ResolvePath(std::string path) override;
|
Entry* ResolvePath(const std::string& path) override;
|
||||||
|
|
||||||
bool is_read_only() const override { return read_only_; }
|
bool is_read_only() const override { return read_only_; }
|
||||||
|
|
||||||
|
|
|
@ -149,7 +149,7 @@ void StfsContainerDevice::Dump(StringBuffer* string_buffer) {
|
||||||
root_entry_->Dump(string_buffer, 0);
|
root_entry_->Dump(string_buffer, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Entry* StfsContainerDevice::ResolvePath(std::string path) {
|
Entry* StfsContainerDevice::ResolvePath(const std::string& path) {
|
||||||
// The filesystem will have stripped our prefix off already, so the path will
|
// The filesystem will have stripped our prefix off already, so the path will
|
||||||
// be in the form:
|
// be in the form:
|
||||||
// some\PATH.foo
|
// some\PATH.foo
|
||||||
|
|
|
@ -171,7 +171,7 @@ class StfsContainerDevice : public Device {
|
||||||
|
|
||||||
bool Initialize() override;
|
bool Initialize() override;
|
||||||
void Dump(StringBuffer* string_buffer) override;
|
void Dump(StringBuffer* string_buffer) override;
|
||||||
Entry* ResolvePath(std::string path) override;
|
Entry* ResolvePath(const std::string& path) override;
|
||||||
|
|
||||||
uint32_t total_allocation_units() const override {
|
uint32_t total_allocation_units() const override {
|
||||||
return uint32_t(mmap_total_size_ / sectors_per_allocation_unit() /
|
return uint32_t(mmap_total_size_ / sectors_per_allocation_unit() /
|
||||||
|
|
|
@ -66,15 +66,40 @@ bool VirtualFileSystem::UnregisterSymbolicLink(const std::string& path) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VirtualFileSystem::IsSymbolicLink(const std::string& path) {
|
bool VirtualFileSystem::FindSymbolicLink(const std::string& path,
|
||||||
auto global_lock = global_critical_region_.Acquire();
|
std::string& target) {
|
||||||
auto it = symlinks_.find(path);
|
auto it =
|
||||||
if (it == symlinks_.end()) {
|
std::find_if(symlinks_.cbegin(), symlinks_.cend(), [&](const auto& s) {
|
||||||
|
return xe::find_first_of_case(path, s.first) == 0;
|
||||||
|
});
|
||||||
|
if (it == symlinks_.cend()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
target = (*it).second;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool VirtualFileSystem::ResolveSymbolicLink(const std::string& path,
|
||||||
|
std::string& result) {
|
||||||
|
result = path;
|
||||||
|
bool was_resolved = false;
|
||||||
|
while (true) {
|
||||||
|
auto it =
|
||||||
|
std::find_if(symlinks_.cbegin(), symlinks_.cend(), [&](const auto& s) {
|
||||||
|
return xe::find_first_of_case(result, s.first) == 0;
|
||||||
|
});
|
||||||
|
if (it == symlinks_.cend()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Found symlink!
|
||||||
|
auto target_path = (*it).second;
|
||||||
|
auto relative_path = result.substr((*it).first.size());
|
||||||
|
result = target_path + relative_path;
|
||||||
|
was_resolved = true;
|
||||||
|
}
|
||||||
|
return was_resolved;
|
||||||
|
}
|
||||||
|
|
||||||
Entry* VirtualFileSystem::ResolvePath(const std::string& path) {
|
Entry* VirtualFileSystem::ResolvePath(const std::string& path) {
|
||||||
auto global_lock = global_critical_region_.Acquire();
|
auto global_lock = global_critical_region_.Acquire();
|
||||||
|
|
||||||
|
@ -82,54 +107,24 @@ Entry* VirtualFileSystem::ResolvePath(const std::string& path) {
|
||||||
std::string normalized_path(xe::filesystem::CanonicalizePath(path));
|
std::string normalized_path(xe::filesystem::CanonicalizePath(path));
|
||||||
|
|
||||||
// Resolve symlinks.
|
// Resolve symlinks.
|
||||||
std::string device_path;
|
std::string resolved_path;
|
||||||
std::string relative_path;
|
if (ResolveSymbolicLink(normalized_path, resolved_path)) {
|
||||||
for (int i = 0; i < 2; i++) {
|
normalized_path = resolved_path;
|
||||||
for (const auto& it : symlinks_) {
|
|
||||||
if (xe::find_first_of_case(normalized_path, it.first) == 0) {
|
|
||||||
// Found symlink!
|
|
||||||
device_path = it.second;
|
|
||||||
if (relative_path.empty()) {
|
|
||||||
relative_path = normalized_path.substr(it.first.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bit of a cheaty move here, but allows double symlinks to be resolved.
|
|
||||||
normalized_path = device_path;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Break as soon as we've completely resolved the symlinks to a device.
|
|
||||||
if (!IsSymbolicLink(device_path)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (device_path.empty()) {
|
// Find the device.
|
||||||
// Symlink wasn't passed in - Check if we've received a raw device name.
|
auto it =
|
||||||
for (auto& device : devices_) {
|
std::find_if(devices_.cbegin(), devices_.cend(), [&](const auto& d) {
|
||||||
if (xe::find_first_of_case(normalized_path, device->mount_path()) == 0) {
|
return xe::find_first_of_case(normalized_path, d->mount_path()) == 0;
|
||||||
device_path = device->mount_path();
|
});
|
||||||
relative_path = normalized_path.substr(device_path.size());
|
if (it == devices_.cend()) {
|
||||||
}
|
XELOGE("ResolvePath(%s) failed - device not found", path.c_str());
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (device_path.empty()) {
|
|
||||||
XELOGE("ResolvePath(%s) failed - no root found", path.c_str());
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scan all devices.
|
const auto& device = *it;
|
||||||
for (auto& device : devices_) {
|
auto relative_path = normalized_path.substr(device->mount_path().size());
|
||||||
if (strcasecmp(device_path.c_str(), device->mount_path().c_str()) == 0) {
|
return device->ResolvePath(relative_path);
|
||||||
return device->ResolvePath(relative_path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
XELOGE("ResolvePath(%s) failed - device not found (%s)", path.c_str(),
|
|
||||||
device_path.c_str());
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Entry* VirtualFileSystem::ResolveBasePath(const std::string& path) {
|
Entry* VirtualFileSystem::ResolveBasePath(const std::string& path) {
|
||||||
|
|
|
@ -33,7 +33,7 @@ class VirtualFileSystem {
|
||||||
|
|
||||||
bool RegisterSymbolicLink(const std::string& path, const std::string& target);
|
bool RegisterSymbolicLink(const std::string& path, const std::string& target);
|
||||||
bool UnregisterSymbolicLink(const std::string& path);
|
bool UnregisterSymbolicLink(const std::string& path);
|
||||||
bool IsSymbolicLink(const std::string& path);
|
bool FindSymbolicLink(const std::string& path, std::string& target);
|
||||||
|
|
||||||
Entry* ResolvePath(const std::string& path);
|
Entry* ResolvePath(const std::string& path);
|
||||||
Entry* ResolveBasePath(const std::string& path);
|
Entry* ResolveBasePath(const std::string& path);
|
||||||
|
@ -50,6 +50,8 @@ class VirtualFileSystem {
|
||||||
xe::global_critical_region global_critical_region_;
|
xe::global_critical_region global_critical_region_;
|
||||||
std::vector<std::unique_ptr<Device>> devices_;
|
std::vector<std::unique_ptr<Device>> devices_;
|
||||||
std::unordered_map<std::string, std::string> symlinks_;
|
std::unordered_map<std::string, std::string> symlinks_;
|
||||||
|
|
||||||
|
bool ResolveSymbolicLink(const std::string& path, std::string& result);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace vfs
|
} // namespace vfs
|
||||||
|
|
Loading…
Reference in New Issue