diff --git a/src/xenia/kernel/app.cc b/src/xenia/kernel/app.cc new file mode 100644 index 000000000..0a037fb64 --- /dev/null +++ b/src/xenia/kernel/app.cc @@ -0,0 +1,50 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2014 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include + +#include + + +namespace xe { +namespace kernel { + + +XApp::XApp(KernelState* kernel_state, uint32_t app_id) + : kernel_state_(kernel_state), app_id_(app_id), + membase_(kernel_state->memory()->membase()) {} + + +void XAppManager::RegisterApp(std::unique_ptr app) { + assert_zero(app_lookup_.count(app->app_id())); + app_lookup_.insert({ app->app_id(), app.get() }); + apps_.push_back(std::move(app)); +} + + +X_RESULT XAppManager::DispatchMessageSync(uint32_t app_id, uint32_t message, uint32_t arg1, uint32_t arg2) { + const auto& it = app_lookup_.find(app_id); + if (it == app_lookup_.end()) { + return X_ERROR_NOT_FOUND; + } + return it->second->DispatchMessageSync(message, arg1, arg2); +} + + +X_RESULT XAppManager::DispatchMessageAsync(uint32_t app_id, uint32_t message, uint32_t buffer_ptr, size_t buffer_length) { + const auto& it = app_lookup_.find(app_id); + if (it == app_lookup_.end()) { + return X_ERROR_NOT_FOUND; + } + return it->second->DispatchMessageAsync(message, buffer_ptr, buffer_length); +} + + +} // namespace kernel +} // namespace xe diff --git a/src/xenia/kernel/app.h b/src/xenia/kernel/app.h new file mode 100644 index 000000000..ab60006e2 --- /dev/null +++ b/src/xenia/kernel/app.h @@ -0,0 +1,62 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2014 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef XENIA_KERNEL_XBOXKRNL_APP_H_ +#define XENIA_KERNEL_XBOXKRNL_APP_H_ + +#include +#include + +#include +#include + +#include + + +namespace xe { +namespace kernel { + + +class KernelState; + + +class XApp { +public: + uint32_t app_id() const { return app_id_; } + + virtual X_RESULT DispatchMessageSync(uint32_t message, uint32_t arg1, uint32_t arg2) = 0; + virtual X_RESULT DispatchMessageAsync(uint32_t message, uint32_t buffer_ptr, size_t buffer_length) = 0; + +protected: + XApp(KernelState* kernel_state, uint32_t app_id); + + KernelState* kernel_state_; + uint32_t app_id_; + uint8_t* membase_; +}; + + +class XAppManager { +public: + void RegisterApp(std::unique_ptr app); + + X_RESULT DispatchMessageSync(uint32_t app_id, uint32_t message, uint32_t arg1, uint32_t arg2); + X_RESULT DispatchMessageAsync(uint32_t app_id, uint32_t message, uint32_t buffer_ptr, size_t buffer_length); + +private: + std::vector> apps_; + std::unordered_map app_lookup_; +}; + + +} // namespace kernel +} // namespace xe + + +#endif // XENIA_KERNEL_XBOXKRNL_APP_H_ diff --git a/src/xenia/kernel/apps/apps.cc b/src/xenia/kernel/apps/apps.cc new file mode 100644 index 000000000..9d18c80ec --- /dev/null +++ b/src/xenia/kernel/apps/apps.cc @@ -0,0 +1,27 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2014 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include + +#include + + +namespace xe { +namespace kernel { +namespace apps { + + +void RegisterApps(KernelState* kernel_state, XAppManager* manager) { + manager->RegisterApp(std::make_unique(kernel_state)); +} + + +} // namespace apps +} // namespace kernel +} // namespace xe diff --git a/src/xenia/kernel/apps/apps.h b/src/xenia/kernel/apps/apps.h new file mode 100644 index 000000000..b18e08fdb --- /dev/null +++ b/src/xenia/kernel/apps/apps.h @@ -0,0 +1,33 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2014 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef XENIA_KERNEL_XBOXKRNL_APPS_APPS_H_ +#define XENIA_KERNEL_XBOXKRNL_APPS_APPS_H_ + +#include +#include + +#include +#include + + +namespace xe { +namespace kernel { +namespace apps { + + +void RegisterApps(KernelState* kernel_state, XAppManager* manager); + + +} // namespace apps +} // namespace kernel +} // namespace xe + + +#endif // XENIA_KERNEL_XBOXKRNL_APPS_APPS_H_ diff --git a/src/xenia/kernel/apps/sources.gypi b/src/xenia/kernel/apps/sources.gypi new file mode 100644 index 000000000..26c6663e2 --- /dev/null +++ b/src/xenia/kernel/apps/sources.gypi @@ -0,0 +1,9 @@ +# Copyright 2013 Ben Vanik. All Rights Reserved. +{ + 'sources': [ + 'apps.cc', + 'apps.h', + 'xmp_app.cc', + 'xmp_app.h', + ], +} diff --git a/src/xenia/kernel/apps/xmp_app.cc b/src/xenia/kernel/apps/xmp_app.cc new file mode 100644 index 000000000..b5b4af54c --- /dev/null +++ b/src/xenia/kernel/apps/xmp_app.cc @@ -0,0 +1,107 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2014 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include + + +namespace xe { +namespace kernel { +namespace apps { + + +X_RESULT XXMPApp::XMPGetStatus(uint32_t unk, uint32_t status_ptr) { + // Some stupid games will hammer this on a thread - induce a delay + // here to keep from starving real threads. + Sleep(1); + + XELOGD("XMPGetStatus(%.8X, %.8X)", unk, status_ptr); + + assert_true(unk == 2); + poly::store_and_swap(membase_ + status_ptr, 0); + + return X_ERROR_SUCCESS; +} + +X_RESULT XXMPApp::XMPGetStatusEx(uint32_t unk, uint32_t unk_ptr, uint32_t disabled_ptr) { + // Some stupid games will hammer this on a thread - induce a delay + // here to keep from starving real threads. + Sleep(1); + + XELOGD("XMPGetStatusEx(%.8X, %.8X, %.8X)", unk, unk_ptr, disabled_ptr); + + assert_true(unk == 2); + poly::store_and_swap(membase_ + unk_ptr, 0); + poly::store_and_swap(membase_ + disabled_ptr, 1); + + return X_ERROR_SUCCESS; +} + +X_RESULT XXMPApp::DispatchMessageSync(uint32_t message, uint32_t arg1, uint32_t arg2) { + // http://freestyledash.googlecode.com/svn-history/r1/trunk/Freestyle/Scenes/Media/Music/ScnMusic.cpp + switch (message) { + case 0x00070009: { + uint32_t unk = + poly::load_and_swap(membase_ + arg1 + 0); // 0x00000002 + uint32_t status_ptr = poly::load_and_swap( + membase_ + arg1 + 4); // out ptr to 4b - expect 0 + assert_zero(arg2); + return XMPGetStatus(unk, status_ptr); + } + case 0x0007001A: { + // dcz + // arg1 = ? + // arg2 = 0 + break; + } + case 0x0007001B: { + uint32_t unk = + poly::load_and_swap(membase_ + arg1 + 0); // 0x00000002 + uint32_t unk_ptr = poly::load_and_swap( + membase_ + arg1 + 4); // out ptr to 4b - expect 0 + uint32_t disabled_ptr = poly::load_and_swap( + membase_ + arg1 + 8); // out ptr to 4b - expect 1 (to skip) + assert_zero(arg2); + return XMPGetStatusEx(unk, unk_ptr, disabled_ptr); + } + } + XELOGE("Unimplemented XMsg message app=%.8X, msg=%.8X, arg1=%.8X, arg2=%.8X", + app_id(), message, arg1, arg2); + return X_ERROR_NOT_FOUND; +} + +X_RESULT XXMPApp::DispatchMessageAsync(uint32_t message, uint32_t buffer_ptr, size_t buffer_length) { + switch (message) { + case 0x00070009: { + uint32_t unk = + poly::load_and_swap(membase_ + buffer_ptr + 0); // 0x00000002 + uint32_t status_ptr = poly::load_and_swap( + membase_ + buffer_ptr + 4); // out ptr to 4b - expect 0 + assert_true(buffer_length == 8); + return XMPGetStatus(unk, status_ptr); + } + case 0x0007001B: { + uint32_t unk = + poly::load_and_swap(membase_ + buffer_ptr + 0); // 0x00000002 + uint32_t unk_ptr = poly::load_and_swap( + membase_ + buffer_ptr + 4); // out ptr to 4b - expect 0 + uint32_t disabled_ptr = poly::load_and_swap( + membase_ + buffer_ptr + 8); // out ptr to 4b - expect 1 (to skip) + assert_true(buffer_length == 0xC); + return XMPGetStatusEx(unk, unk_ptr, disabled_ptr); + } + } + XELOGE("Unimplemented XMsg message app=%.8X, msg=%.8X, buffer=%.8X, len=%d", + app_id(), message, buffer_ptr, buffer_length); + return X_ERROR_NOT_FOUND; +} + + +} // namespace apps +} // namespace kernel +} // namespace xe diff --git a/src/xenia/kernel/apps/xmp_app.h b/src/xenia/kernel/apps/xmp_app.h new file mode 100644 index 000000000..754ca9593 --- /dev/null +++ b/src/xenia/kernel/apps/xmp_app.h @@ -0,0 +1,42 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2014 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef XENIA_KERNEL_XBOXKRNL_APPS_XMP_APP_H_ +#define XENIA_KERNEL_XBOXKRNL_APPS_XMP_APP_H_ + +#include +#include + +#include +#include + + +namespace xe { +namespace kernel { +namespace apps { + + +class XXMPApp : public XApp { +public: + XXMPApp(KernelState* kernel_state) : XApp(kernel_state, 0xFA) {} + + X_RESULT XMPGetStatus(uint32_t unk, uint32_t status_ptr); + X_RESULT XMPGetStatusEx(uint32_t unk, uint32_t unk_ptr, uint32_t disabled_ptr); + + X_RESULT DispatchMessageSync(uint32_t message, uint32_t arg1, uint32_t arg2) override; + X_RESULT DispatchMessageAsync(uint32_t message, uint32_t buffer_ptr, size_t buffer_length) override; +}; + + +} // namespace apps +} // namespace kernel +} // namespace xe + + +#endif // XENIA_KERNEL_XBOXKRNL_APPS_XMP_APP_H_ diff --git a/src/xenia/kernel/kernel_state.cc b/src/xenia/kernel/kernel_state.cc index 025fcc990..f2d3b676d 100644 --- a/src/xenia/kernel/kernel_state.cc +++ b/src/xenia/kernel/kernel_state.cc @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -39,11 +40,15 @@ KernelState::KernelState(Emulator* emulator) : dispatcher_ = new Dispatcher(this); + app_manager_ = std::make_unique(); + object_table_ = new ObjectTable(); object_mutex_ = xe_mutex_alloc(10000); assert_null(shared_kernel_state_); shared_kernel_state_ = this; + + apps::RegisterApps(this, app_manager_.get()); } KernelState::~KernelState() { @@ -53,6 +58,9 @@ KernelState::~KernelState() { xe_mutex_free(object_mutex_); delete object_table_; + // Shutdown apps. + app_manager_.reset(); + delete dispatcher_; assert_true(shared_kernel_state_ == this); diff --git a/src/xenia/kernel/kernel_state.h b/src/xenia/kernel/kernel_state.h index f2fb3f47e..4a7884724 100644 --- a/src/xenia/kernel/kernel_state.h +++ b/src/xenia/kernel/kernel_state.h @@ -10,11 +10,14 @@ #ifndef XENIA_KERNEL_KERNEL_STATE_H_ #define XENIA_KERNEL_KERNEL_STATE_H_ +#include + #include #include #include #include +#include #include #include @@ -47,6 +50,8 @@ public: Dispatcher* dispatcher() const { return dispatcher_; } + XAppManager* app_manager() const { return app_manager_.get(); } + ObjectTable* object_table() const { return object_table_; } XModule* GetModule(const char* name); @@ -69,6 +74,8 @@ private: Dispatcher* dispatcher_; + std::unique_ptr app_manager_; + ObjectTable* object_table_; xe_mutex_t* object_mutex_; std::unordered_map threads_by_id_; diff --git a/src/xenia/kernel/sources.gypi b/src/xenia/kernel/sources.gypi index 7a23d285e..2c393a0ab 100644 --- a/src/xenia/kernel/sources.gypi +++ b/src/xenia/kernel/sources.gypi @@ -1,6 +1,8 @@ # Copyright 2013 Ben Vanik. All Rights Reserved. { 'sources': [ + 'app.cc', + 'app.h', 'async_request.cc', 'async_request.h', 'dispatcher.cc', @@ -70,6 +72,7 @@ ], 'includes': [ + 'apps/sources.gypi', 'fs/sources.gypi', 'objects/sources.gypi', 'util/sources.gypi', diff --git a/src/xenia/kernel/xam_msg.cc b/src/xenia/kernel/xam_msg.cc index 72f2b2eca..f15efcaa3 100644 --- a/src/xenia/kernel/xam_msg.cc +++ b/src/xenia/kernel/xam_msg.cc @@ -34,43 +34,9 @@ SHIM_CALL XMsgInProcessCall_shim( "XMsgInProcessCall(%.8X, %.8X, %.8X, %.8X)", app, message, arg1, arg2); - bool handled = false; - - // TODO(benvanik): build XMsg pump? async/sync/etc - if (app == 0xFA) { - // XMP = music - // http://freestyledash.googlecode.com/svn-history/r1/trunk/Freestyle/Scenes/Media/Music/ScnMusic.cpp - if (message == 0x00070009) { - uint32_t a = SHIM_MEM_32(arg1 + 0); // 0x00000002 - uint32_t b = SHIM_MEM_32(arg1 + 4); // out ptr to 4b - expect 0 - XELOGD("XMPGetStatusEx(%.8X, %.8X)", a, b); - assert_zero(arg2); - assert_true(a == 2); - SHIM_SET_MEM_32(b, 0); - handled = true; - } else if (message == 0x0007001A) { - // dcz - // arg1 = ? - // arg2 = 0 - } else if (message == 0x0007001B) { - // Some stupid games will hammer this on a thread - induce a delay - // here to keep from starving real threads. - Sleep(1); - uint32_t a = SHIM_MEM_32(arg1 + 0); // 0x00000002 - uint32_t b = SHIM_MEM_32(arg1 + 4); // out ptr to 4b - expect 0 - XELOGD("XMPGetStatus(%.8X, %.8X)", a, b); - assert_zero(arg2); - assert_true(a == 2); - SHIM_SET_MEM_32(b, 0); - handled = true; - } - } - - if (!handled) { - XELOGE("Unimplemented XMsgInProcessCall message!"); - } - - SHIM_SET_RETURN_32(handled ? X_ERROR_SUCCESS : X_ERROR_NOT_FOUND); + auto result = state->app_manager()->DispatchMessageSync( + app, message, arg1, arg2); + SHIM_SET_RETURN_32(result); } @@ -86,31 +52,11 @@ SHIM_CALL XMsgStartIORequest_shim( "XMsgStartIORequest(%.8X, %.8X, %.8X, %.8X, %d)", app, message, overlapped_ptr, buffer, buffer_length); - bool handled = false; - assert_zero(overlapped_ptr); - // TODO(benvanik): build XMsg pump? async/sync/etc - if (app == 0xFA) { - // XMP = music - // http://freestyledash.googlecode.com/svn-history/r1/trunk/Freestyle/Scenes/Media/Music/ScnMusic.cpp - if (message == 0x00070009) { - assert(buffer_length == 8); - uint32_t a = SHIM_MEM_32(buffer + 0); // 0x00000002 - uint32_t b = SHIM_MEM_32(buffer + 4); // out ptr to 4b - expect 0 - XELOGD("XMPGetStatusEx(%.8X, %.8X)", a, b); - assert_true(a == 2); - SHIM_SET_MEM_32(b, 0); - Sleep(1); - handled = true; - } - } - - if (!handled) { - XELOGE("Unimplemented XMsgStartIORequest message!"); - } - - SHIM_SET_RETURN_32(handled ? X_ERROR_SUCCESS : X_ERROR_NOT_FOUND); + auto result = state->app_manager()->DispatchMessageAsync( + app, message, buffer, buffer_length); + SHIM_SET_RETURN_32(result); }