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,
|
||||
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;
|
||||
|
|
|
@ -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.
|
||||
};
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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_
|
|
@ -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:
|
||||
|
|
|
@ -121,6 +121,7 @@ class XObject {
|
|||
kTypeSemaphore,
|
||||
kTypeSession,
|
||||
kTypeSocket,
|
||||
kTypeSymbolicLink,
|
||||
kTypeThread,
|
||||
kTypeTimer,
|
||||
};
|
||||
|
|
|
@ -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(); }
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
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),
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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() /
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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_; }
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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() /
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue