sprof: update for 13.1.0 (format version 1)

This commit is contained in:
Michael Scire 2021-10-26 00:51:44 -07:00
parent a14dc6ed89
commit 0e81eac9d1
12 changed files with 119 additions and 85 deletions

View file

@ -34,7 +34,7 @@ namespace ams::sprofile::srv {
constexpr const sm::ServiceName ServiceNameForSystemProcess = sm::ServiceName::Encode("sprof:sp");
constexpr inline size_t BgAgentSessionCountMax = 2;
constexpr inline size_t SystemProcessSessionCountMax = 5;
constexpr inline size_t SystemProcessSessionCountMax = 10;
constexpr inline size_t SessionCountMax = BgAgentSessionCountMax + SystemProcessSessionCountMax;
@ -42,8 +42,8 @@ namespace ams::sprofile::srv {
struct ServerManagerOptions {
static constexpr size_t PointerBufferSize = 0x0;
static constexpr size_t MaxDomains = SessionCountMax; /* NOTE: Official is 3 */
static constexpr size_t MaxDomainObjects = 16; /* NOTE: Official is 8 */
static constexpr size_t MaxDomains = SessionCountMax; /* NOTE: Official is 9 */
static constexpr size_t MaxDomainObjects = 16; /* NOTE: Official is 14 */
static constexpr bool CanDeferInvokeRequest = false;
static constexpr bool CanManageMitmServers = false;
};

View file

@ -18,8 +18,8 @@
#include "sprofile_srv_types.hpp"
#define AMS_SPROFILE_I_PROFILE_IMPORTER_INTERFACE_INFO(C, H) \
AMS_SF_METHOD_INFO(C, H, 0, Result, ImportProfile, (const sprofile::srv::ProfileDataForImportData &data), (data)) \
AMS_SF_METHOD_INFO(C, H, 1, Result, Commit, (), ()) \
AMS_SF_METHOD_INFO(C, H, 0, Result, ImportMetadata, (const sprofile::srv::ProfileMetadataForImportMetadata &data), (data)) \
AMS_SF_METHOD_INFO(C, H, 0, Result, ImportProfile, (const sprofile::srv::ProfileDataForImportData &import), (import)) \
AMS_SF_METHOD_INFO(C, H, 1, Result, Commit, (), ()) \
AMS_SF_METHOD_INFO(C, H, 2, Result, ImportMetadata, (const sprofile::srv::ProfileMetadataForImportMetadata &import), (import)) \
AMS_SF_DEFINE_INTERFACE(ams::sprofile, IProfileImporter, AMS_SPROFILE_I_PROFILE_IMPORTER_INTERFACE_INFO)

View file

@ -21,6 +21,6 @@
AMS_SF_METHOD_INFO(C, H, 1, Result, GetUnsigned64, (sf::Out<u64> out, sprofile::Identifier profile, sprofile::Identifier key), (out, profile, key)) \
AMS_SF_METHOD_INFO(C, H, 2, Result, GetSigned32, (sf::Out<s32> out, sprofile::Identifier profile, sprofile::Identifier key), (out, profile, key)) \
AMS_SF_METHOD_INFO(C, H, 3, Result, GetUnsigned32, (sf::Out<u32> out, sprofile::Identifier profile, sprofile::Identifier key), (out, profile, key)) \
AMS_SF_METHOD_INFO(C, H, 3, Result, GetByte, (sf::Out<u8> out, sprofile::Identifier profile, sprofile::Identifier key), (out, profile, key))
AMS_SF_METHOD_INFO(C, H, 4, Result, GetByte, (sf::Out<u8> out, sprofile::Identifier profile, sprofile::Identifier key), (out, profile, key))
AMS_SF_DEFINE_INTERFACE(ams::sprofile, IProfileReader, AMS_SPROFILE_I_PROFILE_READER_INTERFACE_INFO)

View file

@ -18,9 +18,9 @@
#include "sprofile_srv_i_profile_importer.hpp"
#define AMS_SPROFILE_I_SPROFILE_SERVICE_FOR_BG_AGENT_INTERFACE_INFO(C, H) \
AMS_SF_METHOD_INFO(C, H, 100, Result, OpenProfileImporter, (sf::Out<sf::SharedPointer<::ams::sprofile::IProfileImporter>> out), (out)) \
AMS_SF_METHOD_INFO(C, H, 200, Result, ReadMetadata, (sf::Out<u32> out_count, const sf::OutArray<sprofile::srv::ReadMetadataEntry> &out, const sprofile::srv::ReadMetadataArgument &arg), (out_count, out, arg)) \
AMS_SF_METHOD_INFO(C, H, 201, Result, IsUpdateNeeded, (sf::Out<bool> out, sprofile::Identifier revision_key), (out, revision_key)) \
AMS_SF_METHOD_INFO(C, H, 2000, Result, Reset, (), ())
AMS_SF_METHOD_INFO(C, H, 100, Result, OpenProfileImporter, (sf::Out<sf::SharedPointer<::ams::sprofile::IProfileImporter>> out), (out)) \
AMS_SF_METHOD_INFO(C, H, 200, Result, GetMetadataEntryData, (sf::Out<u32> out_count, const sf::OutArray<sprofile::srv::ProfileMetadataEntryData> &out, const sprofile::srv::ProfileMetadataForImportMetadata &arg), (out_count, out, arg)) \
AMS_SF_METHOD_INFO(C, H, 201, Result, IsUpdateNeeded, (sf::Out<bool> out, sprofile::Identifier revision_key), (out, revision_key)) \
AMS_SF_METHOD_INFO(C, H, 2000, Result, Reset, (), ())
AMS_SF_DEFINE_INTERFACE(ams::sprofile, ISprofileServiceForBgAgent, AMS_SPROFILE_I_SPROFILE_SERVICE_FOR_BG_AGENT_INTERFACE_INFO)

View file

@ -38,7 +38,7 @@ namespace ams::sprofile::srv {
bool HasProfile(Identifier id0, Identifier id1) {
/* Require that we have metadata. */
if (m_metadata.has_value()) {
for (auto i = 0u; i < m_metadata->num_entries; ++i) {
for (auto i = 0u; i < std::min<size_t>(m_metadata->num_entries, util::size(m_metadata->entries)); ++i) {
const auto &entry = m_metadata->entries[i];
if (entry.identifier_0 == id0 && entry.identifier_1 == id1) {
return true;
@ -63,7 +63,7 @@ namespace ams::sprofile::srv {
m_revision_key = meta.revision_key;
/* Import all profiles. */
for (auto i = 0u; i < meta.num_entries; ++i) {
for (auto i = 0u; i < std::min<size_t>(meta.num_entries, util::size(meta.entries)); ++i) {
const auto &import_entry = meta.entries[i];
if (!this->HasProfile(import_entry.identifier_0, import_entry.identifier_1)) {
m_importing_profiles[m_importing_count++] = import_entry.identifier_0;

View file

@ -19,16 +19,16 @@
namespace ams::sprofile::srv {
Result ProfileImporterImpl::ImportProfile(const sprofile::srv::ProfileDataForImportData &data) {
return m_manager->ImportProfile(data);
Result ProfileImporterImpl::ImportProfile(const sprofile::srv::ProfileDataForImportData &import) {
return m_manager->ImportProfile(import);
}
Result ProfileImporterImpl::Commit() {
return m_manager->Commit();
}
Result ProfileImporterImpl::ImportMetadata(const sprofile::srv::ProfileMetadataForImportMetadata &data) {
return m_manager->ImportMetadata(data);
Result ProfileImporterImpl::ImportMetadata(const sprofile::srv::ProfileMetadataForImportMetadata &import) {
return m_manager->ImportMetadata(import);
}
}

View file

@ -27,9 +27,9 @@ namespace ams::sprofile::srv {
public:
ProfileImporterImpl(ProfileManager *manager) : m_manager(manager) { /* ... */ }
public:
Result ImportProfile(const sprofile::srv::ProfileDataForImportData &data);
Result ImportProfile(const sprofile::srv::ProfileDataForImportData &import);
Result Commit();
Result ImportMetadata(const sprofile::srv::ProfileMetadataForImportMetadata &data);
Result ImportMetadata(const sprofile::srv::ProfileMetadataForImportMetadata &import);
};
static_assert(IsIProfileImporter<ProfileImporterImpl>);

View file

@ -151,7 +151,7 @@ namespace ams::sprofile::srv {
return ResultSuccess();
}
Result ProfileManager::ImportProfile(const sprofile::srv::ProfileDataForImportData &data) {
Result ProfileManager::ImportProfile(const sprofile::srv::ProfileDataForImportData &import) {
/* Acquire locks. */
std::scoped_lock lk1(m_profile_importer_mutex);
std::scoped_lock lk2(m_fs_mutex);
@ -159,25 +159,37 @@ namespace ams::sprofile::srv {
/* Check that we have an importer. */
R_UNLESS(m_profile_importer.has_value(), sprofile::ResultInvalidState());
/* Check that the metadata we're importing is valid. */
R_UNLESS(data.data.version == ProfileDataVersion, sprofile::ResultInvalidDataVersion());
/* Check that the metadata we're importing is a valid version. */
R_UNLESS(IsValidProfileFormatVersion(import.header.version), sprofile::ResultInvalidDataVersion());
/* Check that the metadata we're importing has a valid hash. */
{
crypto::Md5Generator md5;
md5.Update(std::addressof(import.header), sizeof(import.header));
md5.Update(std::addressof(import.data), sizeof(import.data) - sizeof(import.data.entries[0]) * (util::size(import.data.entries) - std::min<size_t>(import.data.num_entries, util::size(import.data.entries))));
u8 hash[crypto::Md5Generator::HashSize];
md5.GetHash(hash, sizeof(hash));
R_UNLESS(crypto::IsSameBytes(hash, import.hash, sizeof(hash)), sprofile::ResultInvalidDataHash());
}
/* Succeed if we already have the profile. */
R_SUCCEED_IF(m_profile_importer->HasProfile(data.identifier_0, data.identifier_1));
R_SUCCEED_IF(m_profile_importer->HasProfile(import.header.identifier_0, import.header.identifier_1));
/* Check that we're importing the profile. */
R_UNLESS(m_profile_importer->CanImportProfile(data.identifier_0), sprofile::ResultInvalidState());
R_UNLESS(m_profile_importer->CanImportProfile(import.header.identifier_0), sprofile::ResultInvalidState());
/* Create temporary directories. */
R_TRY(this->EnsureTemporaryDirectories());
/* Create profile. */
char path[0x30];
CreateTemporaryProfilePath(path, sizeof(path), m_save_data_info.mount_name, data.identifier_0);
R_TRY(WriteFile(path, std::addressof(data.data), sizeof(data.data)));
CreateTemporaryProfilePath(path, sizeof(path), m_save_data_info.mount_name, import.header.identifier_0);
R_TRY(WriteFile(path, std::addressof(import.data), sizeof(import.data)));
/* Set profile imported. */
m_profile_importer->OnImportProfile(data.identifier_0);
m_profile_importer->OnImportProfile(import.header.identifier_0);
return ResultSuccess();
}
@ -231,7 +243,7 @@ namespace ams::sprofile::srv {
return ResultSuccess();
}
Result ProfileManager::ImportMetadata(const sprofile::srv::ProfileMetadataForImportMetadata &data) {
Result ProfileManager::ImportMetadata(const sprofile::srv::ProfileMetadataForImportMetadata &import) {
/* Acquire locks. */
std::scoped_lock lk1(m_profile_importer_mutex);
std::scoped_lock lk2(m_fs_mutex);
@ -240,8 +252,21 @@ namespace ams::sprofile::srv {
R_UNLESS(m_profile_importer.has_value(), sprofile::ResultInvalidState());
R_UNLESS(m_profile_importer->CanImportMetadata(), sprofile::ResultInvalidState());
/* Check that the metadata we're importing is valid. */
R_UNLESS(data.metadata.version == ProfileMetadataVersion, sprofile::ResultInvalidMetadataVersion());
/* Check that the metadata we're importing is a valid version. */
R_UNLESS(IsValidProfileFormatVersion(import.header.version), sprofile::ResultInvalidMetadataVersion());
/* Check that the metadata we're importing has a valid hash. */
{
crypto::Md5Generator md5;
md5.Update(std::addressof(import.header), sizeof(import.header));
md5.Update(std::addressof(import.metadata), sizeof(import.metadata));
md5.Update(std::addressof(import.entries), sizeof(import.entries[0]) * std::min<size_t>(import.metadata.num_entries, util::size(import.metadata.entries)));
u8 hash[crypto::Md5Generator::HashSize];
md5.GetHash(hash, sizeof(hash));
R_UNLESS(crypto::IsSameBytes(hash, import.hash, sizeof(hash)), sprofile::ResultInvalidMetadataHash());
}
/* Create temporary directories. */
R_TRY(this->EnsureTemporaryDirectories());
@ -249,10 +274,10 @@ namespace ams::sprofile::srv {
/* Create metadata. */
char path[0x30];
CreateTemporaryMetadataPath(path, sizeof(path), m_save_data_info.mount_name);
R_TRY(WriteFile(path, std::addressof(data.metadata), sizeof(data.metadata)));
R_TRY(WriteFile(path, std::addressof(import.metadata), sizeof(import.metadata)));
/* Import the metadata. */
m_profile_importer->ImportMetadata(data.metadata);
m_profile_importer->ImportMetadata(import.metadata);
return ResultSuccess();
}
@ -309,13 +334,13 @@ namespace ams::sprofile::srv {
std::scoped_lock lk2(m_general_mutex);
/* Load the desired profile. */
R_TRY(this->LoadProfile(profile));
/* Find the specified key. */
for (auto i = 0u; i < m_service_profile->data.num_entries; ++i) {
if (m_service_profile->data.entries[i].key == key) {
*out = m_service_profile->data.entries[i];
return ResultSuccess();
if (R_SUCCEEDED(this->LoadProfile(profile))) {
/* Find the specified key. */
for (auto i = 0u; i < std::min<size_t>(m_service_profile->data.num_entries, util::size(m_service_profile->data.entries)); ++i) {
if (m_service_profile->data.entries[i].key == key) {
*out = m_service_profile->data.entries[i];
return ResultSuccess();
}
}
}
@ -426,6 +451,8 @@ namespace ams::sprofile::srv {
}
void ProfileManager::OnCommitted() {
/* TODO: Here, Nintendo sets the erpt ServiceProfileRevisionKey to the current revision key. */
/* If we need to, invalidate the loaded service profile. */
if (m_service_profile.has_value()) {
for (auto i = 0; i < m_profile_importer->GetImportingCount(); ++i) {
@ -436,8 +463,6 @@ namespace ams::sprofile::srv {
}
}
/* TODO: Here, Nintendo sets the erpt ServiceProfileRevisionKey to the current revision key. */
/* Reset profile metadata. */
m_profile_metadata = util::nullopt;
@ -445,6 +470,9 @@ namespace ams::sprofile::srv {
for (auto i = 0; i < m_profile_importer->GetImportingCount(); ++i) {
m_update_observer_manager.OnUpdate(m_profile_importer->GetImportingProfile(i));
}
/* Reset profile importer. */
m_profile_importer = util::nullopt;
}
Result ProfileManager::EnsurePrimaryDirectories() {

View file

@ -34,7 +34,7 @@ namespace ams::sprofile::srv {
return ResultSuccess();
}
Result ServiceForBgAgent::ReadMetadata(sf::Out<u32> out_count, const sf::OutArray<sprofile::srv::ReadMetadataEntry> &out, const sprofile::srv::ReadMetadataArgument &arg) {
Result ServiceForBgAgent::GetMetadataEntryData(sf::Out<u32> out_count, const sf::OutArray<sprofile::srv::ProfileMetadataEntryData> &out, const sprofile::srv::ProfileMetadataForImportMetadata &arg) {
/* Check size. */
R_UNLESS(out.GetSize() >= arg.metadata.num_entries, sprofile::ResultInvalidArgument());

View file

@ -29,7 +29,7 @@ namespace ams::sprofile::srv {
constexpr ServiceForBgAgent(MemoryResource *mr, ProfileManager *pm) : m_memory_resource(mr), m_profile_manager(pm) { /* ... */ }
public:
Result OpenProfileImporter(sf::Out<sf::SharedPointer<::ams::sprofile::IProfileImporter>> out);
Result ReadMetadata(sf::Out<u32> out_count, const sf::OutArray<sprofile::srv::ReadMetadataEntry> &out, const sprofile::srv::ReadMetadataArgument &arg);
Result GetMetadataEntryData(sf::Out<u32> out_count, const sf::OutArray<sprofile::srv::ProfileMetadataEntryData> &out, const sprofile::srv::ProfileMetadataForImportMetadata &arg);
Result IsUpdateNeeded(sf::Out<bool> out, Identifier revision_key);
Result Reset();
};

View file

@ -18,34 +18,11 @@
namespace ams::sprofile::srv {
struct ProfileMetadataEntry {
Identifier identifier_0;
Identifier identifier_1;
u8 unk_0E[0x32];
};
static_assert(util::is_pod<ProfileMetadataEntry>::value);
static_assert(sizeof(ProfileMetadataEntry) == 0x40);
constexpr inline const u32 ProfileFormatVersion = 1;
constexpr inline const u32 ProfileMetadataVersion = 0;
struct ProfileMetadata {
u32 version;
u32 num_entries;
Identifier revision_key;
u8 unk_10[0x30];
ProfileMetadataEntry entries[50];
};
static_assert(util::is_pod<ProfileMetadata>::value);
static_assert(sizeof(ProfileMetadata) == 0xCC0);
struct ProfileMetadataForImportMetadata : public sf::LargeData, public sf::PrefersMapAliasTransferMode {
ProfileMetadata metadata;
u8 unk[0x8000 - sizeof(metadata)];
};
static_assert(util::is_pod<ProfileMetadataForImportMetadata>::value);
static_assert(sizeof(ProfileMetadataForImportMetadata) == 0x8000);
constexpr inline const u32 ProfileDataVersion = 0;
constexpr inline bool IsValidProfileFormatVersion(u32 version) {
return version == ProfileFormatVersion;
}
enum ValueType : u8 {
ValueType_Byte = 0,
@ -70,9 +47,9 @@ namespace ams::sprofile::srv {
static_assert(sizeof(ProfileDataEntry) == 0x10);
struct ProfileData {
u32 version;
u32 num_entries;
u8 unk_08[0x28];
u8 unk_04[0x0C];
u8 unk_10[0x20];
ProfileDataEntry entries[(0x4000 - 0x30) / sizeof(ProfileDataEntry)];
};
static_assert(util::is_pod<ProfileData>::value);
@ -86,28 +63,55 @@ namespace ams::sprofile::srv {
static_assert(sizeof(ServiceProfile) == 0x4008);
struct ProfileDataForImportData : public sf::LargeData, public sf::PrefersMapAliasTransferMode {
Identifier identifier_0;
Identifier identifier_1;
u8 unk_0E[2];
struct {
Identifier identifier_0;
Identifier identifier_1;
u8 unk_0E[2];
u32 version;
u8 unk_14[0x1C];
} header;
u8 hash[crypto::Md5Generator::HashSize];
ProfileData data;
u8 unk_4010[0x4400 - 0x4010];
u8 unk_4040[0x4400 - 0x4040];
};
static_assert(util::is_pod<ProfileDataForImportData>::value);
static_assert(sizeof(ProfileDataForImportData) == 0x4400);
struct ReadMetadataEntry {
struct ProfileMetadataEntry {
Identifier identifier_0;
Identifier identifier_1;
u8 unk_0E[0x32];
};
static_assert(util::is_pod<ProfileMetadataEntry>::value);
static_assert(sizeof(ProfileMetadataEntry) == 0x40);
struct ProfileMetadataEntryData : public sf::PrefersMapAliasTransferMode {
u8 unk[0x100];
};
static_assert(util::is_pod<ReadMetadataEntry>::value);
static_assert(sizeof(ReadMetadataEntry) == 0x100);
static_assert(util::is_pod<ProfileMetadataEntryData>::value);
static_assert(sizeof(ProfileMetadataEntryData) == 0x100);
struct ReadMetadataArgument : public sf::LargeData, public sf::PrefersMapAliasTransferMode {
ProfileMetadata metadata;
ReadMetadataEntry entries[(0x8000 - sizeof(metadata)) / sizeof(ReadMetadataEntry)];
u8 unk_7FC0[0x40];
struct ProfileMetadata {
u32 num_entries;
u32 unk_04;
Identifier revision_key;
u8 unk_10[0x30];
ProfileMetadataEntry entries[50];
};
static_assert(util::is_pod<ReadMetadataArgument>::value);
static_assert(sizeof(ReadMetadataArgument) == 0x8000);
static_assert(util::is_pod<ProfileMetadata>::value);
static_assert(sizeof(ProfileMetadata) == 0xCC0);
struct ProfileMetadataForImportMetadata : public sf::LargeData, public sf::PrefersMapAliasTransferMode {
struct {
u32 version;
u8 unk_04[0x1C];
} header;
u8 hash[crypto::Md5Generator::HashSize];
ProfileMetadata metadata;
ProfileMetadataEntryData entries[50];
u8 unk[0x8000 - 0x3EF0];
};
static_assert(util::is_pod<ProfileMetadataForImportMetadata>::value);
static_assert(sizeof(ProfileMetadataForImportMetadata) == 0x8000);
}

View file

@ -37,6 +37,8 @@ namespace ams::sprofile {
R_DEFINE_ERROR_RESULT(MaxObservers, 623);
R_DEFINE_ERROR_RESULT(InvalidMetadataVersion, 3210);
R_DEFINE_ERROR_RESULT(InvalidMetadataHash, 3211);
R_DEFINE_ERROR_RESULT(InvalidDataVersion, 3230);
R_DEFINE_ERROR_RESULT(InvalidDataHash, 3231);
}