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, 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;

View File

@ -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.
}; };

View File

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

View File

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

View File

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

View File

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

View File

@ -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);
} }

View File

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

View File

@ -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) {}

View File

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

View File

@ -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);
} }

View File

@ -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);
} }

View File

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

View File

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

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/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,7 +47,7 @@ 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;
@ -65,7 +65,7 @@ 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;
@ -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

View File

@ -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,7 +37,7 @@ 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:
@ -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_

View File

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

View File

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

View File

@ -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(); }

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; 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),

View File

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

View File

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

View File

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

View File

@ -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() /

View File

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

View File

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

View File

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

View File

@ -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() /

View File

@ -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. // Find the device.
normalized_path = device_path; auto it =
break; 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()) {
// Break as soon as we've completely resolved the symlinks to a device. XELOGE("ResolvePath(%s) failed - device not found", path.c_str());
if (!IsSymbolicLink(device_path)) {
break;
}
}
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());
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) {

View File

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