From aad4d7bebfc1928929ab248906e11c96b9c65dd2 Mon Sep 17 00:00:00 2001 From: Ben Vanik Date: Sat, 4 Jan 2014 16:18:16 -0800 Subject: [PATCH] In progress XNotify stuff. Going to merge xam/xboxkrnl next. --- src/xenia/kernel/xam/sources.gypi | 2 + src/xenia/kernel/xam/xam_module.cc | 1 + src/xenia/kernel/xam/xam_notify.cc | 95 +++++++++++++ src/xenia/kernel/xam/xam_notify.h | 31 +++++ src/xenia/kernel/xam/xam_private.h | 1 + .../kernel/xboxkrnl/objects/sources.gypi | 2 + .../xboxkrnl/objects/xnotify_listener.cc | 126 ++++++++++++++++++ .../xboxkrnl/objects/xnotify_listener.h | 57 ++++++++ src/xenia/kernel/xboxkrnl/xobject.h | 11 +- 9 files changed, 321 insertions(+), 5 deletions(-) create mode 100644 src/xenia/kernel/xam/xam_notify.cc create mode 100644 src/xenia/kernel/xam/xam_notify.h create mode 100644 src/xenia/kernel/xboxkrnl/objects/xnotify_listener.cc create mode 100644 src/xenia/kernel/xboxkrnl/objects/xnotify_listener.h diff --git a/src/xenia/kernel/xam/sources.gypi b/src/xenia/kernel/xam/sources.gypi index 1ec8c9841..d12a381dd 100644 --- a/src/xenia/kernel/xam/sources.gypi +++ b/src/xenia/kernel/xam/sources.gypi @@ -11,6 +11,8 @@ 'xam_module.h', 'xam_net.cc', 'xam_net.h', + 'xam_notify.cc', + 'xam_notify.h', 'xam_ordinals.h', 'xam_private.h', 'xam_state.cc', diff --git a/src/xenia/kernel/xam/xam_module.cc b/src/xenia/kernel/xam/xam_module.cc index de6ea1a78..e3ff3b3f2 100644 --- a/src/xenia/kernel/xam/xam_module.cc +++ b/src/xenia/kernel/xam/xam_module.cc @@ -45,6 +45,7 @@ XamModule::XamModule(Emulator* emulator) : RegisterInfoExports(export_resolver_, xam_state_); RegisterInputExports(export_resolver_, xam_state_); RegisterNetExports(export_resolver_, xam_state_); + RegisterNotifyExports(export_resolver_, xam_state_); RegisterUserExports(export_resolver_, xam_state_); RegisterVideoExports(export_resolver_, xam_state_); } diff --git a/src/xenia/kernel/xam/xam_notify.cc b/src/xenia/kernel/xam/xam_notify.cc new file mode 100644 index 000000000..c271bc983 --- /dev/null +++ b/src/xenia/kernel/xam/xam_notify.cc @@ -0,0 +1,95 @@ +/** + ****************************************************************************** + * 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 + +#include +#include +#include +#include + + +using namespace xe; +using namespace xe::kernel; +using namespace xe::kernel::xam; +using namespace xe::kernel::xboxkrnl; + + +namespace xe { +namespace kernel { +namespace xam { + + +SHIM_CALL XamNotifyCreateListener_shim( + PPCContext* ppc_state, XamState* state) { + uint64_t mask = SHIM_GET_ARG_64(0); + uint32_t one = SHIM_GET_ARG_32(1); + + XELOGD( + "XamNotifyCreateListener(%.8llX, %d)", + mask, + one); + + // r4=1 may indicate user process? + + //return handle; + + SHIM_SET_RETURN(0); +} + + +// http://ffplay360.googlecode.com/svn/Test/Common/AtgSignIn.cpp +SHIM_CALL XNotifyGetNext_shim( + PPCContext* ppc_state, XamState* state) { + uint32_t handle = SHIM_GET_ARG_32(0); + uint32_t match_id = SHIM_GET_ARG_32(1); + uint32_t id_ptr = SHIM_GET_ARG_32(2); + uint32_t param_ptr = SHIM_GET_ARG_32(3); + + XELOGD( + "XNotifyGetNext(%.8X, %.8X, %.8X, %.8X)", + handle, + match_id, + id_ptr, + param_ptr); + + // get from handle + XNotifyListener* listener = 0; + + bool dequeued = false; + uint32_t id = 0; + uint32_t param = 0; + if (match_id) { + // Asking for a specific notification + id = match_id; + dequeued = listener->DequeueNotification(match_id, ¶m); + } else { + // Just get next. + dequeued = listener->DequeueNotification(&id, ¶m); + } + + if (dequeued) { + SHIM_SET_MEM_32(id_ptr, id); + SHIM_SET_MEM_32(param_ptr, param); + } + + SHIM_SET_RETURN(dequeued ? 1 : 0); +} + + +} // namespace xam +} // namespace kernel +} // namespace xe + + +void xe::kernel::xam::RegisterNotifyExports( + ExportResolver* export_resolver, XamState* state) { + SHIM_SET_MAPPING("xam.xex", XamNotifyCreateListener, state); + SHIM_SET_MAPPING("xam.xex", XNotifyGetNext, state); +} diff --git a/src/xenia/kernel/xam/xam_notify.h b/src/xenia/kernel/xam/xam_notify.h new file mode 100644 index 000000000..0fcea77e4 --- /dev/null +++ b/src/xenia/kernel/xam/xam_notify.h @@ -0,0 +1,31 @@ +/** + ****************************************************************************** + * 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_XAM_NOTIFY_H_ +#define XENIA_KERNEL_XAM_NOTIFY_H_ + +#include +#include + +#include + + +namespace xe { +namespace kernel { +namespace xam { + + + + +} // namespace xam +} // namespace kernel +} // namespace xe + + +#endif // XENIA_KERNEL_XAM_NOTIFY_H_ diff --git a/src/xenia/kernel/xam/xam_private.h b/src/xenia/kernel/xam/xam_private.h index 8336c9b7a..1b0fe0da3 100644 --- a/src/xenia/kernel/xam/xam_private.h +++ b/src/xenia/kernel/xam/xam_private.h @@ -34,6 +34,7 @@ void RegisterContentExports(ExportResolver* export_resolver, XamState* state); void RegisterInfoExports(ExportResolver* export_resolver, XamState* state); void RegisterInputExports(ExportResolver* export_resolver, XamState* state); void RegisterNetExports(ExportResolver* export_resolver, XamState* state); +void RegisterNotifyExports(ExportResolver* export_resolver, XamState* state); void RegisterUserExports(ExportResolver* export_resolver, XamState* state); void RegisterVideoExports(ExportResolver* export_resolver, XamState* state); diff --git a/src/xenia/kernel/xboxkrnl/objects/sources.gypi b/src/xenia/kernel/xboxkrnl/objects/sources.gypi index 68d41dbf7..9e74823fe 100644 --- a/src/xenia/kernel/xboxkrnl/objects/sources.gypi +++ b/src/xenia/kernel/xboxkrnl/objects/sources.gypi @@ -7,6 +7,8 @@ 'xfile.h', 'xmodule.cc', 'xmodule.h', + 'xnotify_listener.cc', + 'xnotify_listener.h', 'xsemaphore.cc', 'xsemaphore.h', 'xthread.cc', diff --git a/src/xenia/kernel/xboxkrnl/objects/xnotify_listener.cc b/src/xenia/kernel/xboxkrnl/objects/xnotify_listener.cc new file mode 100644 index 000000000..b78bd8e48 --- /dev/null +++ b/src/xenia/kernel/xboxkrnl/objects/xnotify_listener.cc @@ -0,0 +1,126 @@ +/** + ****************************************************************************** + * 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 + + +using namespace xe; +using namespace xe::kernel; +using namespace xe::kernel::xboxkrnl; + + +XNotifyListener::XNotifyListener(KernelState* kernel_state) : + XObject(kernel_state, kTypeNotifyListener), + wait_handle_(NULL), lock_(0), mask_(0), notification_count_(0) { +} + +XNotifyListener::~XNotifyListener() { + xe_mutex_free(lock_); + if (wait_handle_) { + CloseHandle(wait_handle_); + } +} + +void XNotifyListener::Initialize(uint64_t mask) { + XEASSERTNULL(wait_handle_); + + lock_ = xe_mutex_alloc(); + wait_handle_ = CreateEvent(NULL, TRUE, FALSE, NULL); + mask_ = mask; +} + +void XNotifyListener::EnqueueNotification(XNotificationID id, uint32_t data) { + xe_mutex_lock(lock_); + auto existing = notifications_.find(id); + if (existing != notifications_.end()) { + // Already exists. Overwrite. + notifications_[id] = data; + } else { + // New. + notification_count_++; + } + SetEvent(wait_handle_); + xe_mutex_unlock(lock_); +} + +bool XNotifyListener::DequeueNotification( + XNotificationID* out_id, uint32_t* out_data) { + bool dequeued = false; + xe_mutex_lock(lock_); + if (notification_count_) { + dequeued = true; + auto it = notifications_.begin(); + *out_id = it->first; + *out_data = it->second; + notifications_.erase(it); + notification_count_--; + if (!notification_count_) { + ResetEvent(wait_handle_); + } + } + xe_mutex_unlock(lock_); + return dequeued; +} + +bool XNotifyListener::DequeueNotification( + XNotificationID id, uint32_t* out_data) { + bool dequeued = false; + xe_mutex_lock(lock_); + if (notification_count_) { + dequeued = true; + auto it = notifications_.find(id); + if (it != notifications_.end()) { + *out_data = it->second; + notifications_.erase(it); + notification_count_--; + if (!notification_count_) { + ResetEvent(wait_handle_); + } + } + } + xe_mutex_unlock(lock_); + return dequeued; +} + +// TODO(benvanik): move this to common class +X_STATUS XNotifyListener::Wait(uint32_t wait_reason, uint32_t processor_mode, + uint32_t alertable, uint64_t* opt_timeout) { + DWORD timeout_ms; + if (opt_timeout) { + int64_t timeout_ticks = (int64_t)(*opt_timeout); + if (timeout_ticks > 0) { + // Absolute time, based on January 1, 1601. + // TODO(benvanik): convert time to relative time. + XEASSERTALWAYS(); + timeout_ms = 0; + } else if (timeout_ticks < 0) { + // Relative time. + timeout_ms = (DWORD)(-timeout_ticks / 10000); // Ticks -> MS + } else { + timeout_ms = 0; + } + } else { + timeout_ms = INFINITE; + } + + DWORD result = WaitForSingleObjectEx(wait_handle_, timeout_ms, alertable); + switch (result) { + case WAIT_OBJECT_0: + return X_STATUS_SUCCESS; + case WAIT_IO_COMPLETION: + // Or X_STATUS_ALERTED? + return X_STATUS_USER_APC; + case WAIT_TIMEOUT: + return X_STATUS_TIMEOUT; + default: + case WAIT_FAILED: + case WAIT_ABANDONED: + return X_STATUS_ABANDONED_WAIT_0; + } +} diff --git a/src/xenia/kernel/xboxkrnl/objects/xnotify_listener.h b/src/xenia/kernel/xboxkrnl/objects/xnotify_listener.h new file mode 100644 index 000000000..3c2d02be9 --- /dev/null +++ b/src/xenia/kernel/xboxkrnl/objects/xnotify_listener.h @@ -0,0 +1,57 @@ +/** + ****************************************************************************** + * 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. * + ****************************************************************************** + */ + +// This should probably be in XAM, but I don't want to build an extensible +// object system. Meh. + +#ifndef XENIA_KERNEL_XBOXKRNL_XNOTIFY_LISTENER_H_ +#define XENIA_KERNEL_XBOXKRNL_XNOTIFY_LISTENER_H_ + +#include + +#include + + +namespace xe { +namespace kernel { +namespace xboxkrnl { + +// Values seem to be all over the place - GUIDs? +typedef uint32_t XNotificationID; + + +class XNotifyListener : public XObject { +public: + XNotifyListener(KernelState* kernel_state); + virtual ~XNotifyListener(); + + void Initialize(uint64_t mask); + + void EnqueueNotification(XNotificationID id, uint32_t data); + bool DequeueNotification(XNotificationID* out_id, uint32_t* out_data); + bool DequeueNotification(XNotificationID id, uint32_t* out_data); + + virtual X_STATUS Wait(uint32_t wait_reason, uint32_t processor_mode, + uint32_t alertable, uint64_t* opt_timeout); + +private: + HANDLE wait_handle_; + xe_mutex_t* lock_; + std::unordered_map notifications_; + size_t notification_count_; + uint64_t mask_; +}; + + +} // namespace xboxkrnl +} // namespace kernel +} // namespace xe + + +#endif // XENIA_KERNEL_XBOXKRNL_XNOTIFY_LISTENER_H_ diff --git a/src/xenia/kernel/xboxkrnl/xobject.h b/src/xenia/kernel/xboxkrnl/xobject.h index 95bc2df3d..ea7d3f83f 100644 --- a/src/xenia/kernel/xboxkrnl/xobject.h +++ b/src/xenia/kernel/xboxkrnl/xobject.h @@ -32,11 +32,12 @@ typedef struct { class XObject { public: enum Type { - kTypeModule = 0x00000001, - kTypeThread = 0x00000002, - kTypeEvent = 0x00000003, - kTypeFile = 0x00000004, - kTypeSemaphore = 0x00000005, + kTypeModule, + kTypeThread, + kTypeEvent, + kTypeFile, + kTypeSemaphore, + kTypeNotifyListener, }; XObject(KernelState* kernel_state, Type type);