From 1d02ce63d3896fc5c8ec4e168f1bf0bdeabb71df Mon Sep 17 00:00:00 2001 From: gibbed Date: Fri, 5 Jun 2015 18:52:53 -0500 Subject: [PATCH] Cleaned up XamUserReadProfileSettings. Also fixed writing out pointers for setting data, fixing issues with games trying to read from zero page after reading profile settings. --- src/xenia/kernel/user_profile.h | 34 ++++++------- src/xenia/kernel/xam_user.cc | 90 +++++++++++++++++++-------------- 2 files changed, 68 insertions(+), 56 deletions(-) diff --git a/src/xenia/kernel/user_profile.h b/src/xenia/kernel/user_profile.h index b7fdfe7d3..4a6ce71e1 100644 --- a/src/xenia/kernel/user_profile.h +++ b/src/xenia/kernel/user_profile.h @@ -50,7 +50,7 @@ class UserProfile { : setting_id(setting_id), type(type), size(size) {} virtual size_t extra_size() const { return 0; } virtual size_t Append(uint8_t* user_data, uint8_t* buffer, - size_t buffer_offset) { + uint32_t buffer_ptr, size_t buffer_offset) { xe::store_and_swap(user_data + kTypeOffset, static_cast(type)); return buffer_offset; @@ -67,8 +67,8 @@ class UserProfile { : Setting(setting_id, Type::INT32, 4), value(value) {} int32_t value; size_t Append(uint8_t* user_data, uint8_t* buffer, - size_t buffer_offset) override { - buffer_offset = Setting::Append(user_data, buffer, buffer_offset); + uint32_t buffer_ptr, size_t buffer_offset) override { + buffer_offset = Setting::Append(user_data, buffer, buffer_ptr, buffer_offset); xe::store_and_swap(user_data + kValueOffset, value); return buffer_offset; } @@ -78,8 +78,8 @@ class UserProfile { : Setting(setting_id, Type::INT64, 8), value(value) {} int64_t value; size_t Append(uint8_t* user_data, uint8_t* buffer, - size_t buffer_offset) override { - buffer_offset = Setting::Append(user_data, buffer, buffer_offset); + uint32_t buffer_ptr, size_t buffer_offset) override { + buffer_offset = Setting::Append(user_data, buffer, buffer_ptr, buffer_offset); xe::store_and_swap(user_data + kValueOffset, value); return buffer_offset; } @@ -89,8 +89,8 @@ class UserProfile { : Setting(setting_id, Type::DOUBLE, 8), value(value) {} double value; size_t Append(uint8_t* user_data, uint8_t* buffer, - size_t buffer_offset) override { - buffer_offset = Setting::Append(user_data, buffer, buffer_offset); + uint32_t buffer_ptr, size_t buffer_offset) override { + buffer_offset = Setting::Append(user_data, buffer, buffer_ptr, buffer_offset); xe::store_and_swap(user_data + kValueOffset, value); return buffer_offset; } @@ -103,8 +103,8 @@ class UserProfile { return value.empty() ? 0 : 2 * (static_cast(value.size()) + 1); } size_t Append(uint8_t* user_data, uint8_t* buffer, - size_t buffer_offset) override { - buffer_offset = Setting::Append(user_data, buffer, buffer_offset); + uint32_t buffer_ptr, size_t buffer_offset) override { + buffer_offset = Setting::Append(user_data, buffer, buffer_ptr, buffer_offset); int32_t length; if (value.empty()) { length = 0; @@ -114,7 +114,7 @@ class UserProfile { length = 2 * (static_cast(value.size()) + 1); xe::store_and_swap(user_data + kValueOffset, length); xe::store_and_swap(user_data + kPointerOffset, - static_cast(buffer_offset)); + buffer_ptr + static_cast(buffer_offset)); memcpy(buffer + buffer_offset, value.data(), length); } return buffer_offset + length; @@ -125,8 +125,8 @@ class UserProfile { : Setting(setting_id, Type::FLOAT, 4), value(value) {} float value; size_t Append(uint8_t* user_data, uint8_t* buffer, - size_t buffer_offset) override { - buffer_offset = Setting::Append(user_data, buffer, buffer_offset); + uint32_t buffer_ptr, size_t buffer_offset) override { + buffer_offset = Setting::Append(user_data, buffer, buffer_ptr, buffer_offset); xe::store_and_swap(user_data + kValueOffset, value); return buffer_offset; } @@ -139,8 +139,8 @@ class UserProfile { return static_cast(value.size()); } size_t Append(uint8_t* user_data, uint8_t* buffer, - size_t buffer_offset) override { - buffer_offset = Setting::Append(user_data, buffer, buffer_offset); + uint32_t buffer_ptr, size_t buffer_offset) override { + buffer_offset = Setting::Append(user_data, buffer, buffer_ptr, buffer_offset); int32_t length; if (value.empty()) { length = 0; @@ -150,7 +150,7 @@ class UserProfile { length = static_cast(value.size()); xe::store_and_swap(user_data + kValueOffset, length); xe::store_and_swap(user_data + kPointerOffset, - static_cast(buffer_offset)); + buffer_ptr + static_cast(buffer_offset)); memcpy(buffer + buffer_offset, value.data(), length); } return buffer_offset + length; @@ -161,8 +161,8 @@ class UserProfile { : Setting(setting_id, Type::DATETIME, 8), value(value) {} int64_t value; size_t Append(uint8_t* user_data, uint8_t* buffer, - size_t buffer_offset) override { - buffer_offset = Setting::Append(user_data, buffer, buffer_offset); + uint32_t buffer_ptr, size_t buffer_offset) override { + buffer_offset = Setting::Append(user_data, buffer, buffer_ptr, buffer_offset); xe::store_and_swap(user_data + kValueOffset, value); return buffer_offset; } diff --git a/src/xenia/kernel/xam_user.cc b/src/xenia/kernel/xam_user.cc index e9b5cb8c2..3bf1bb7d7 100644 --- a/src/xenia/kernel/xam_user.cc +++ b/src/xenia/kernel/xam_user.cc @@ -96,6 +96,23 @@ SHIM_CALL XamUserGetName_shim(PPCContext* ppc_context, } } +typedef struct { + xe::be setting_count; + xe::be settings_ptr; +} X_USER_READ_PROFILE_SETTINGS; +static_assert_size(X_USER_READ_PROFILE_SETTINGS, 8); + +typedef struct { + xe::be from; + xe::be unk04; + xe::be user_index; + xe::be unk0C; + xe::be setting_id; + xe::be unk14; + uint8_t setting_data[16]; +} X_USER_READ_PROFILE_SETTING; +static_assert_size(X_USER_READ_PROFILE_SETTING, 40); + // http://freestyledash.googlecode.com/svn/trunk/Freestyle/Tools/Generic/xboxtools.cpp SHIM_CALL XamUserReadProfileSettings_shim(PPCContext* ppc_context, KernelState* kernel_state) { @@ -109,7 +126,7 @@ SHIM_CALL XamUserReadProfileSettings_shim(PPCContext* ppc_context, uint32_t buffer_ptr = SHIM_GET_ARG_32(7); uint32_t overlapped_ptr = SHIM_GET_ARG_32(8); - uint32_t buffer_size = SHIM_MEM_32(buffer_size_ptr); + uint32_t buffer_size = !buffer_size_ptr ? 0 : SHIM_MEM_32(buffer_size_ptr); XELOGD( "XamUserReadProfileSettings(%.8X, %d, %d, %d, %d, %.8X, %.8X(%d), %.8X, " @@ -117,13 +134,12 @@ SHIM_CALL XamUserReadProfileSettings_shim(PPCContext* ppc_context, title_id, user_index, unk_0, unk_1, setting_count, setting_ids_ptr, buffer_size_ptr, buffer_size, buffer_ptr, overlapped_ptr); + assert_zero(unk_0); + assert_zero(unk_1); + // Title ID = 0 means us. // 0xfffe07d1 = profile? - if (user_index == 255) { - user_index = 0; - } - if (user_index) { // Only support user 0. if (overlapped_ptr) { @@ -135,30 +151,23 @@ SHIM_CALL XamUserReadProfileSettings_shim(PPCContext* ppc_context, } return; } + const auto& user_profile = kernel_state->user_profile(); // First call asks for size (fill buffer_size_ptr). // Second call asks for buffer contents with that size. - // http://cs.rin.ru/forum/viewtopic.php?f=38&t=60668&hilit=gfwl+live&start=195 - // Result buffer is: - // uint32_t setting_count - // struct { - // uint32_t source; - // (4b pad) - // uint32_t user_index; - // (4b pad) - // uint32_t setting_id; - // (4b pad) - // - // } settings[setting_count] - const size_t kSettingSize = 4 + 4 + 4 + 4 + 4 + 4 + 16; + auto setting_ids = (xe::be*)SHIM_MEM_ADDR(setting_ids_ptr); - // Compute required size. + // Compute required base size. + uint32_t base_size_needed = sizeof(X_USER_READ_PROFILE_SETTINGS); + base_size_needed += setting_count * sizeof(X_USER_READ_PROFILE_SETTING); + + // Compute required extra size. + uint32_t size_needed = base_size_needed; bool any_missing = false; - uint32_t size_needed = 4 + 4 + setting_count * kSettingSize; for (uint32_t n = 0; n < setting_count; ++n) { - uint32_t setting_id = SHIM_MEM_32(setting_ids_ptr + n * 4); + uint32_t setting_id = setting_ids[n]; auto setting = user_profile->GetSetting(setting_id); if (setting) { auto extra_size = static_cast(setting->extra_size()); @@ -169,6 +178,7 @@ SHIM_CALL XamUserReadProfileSettings_shim(PPCContext* ppc_context, setting_id); } } + if (any_missing) { // TODO(benvanik): don't fail? most games don't even check! if (overlapped_ptr) { @@ -180,6 +190,7 @@ SHIM_CALL XamUserReadProfileSettings_shim(PPCContext* ppc_context, } return; } + SHIM_SET_MEM_32(buffer_size_ptr, size_needed); if (!buffer_ptr || buffer_size < size_needed) { if (overlapped_ptr) { @@ -192,28 +203,29 @@ SHIM_CALL XamUserReadProfileSettings_shim(PPCContext* ppc_context, return; } - SHIM_SET_MEM_32(buffer_ptr + 0, setting_count); - SHIM_SET_MEM_32(buffer_ptr + 4, buffer_ptr + 8); + auto out_header = (X_USER_READ_PROFILE_SETTINGS*)SHIM_MEM_ADDR(buffer_ptr); + out_header->setting_count = setting_count; + out_header->settings_ptr = buffer_ptr + 8; - size_t buffer_offset = 4 + setting_count * kSettingSize; - size_t user_data_ptr = buffer_ptr + 8; + auto out_setting = (X_USER_READ_PROFILE_SETTING*)SHIM_MEM_ADDR(out_header->settings_ptr); + + size_t buffer_offset = base_size_needed; for (uint32_t n = 0; n < setting_count; ++n) { - uint32_t setting_id = SHIM_MEM_32(setting_ids_ptr + n * 4); + uint32_t setting_id = setting_ids[n]; auto setting = user_profile->GetSetting(setting_id); + + std::memset(out_setting, 0, sizeof(X_USER_READ_PROFILE_SETTING)); + out_setting->from = !setting ? 0 : setting->is_title_specific() ? 2 : 1; + out_setting->user_index = user_index; + out_setting->setting_id = setting_id; + if (setting) { - SHIM_SET_MEM_32(user_data_ptr + 0, setting->is_title_specific() ? 2 : 1); - } else { - SHIM_SET_MEM_32(user_data_ptr + 0, 0); - } - SHIM_SET_MEM_32(user_data_ptr + 8, user_index); - SHIM_SET_MEM_32(user_data_ptr + 16, setting_id); - if (setting) { - buffer_offset = setting->Append(SHIM_MEM_ADDR(user_data_ptr + 24), - SHIM_MEM_ADDR(buffer_ptr), buffer_offset); - } else { - std::memset(SHIM_MEM_ADDR(user_data_ptr + 24), 0, 16); - } - user_data_ptr += kSettingSize; + buffer_offset = setting->Append(&out_setting->setting_data[0], + SHIM_MEM_ADDR(buffer_ptr), buffer_ptr, buffer_offset); + } /*else { + std::memset(&out_setting->setting_data[0], 0, sizeof(out_setting->setting_data)); + }*/ + ++out_setting; } if (overlapped_ptr) {