diff --git a/src/xenia/emulator.cc b/src/xenia/emulator.cc index c5af4e017..56f8fc75b 100644 --- a/src/xenia/emulator.cc +++ b/src/xenia/emulator.cc @@ -40,6 +40,7 @@ #include "xenia/hid/input_driver.h" #include "xenia/hid/input_system.h" #include "xenia/kernel/kernel_state.h" +#include "xenia/kernel/title_id_utils.h" #include "xenia/kernel/user_module.h" #include "xenia/kernel/xam/achievement_manager.h" #include "xenia/kernel/xam/xam_module.h" @@ -574,7 +575,8 @@ X_STATUS Emulator::LaunchXexFile(const std::filesystem::path& path) { if (XSUCCEEDED(result)) { kernel_state_->deployment_type_ = XDeploymentType::kHardDrive; - if (!kernel_state_->is_title_system_type(title_id())) { + auto title_id = kernel_state_->title_id(); + if (!kernel::IsSystemTitle(title_id)) { // Assumption that any loaded game is loaded as a disc. kernel_state_->deployment_type_ = XDeploymentType::kOpticalDisc; } @@ -622,7 +624,8 @@ X_STATUS Emulator::LaunchDefaultModule(const std::filesystem::path& path) { if (XSUCCEEDED(result)) { kernel_state_->deployment_type_ = XDeploymentType::kHardDrive; - if (!kernel_state_->is_title_system_type(title_id())) { + auto title_id = kernel_state_->title_id(); + if (!kernel::IsSystemTitle(title_id)) { // Assumption that any loaded game is loaded as a disc. kernel_state_->deployment_type_ = XDeploymentType::kOpticalDisc; } diff --git a/src/xenia/kernel/kernel_state.cc b/src/xenia/kernel/kernel_state.cc index c59239ba4..528429aa2 100644 --- a/src/xenia/kernel/kernel_state.cc +++ b/src/xenia/kernel/kernel_state.cc @@ -127,18 +127,6 @@ uint32_t KernelState::title_id() const { return 0; } -bool KernelState::is_title_system_type(uint32_t title_id) { - if (!title_id) { - return true; - } - - if ((title_id & 0xFF000000) == 0x58000000u) { - return (title_id & 0xFF0000) != 0x410000; // if 'X' but not 'XA' (XBLA) - } - - return (title_id >> 16) == 0xFFFE; -} - const std::unique_ptr KernelState::title_xdbf() const { return module_xdbf(executable_module_); } diff --git a/src/xenia/kernel/kernel_state.h b/src/xenia/kernel/kernel_state.h index 20281044d..497853f56 100644 --- a/src/xenia/kernel/kernel_state.h +++ b/src/xenia/kernel/kernel_state.h @@ -185,7 +185,6 @@ class KernelState { vfs::VirtualFileSystem* file_system() const { return file_system_; } uint32_t title_id() const; - static bool is_title_system_type(uint32_t title_id); const std::unique_ptr title_xdbf() const; const std::unique_ptr module_xdbf( object_ref exec_module) const; diff --git a/src/xenia/kernel/title_id_utils.h b/src/xenia/kernel/title_id_utils.h new file mode 100644 index 000000000..2ac49c690 --- /dev/null +++ b/src/xenia/kernel/title_id_utils.h @@ -0,0 +1,101 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2025 Xenia Canary. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef XENIA_KERNEL_UTIL_TITLE_ID_UTILS_H_ +#define XENIA_KERNEL_UTIL_TITLE_ID_UTILS_H_ + +#include +#include + +namespace xe { +namespace kernel { + +static constexpr uint32_t kXN_2001 = 0x584E07D1; +static constexpr uint32_t kXN_2002 = 0x584E07D2; +static constexpr uint32_t kDashboardID = 0xFFFE07D1; + +static constexpr uint16_t GetGameId(const uint32_t title_id) { + return title_id >> 16; +} + +static constexpr bool IsValidGameId(const uint32_t title_id) { + return (title_id >> 16) != 0xFFFE; +} + +static constexpr std::pair GetTitlePublisher( + const uint32_t title_id) { + const char first_char = title_id >> 24; + const char second_char = (title_id >> 16) & 0xFF; + + return {first_char, second_char}; +} + +static constexpr bool IsXboxTitle(const uint32_t title_id) { + const auto publisher = GetTitlePublisher(title_id); + + return publisher.first == 'X'; +} + +static constexpr bool IsXblaTitle(const uint32_t title_id) { + const auto publisher = GetTitlePublisher(title_id); + + return publisher.first == 'X' && publisher.second == 'A'; +} + +static constexpr bool IsAppTitle(const uint32_t title_id) { + const auto publisher = GetTitlePublisher(title_id); + + return publisher.first == 'X' && publisher.second == 'H' || + publisher.first == 'X' && publisher.second == 'H'; +} + +static constexpr bool IsXNTitle(const uint32_t title_id) { + return title_id == kXN_2001 || title_id == kXN_2002; +} + +static constexpr bool IsSystemExperienceTitle(const uint32_t title_id) { + if (IsAppTitle(title_id)) { + return true; + } + + return IsXNTitle(title_id); +}; + +static constexpr bool IsSystemTitle(const uint32_t title_id) { + if (!title_id) { + return true; + } + + if (!IsXboxTitle(title_id)) { + return IsValidGameId(title_id); + } + + if (IsXblaTitle(title_id)) { + return IsValidGameId(title_id); + } + + return true; +}; + +static constexpr bool IsOriginalXboxTitle(const uint32_t title_id) { + if (!IsValidGameId(title_id)) { + return true; + } + + if (!title_id || (title_id >> 24) == 0xFF) { + return false; + } + + return (title_id >> 17) < 0x7D0; +}; + +} // namespace kernel +} // namespace xe + +#endif \ No newline at end of file diff --git a/src/xenia/kernel/xam/profile_manager.h b/src/xenia/kernel/xam/profile_manager.h index 207610ca4..e6ef40aa0 100644 --- a/src/xenia/kernel/xam/profile_manager.h +++ b/src/xenia/kernel/xam/profile_manager.h @@ -17,6 +17,7 @@ #include "third_party/fmt/include/fmt/format.h" #include "xenia/base/string.h" +#include "xenia/kernel/title_id_utils.h" #include "xenia/kernel/xam/user_profile.h" #include "xenia/xbox.h" @@ -38,7 +39,6 @@ namespace xe { namespace kernel { namespace xam { -constexpr uint32_t kDashboardID = 0xFFFE07D1; const static std::string kDashboardStringID = fmt::format("{:08X}", kDashboardID); diff --git a/src/xenia/kernel/xam/xam_info.cc b/src/xenia/kernel/xam/xam_info.cc index 70de336f3..c2d027671 100644 --- a/src/xenia/kernel/xam/xam_info.cc +++ b/src/xenia/kernel/xam/xam_info.cc @@ -13,6 +13,7 @@ #include "xenia/base/logging.h" #include "xenia/base/string_util.h" #include "xenia/kernel/kernel_state.h" +#include "xenia/kernel/title_id_utils.h" #include "xenia/kernel/user_module.h" #include "xenia/kernel/util/shim_utils.h" #include "xenia/kernel/xam/xam_module.h" @@ -281,7 +282,7 @@ dword_result_t XamGetCurrentTitleId_entry() { DECLARE_XAM_EXPORT1(XamGetCurrentTitleId, kNone, kImplemented); dword_result_t XamIsCurrentTitleDash_entry(const ppc_context_t& ctx) { - return ctx->kernel_state->title_id() == 0xFFFE07D1; + return ctx->kernel_state->title_id() == kDashboardID; } DECLARE_XAM_EXPORT1(XamIsCurrentTitleDash, kNone, kImplemented); @@ -712,6 +713,21 @@ DECLARE_XAM_EXPORT1(RtlRandom, kNone, kImplemented); dword_result_t Refresh_entry() { return X_ERROR_SUCCESS; } DECLARE_XAM_EXPORT1(Refresh, kNone, kStub); +dword_result_t XamIsSystemExperienceTitleId_entry(dword_t title_id) { + return IsSystemExperienceTitle(title_id); +} +DECLARE_XAM_EXPORT1(XamIsSystemExperienceTitleId, kNone, kImplemented); + +dword_result_t XamIsSystemTitleId_entry(dword_t title_id) { + return IsSystemTitle(title_id); +} +DECLARE_XAM_EXPORT1(XamIsSystemTitleId, kNone, kImplemented); + +dword_result_t XamIsXbox1TitleId_entry(dword_t title_id) { + return IsOriginalXboxTitle(title_id); +} +DECLARE_XAM_EXPORT1(XamIsXbox1TitleId, kNone, kImplemented); + } // namespace xam } // namespace kernel } // namespace xe diff --git a/src/xenia/kernel/xam/xdbf/gpd_info_profile.h b/src/xenia/kernel/xam/xdbf/gpd_info_profile.h index 0347c466c..c38709a9d 100644 --- a/src/xenia/kernel/xam/xdbf/gpd_info_profile.h +++ b/src/xenia/kernel/xam/xdbf/gpd_info_profile.h @@ -10,6 +10,7 @@ #ifndef XENIA_KERNEL_XAM_XDBF_GPD_INFO_PROFILE_H_ #define XENIA_KERNEL_XAM_XDBF_GPD_INFO_PROFILE_H_ +#include "xenia/kernel/title_id_utils.h" #include "xenia/kernel/xam/xdbf/gpd_info.h" #include "xenia/kernel/xam/xdbf/spa_info.h" @@ -24,9 +25,9 @@ namespace xam { class GpdInfoProfile : public GpdInfo { public: - GpdInfoProfile() : GpdInfo(0xFFFE07D1) {}; + GpdInfoProfile() : GpdInfo(kDashboardID) {}; GpdInfoProfile(const std::vector buffer) - : GpdInfo(0xFFFE07D1, buffer) {}; + : GpdInfo(kDashboardID, buffer) {}; ~GpdInfoProfile() {};