Merge branch 'master' into d3d12

This commit is contained in:
Triang3l 2019-07-30 07:59:38 +03:00
commit 83da671bb4
32 changed files with 334 additions and 121 deletions

View File

@ -50,7 +50,24 @@ namespace xe {
Emulator::Emulator(const std::wstring& command_line,
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() {
// 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.
kernel_state_->LoadKernelModule<kernel::xboxkrnl::XboxkrnlModule>();
kernel_state_->LoadKernelModule<kernel::xam::XamModule>();
kernel_state_->LoadKernelModule<kernel::xbdm::XbdmModule>();
LOAD_KERNEL_MODULE(xboxkrnl::XboxkrnlModule);
LOAD_KERNEL_MODULE(xam::XamModule);
LOAD_KERNEL_MODULE(xbdm::XbdmModule);
#undef LOAD_KERNEL_MODULE
// Initialize emulator fallback exception handling last.
ExceptionHandler::Install(Emulator::ExceptionCallbackThunk, this);
@ -455,7 +475,7 @@ bool Emulator::RestoreFromFile(const std::wstring& path) {
kernel_state_->object_table()->GetObjectsByType<kernel::XThread>();
for (auto thread : threads) {
if (thread->main_thread()) {
main_thread_ = thread->thread();
main_thread_ = thread;
break;
}
}
@ -557,7 +577,7 @@ bool Emulator::ExceptionCallback(Exception* ex) {
void Emulator::WaitUntilExit() {
while (true) {
xe::threading::Wait(main_thread_, false);
xe::threading::Wait(main_thread_->thread(), false);
if (restoring_) {
restore_fence_.Wait();
@ -642,12 +662,12 @@ X_STATUS Emulator::CompleteLaunch(const std::wstring& path,
}
}
auto main_xthread = kernel_state_->LaunchModule(module);
if (!main_xthread) {
auto main_thread = kernel_state_->LaunchModule(module);
if (!main_thread) {
return X_STATUS_UNSUCCESSFUL;
}
main_thread_ = main_xthread->thread();
main_thread_ = main_thread;
on_launch();
return X_STATUS_SUCCESS;

View File

@ -175,11 +175,11 @@ class Emulator {
std::unique_ptr<vfs::VirtualFileSystem> file_system_;
std::unique_ptr<kernel::KernelState> kernel_state_;
threading::Thread* main_thread_ = nullptr;
uint32_t title_id_ = 0; // Currently running title ID
kernel::object_ref<kernel::XThread> main_thread_;
uint32_t title_id_; // Currently running title ID
bool paused_ = false;
bool restoring_ = false;
bool paused_;
bool restoring_;
threading::Fence restore_fence_; // Fired on restore finish.
};

View File

@ -19,13 +19,13 @@
#include "xenia/base/string.h"
#include "xenia/cpu/processor.h"
#include "xenia/emulator.h"
#include "xenia/kernel/notify_listener.h"
#include "xenia/kernel/user_module.h"
#include "xenia/kernel/util/shim_utils.h"
#include "xenia/kernel/xam/xam_module.h"
#include "xenia/kernel/xboxkrnl/xboxkrnl_module.h"
#include "xenia/kernel/xevent.h"
#include "xenia/kernel/xmodule.h"
#include "xenia/kernel/xnotifylistener.h"
#include "xenia/kernel/xobject.h"
#include "xenia/kernel/xthread.h"
@ -573,7 +573,7 @@ object_ref<XThread> KernelState::GetThreadByID(uint32_t thread_id) {
return retain_object(thread);
}
void KernelState::RegisterNotifyListener(NotifyListener* listener) {
void KernelState::RegisterNotifyListener(XNotifyListener* listener) {
auto global_lock = global_critical_region_.Acquire();
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();
for (auto it = notify_listeners_.begin(); it != notify_listeners_.end();
++it) {

View File

@ -48,7 +48,7 @@ class Dispatcher;
class XHostThread;
class KernelModule;
class XModule;
class NotifyListener;
class XNotifyListener;
class XThread;
class UserModule;
@ -158,8 +158,8 @@ class KernelState {
void OnThreadExit(XThread* thread);
object_ref<XThread> GetThreadByID(uint32_t thread_id);
void RegisterNotifyListener(NotifyListener* listener);
void UnregisterNotifyListener(NotifyListener* listener);
void RegisterNotifyListener(XNotifyListener* listener);
void UnregisterNotifyListener(XNotifyListener* listener);
void BroadcastNotification(XNotificationID id, uint32_t data);
util::NativeList* dpc_list() { return &dpc_list_; }
@ -196,7 +196,7 @@ class KernelState {
// Must be guarded by the global critical region.
util::ObjectTable object_table_;
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;
uint32_t process_type_ = X_PROCTYPE_USER;

View File

@ -9,9 +9,9 @@
#include "xenia/base/logging.h"
#include "xenia/kernel/kernel_state.h"
#include "xenia/kernel/notify_listener.h"
#include "xenia/kernel/util/shim_utils.h"
#include "xenia/kernel/xam/xam_private.h"
#include "xenia/kernel/xnotifylistener.h"
#include "xenia/xbox.h"
namespace xe {
@ -23,7 +23,7 @@ dword_result_t XamNotifyCreateListenerInternal(qword_t mask, dword_t unk,
// r4=1 may indicate user process?
auto listener =
object_ref<NotifyListener>(new NotifyListener(kernel_state()));
object_ref<XNotifyListener>(new XNotifyListener(kernel_state()));
listener->Initialize(mask);
// Handle ref is incremented, so return that.
@ -48,7 +48,7 @@ dword_result_t XNotifyGetNext(dword_t handle, dword_t match_id,
// Grab listener.
auto listener =
kernel_state()->object_table()->LookupObject<NotifyListener>(handle);
kernel_state()->object_table()->LookupObject<XNotifyListener>(handle);
if (!listener) {
return 0;
}

View File

@ -16,6 +16,7 @@
#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"
@ -717,6 +718,64 @@ dword_result_t NtFlushBuffersFile(
}
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; }
DECLARE_XBOXKRNL_EXPORT1(FscGetCacheElementCount, kFileSystem, kStub);

View File

@ -543,6 +543,12 @@ dword_result_t ExAllocatePoolTypeWithTag(dword_t size, dword_t tag,
}
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) {
kernel_state()->memory()->SystemHeapFree(base_address);
}

View File

@ -312,6 +312,30 @@ dword_result_t RtlUnicodeToMultiByteN(pointer_t<uint8_t> destination_ptr,
DECLARE_XBOXKRNL_EXPORT3(RtlUnicodeToMultiByteN, kNone, kImplemented,
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,
dword_t field_dword) {
uint32_t field_value = 0;

View File

@ -14,7 +14,7 @@ namespace kernel {
XEnumerator::XEnumerator(KernelState* kernel_state, size_t items_per_enumerate,
size_t item_size)
: XObject(kernel_state, kTypeEnumerator),
: XObject(kernel_state, kType),
items_per_enumerate_(items_per_enumerate),
item_size_(item_size) {}

View File

@ -15,7 +15,7 @@
namespace xe {
namespace kernel {
XEvent::XEvent(KernelState* kernel_state) : XObject(kernel_state, kTypeEvent) {}
XEvent::XEvent(KernelState* kernel_state) : XObject(kernel_state, kType) {}
XEvent::~XEvent() = default;

View File

@ -20,13 +20,11 @@ namespace xe {
namespace kernel {
XFile::XFile(KernelState* kernel_state, vfs::File* file, bool synchronous)
: XObject(kernel_state, kTypeFile),
file_(file),
is_synchronous_(synchronous) {
: XObject(kernel_state, kType), file_(file), is_synchronous_(synchronous) {
async_event_ = threading::Event::CreateAutoResetEvent(false);
}
XFile::XFile() : XObject(kTypeFile) {
XFile::XFile() : XObject(kType) {
async_event_ = threading::Event::CreateAutoResetEvent(false);
}

View File

@ -13,7 +13,7 @@ namespace xe {
namespace kernel {
XIOCompletion::XIOCompletion(KernelState* kernel_state)
: XObject(kernel_state, kTypeIOCompletion) {
: XObject(kernel_state, kType) {
notification_semaphore_ = threading::Semaphore::Create(0, kMaxNotifications);
}

View File

@ -19,7 +19,7 @@ namespace xe {
namespace kernel {
XModule::XModule(KernelState* kernel_state, ModuleType module_type)
: XObject(kernel_state, kTypeModule),
: XObject(kernel_state, kType),
module_type_(module_type),
processor_module_(nullptr),
hmodule_ptr_(0) {

View File

@ -17,10 +17,9 @@
namespace xe {
namespace kernel {
XMutant::XMutant() : XObject(kTypeMutant) {}
XMutant::XMutant() : XObject(kType) {}
XMutant::XMutant(KernelState* kernel_state)
: XObject(kernel_state, kTypeMutant) {}
XMutant::XMutant(KernelState* kernel_state) : XObject(kernel_state, kType) {}
XMutant::~XMutant() = default;

View File

@ -7,7 +7,7 @@
******************************************************************************
*/
#include "xenia/kernel/notify_listener.h"
#include "xenia/kernel/xnotifylistener.h"
#include "xenia/base/byte_stream.h"
#include "xenia/kernel/kernel_state.h"
@ -15,12 +15,12 @@
namespace xe {
namespace kernel {
NotifyListener::NotifyListener(KernelState* kernel_state)
: XObject(kernel_state, kTypeNotifyListener) {}
XNotifyListener::XNotifyListener(KernelState* kernel_state)
: XObject(kernel_state, kType) {}
NotifyListener::~NotifyListener() {}
XNotifyListener::~XNotifyListener() {}
void NotifyListener::Initialize(uint64_t mask) {
void XNotifyListener::Initialize(uint64_t mask) {
assert_false(wait_handle_);
wait_handle_ = xe::threading::Event::CreateManualResetEvent(false);
@ -29,7 +29,7 @@ void NotifyListener::Initialize(uint64_t mask) {
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.
if ((mask_ & uint64_t(1ULL << (id >> 25))) == 0) {
return;
@ -47,8 +47,8 @@ void NotifyListener::EnqueueNotification(XNotificationID id, uint32_t data) {
wait_handle_->Set();
}
bool NotifyListener::DequeueNotification(XNotificationID* out_id,
uint32_t* out_data) {
bool XNotifyListener::DequeueNotification(XNotificationID* out_id,
uint32_t* out_data) {
auto global_lock = global_critical_region_.Acquire();
bool dequeued = false;
if (notification_count_) {
@ -65,8 +65,8 @@ bool NotifyListener::DequeueNotification(XNotificationID* out_id,
return dequeued;
}
bool NotifyListener::DequeueNotification(XNotificationID id,
uint32_t* out_data) {
bool XNotifyListener::DequeueNotification(XNotificationID id,
uint32_t* out_data) {
auto global_lock = global_critical_region_.Acquire();
bool dequeued = false;
if (notification_count_) {
@ -84,7 +84,7 @@ bool NotifyListener::DequeueNotification(XNotificationID id,
return dequeued;
}
bool NotifyListener::Save(ByteStream* stream) {
bool XNotifyListener::Save(ByteStream* stream) {
SaveObject(stream);
stream->Write(mask_);
@ -99,9 +99,9 @@ bool NotifyListener::Save(ByteStream* stream) {
return true;
}
object_ref<NotifyListener> NotifyListener::Restore(KernelState* kernel_state,
ByteStream* stream) {
auto notify = new NotifyListener(nullptr);
object_ref<XNotifyListener> XNotifyListener::Restore(KernelState* kernel_state,
ByteStream* stream) {
auto notify = new XNotifyListener(nullptr);
notify->kernel_state_ = kernel_state;
notify->RestoreObject(stream);
@ -115,7 +115,7 @@ object_ref<NotifyListener> NotifyListener::Restore(KernelState* kernel_state,
notify->notifications_.insert(pair);
}
return object_ref<NotifyListener>(notify);
return object_ref<XNotifyListener>(notify);
}
} // namespace kernel

View File

@ -7,8 +7,8 @@
******************************************************************************
*/
#ifndef XENIA_KERNEL_NOTIFY_LISTENER_H_
#define XENIA_KERNEL_NOTIFY_LISTENER_H_
#ifndef XENIA_KERNEL_XNOTIFYLISTENER_H_
#define XENIA_KERNEL_XNOTIFYLISTENER_H_
#include <memory>
#include <unordered_map>
@ -21,12 +21,12 @@
namespace xe {
namespace kernel {
class NotifyListener : public XObject {
class XNotifyListener : public XObject {
public:
static const Type kType = kTypeNotifyListener;
explicit NotifyListener(KernelState* kernel_state);
~NotifyListener() override;
explicit XNotifyListener(KernelState* kernel_state);
~XNotifyListener() override;
uint64_t mask() const { return mask_; }
@ -37,8 +37,8 @@ class NotifyListener : public XObject {
bool DequeueNotification(XNotificationID id, uint32_t* out_data);
bool Save(ByteStream* stream) override;
static object_ref<NotifyListener> Restore(KernelState* kernel_state,
ByteStream* stream);
static object_ref<XNotifyListener> Restore(KernelState* kernel_state,
ByteStream* stream);
protected:
xe::threading::WaitHandle* GetWaitHandle() override {
@ -56,4 +56,4 @@ class NotifyListener : public XObject {
} // namespace kernel
} // namespace xe
#endif // XENIA_KERNEL_NOTIFY_LISTENER_H_
#endif // XENIA_KERNEL_XNOTIFYLISTENER_H_

View File

@ -14,14 +14,15 @@
#include "xenia/base/byte_stream.h"
#include "xenia/base/clock.h"
#include "xenia/kernel/kernel_state.h"
#include "xenia/kernel/notify_listener.h"
#include "xenia/kernel/xboxkrnl/xboxkrnl_private.h"
#include "xenia/kernel/xenumerator.h"
#include "xenia/kernel/xevent.h"
#include "xenia/kernel/xfile.h"
#include "xenia/kernel/xmodule.h"
#include "xenia/kernel/xmutant.h"
#include "xenia/kernel/xnotifylistener.h"
#include "xenia/kernel/xsemaphore.h"
#include "xenia/kernel/xsymboliclink.h"
#include "xenia/kernel/xthread.h"
namespace xe {
@ -139,13 +140,15 @@ object_ref<XObject> XObject::Restore(KernelState* kernel_state, Type type,
case kTypeMutant:
return XMutant::Restore(kernel_state, stream);
case kTypeNotifyListener:
return NotifyListener::Restore(kernel_state, stream);
return XNotifyListener::Restore(kernel_state, stream);
case kTypeSemaphore:
return XSemaphore::Restore(kernel_state, stream);
case kTypeSession:
break;
case kTypeSocket:
break;
case kTypeSymbolicLink:
return XSymbolicLink::Restore(kernel_state, stream);
case kTypeThread:
return XThread::Restore(kernel_state, stream);
case kTypeTimer:

View File

@ -121,6 +121,7 @@ class XObject {
kTypeSemaphore,
kTypeSession,
kTypeSocket,
kTypeSymbolicLink,
kTypeThread,
kTypeTimer,
};

View File

@ -31,12 +31,10 @@
namespace xe {
namespace kernel {
XSocket::XSocket(KernelState* kernel_state)
: XObject(kernel_state, XObject::kTypeSocket) {}
XSocket::XSocket(KernelState* kernel_state) : XObject(kernel_state, kType) {}
XSocket::XSocket(KernelState* kernel_state, uint64_t native_handle)
: XObject(kernel_state, XObject::kTypeSocket),
native_handle_(native_handle) {}
: XObject(kernel_state, kType), native_handle_(native_handle) {}
XSocket::~XSocket() { Close(); }

View File

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

View File

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

View File

@ -49,13 +49,13 @@ using xe::cpu::ppc::PPCOpcode;
uint32_t next_xthread_id_ = 0;
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,
uint32_t xapi_thread_startup, uint32_t start_address,
uint32_t start_context, uint32_t creation_flags,
bool guest_thread, bool main_thread)
: XObject(kernel_state, kTypeThread),
: XObject(kernel_state, kType),
thread_id_(++next_xthread_id_),
guest_thread_(guest_thread),
main_thread_(main_thread),

View File

@ -17,7 +17,7 @@
namespace xe {
namespace kernel {
XTimer::XTimer(KernelState* kernel_state) : XObject(kernel_state, kTypeTimer) {}
XTimer::XTimer(KernelState* kernel_state) : XObject(kernel_state, kType) {}
XTimer::~XTimer() = default;

View File

@ -31,7 +31,7 @@ class Device {
virtual bool is_read_only() const { return true; }
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 available_allocation_units() const = 0;

View File

@ -54,7 +54,7 @@ void DiscImageDevice::Dump(StringBuffer* string_buffer) {
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
// be in the form:
// some\PATH.foo

View File

@ -29,7 +29,7 @@ class DiscImageDevice : public Device {
bool Initialize() 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 {
return uint32_t(mmap_->size() / sectors_per_allocation_unit() /

View File

@ -48,7 +48,7 @@ void HostPathDevice::Dump(StringBuffer* string_buffer) {
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
// be in the form:
// some\PATH.foo

View File

@ -27,7 +27,7 @@ class HostPathDevice : public Device {
bool Initialize() 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_; }

View File

@ -149,7 +149,7 @@ void StfsContainerDevice::Dump(StringBuffer* string_buffer) {
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
// be in the form:
// some\PATH.foo

View File

@ -171,7 +171,7 @@ class StfsContainerDevice : public Device {
bool Initialize() 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 {
return uint32_t(mmap_total_size_ / sectors_per_allocation_unit() /

View File

@ -66,15 +66,40 @@ bool VirtualFileSystem::UnregisterSymbolicLink(const std::string& path) {
return true;
}
bool VirtualFileSystem::IsSymbolicLink(const std::string& path) {
auto global_lock = global_critical_region_.Acquire();
auto it = symlinks_.find(path);
if (it == symlinks_.end()) {
bool VirtualFileSystem::FindSymbolicLink(const std::string& path,
std::string& target) {
auto it =
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;
}
target = (*it).second;
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) {
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));
// Resolve symlinks.
std::string device_path;
std::string relative_path;
for (int i = 0; i < 2; i++) {
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;
}
std::string resolved_path;
if (ResolveSymbolicLink(normalized_path, resolved_path)) {
normalized_path = resolved_path;
}
if (device_path.empty()) {
// Symlink wasn't passed in - Check if we've received a raw device name.
for (auto& device : devices_) {
if (xe::find_first_of_case(normalized_path, device->mount_path()) == 0) {
device_path = device->mount_path();
relative_path = normalized_path.substr(device_path.size());
}
}
}
if (device_path.empty()) {
XELOGE("ResolvePath(%s) failed - no root found", path.c_str());
// Find the device.
auto it =
std::find_if(devices_.cbegin(), devices_.cend(), [&](const auto& d) {
return xe::find_first_of_case(normalized_path, d->mount_path()) == 0;
});
if (it == devices_.cend()) {
XELOGE("ResolvePath(%s) failed - device not found", path.c_str());
return nullptr;
}
// Scan all devices.
for (auto& device : devices_) {
if (strcasecmp(device_path.c_str(), device->mount_path().c_str()) == 0) {
return device->ResolvePath(relative_path);
}
}
XELOGE("ResolvePath(%s) failed - device not found (%s)", path.c_str(),
device_path.c_str());
return nullptr;
const auto& device = *it;
auto relative_path = normalized_path.substr(device->mount_path().size());
return device->ResolvePath(relative_path);
}
Entry* VirtualFileSystem::ResolveBasePath(const std::string& path) {

View File

@ -33,7 +33,7 @@ class VirtualFileSystem {
bool RegisterSymbolicLink(const std::string& path, const std::string& target);
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* ResolveBasePath(const std::string& path);
@ -50,6 +50,8 @@ class VirtualFileSystem {
xe::global_critical_region global_critical_region_;
std::vector<std::unique_ptr<Device>> devices_;
std::unordered_map<std::string, std::string> symlinks_;
bool ResolveSymbolicLink(const std::string& path, std::string& result);
};
} // namespace vfs