diff --git a/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_api.cpp b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_api.cpp index 5fc1e5100..c856399dc 100644 --- a/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_api.cpp +++ b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_api.cpp @@ -86,6 +86,9 @@ namespace ams::sprofile::srv { /* Create the profile manager. */ util::ConstructAt(g_profile_manager, SaveDataInfo); + /* Process profile manager savedata. */ + util::GetReference(g_profile_manager).InitializeSaveData(); + /* Create the service objects. */ util::ConstructAt(g_bg_service_object, std::addressof(g_sf_memory_resource), util::GetPointer(g_profile_manager)); util::ConstructAt(g_sp_service_object, std::addressof(g_sf_memory_resource), util::GetPointer(g_profile_manager)); diff --git a/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_fs_utils.cpp b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_fs_utils.cpp new file mode 100644 index 000000000..6f3a11a95 --- /dev/null +++ b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_fs_utils.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include "sprofile_srv_profile_manager.hpp" + +namespace ams::sprofile::srv { + + Result WriteFile(const char *path, const void *src, size_t size) { + /* Create the file. */ + R_TRY_CATCH(fs::CreateFile(path, size)) { + R_CATCH(fs::ResultPathAlreadyExists) { /* It's okay if the file already exists. */ } + } R_END_TRY_CATCH_WITH_ABORT_UNLESS; + + /* Open the file. */ + fs::FileHandle file; + R_ABORT_UNLESS(fs::OpenFile(std::addressof(file), path, fs::OpenMode_Write)); + ON_SCOPE_EXIT { fs::CloseFile(file); }; + + /* Set the file size. */ + R_ABORT_UNLESS(fs::SetFileSize(file, size)); + + /* Write the file. */ + return fs::WriteFile(file, 0, src, size, fs::WriteOption::Flush); + } + +} diff --git a/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_fs_utils.hpp b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_fs_utils.hpp new file mode 100644 index 000000000..19bb8229c --- /dev/null +++ b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_fs_utils.hpp @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include + +namespace ams::sprofile::srv { + + Result ReadFile(const char *path, void *dst, size_t size, s64 offset); + Result WriteFile(const char *path, const void *src, size_t size); + Result MoveFile(const char *dst_path, const char *src_path); + +} \ No newline at end of file diff --git a/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_profile_manager.cpp b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_profile_manager.cpp new file mode 100644 index 000000000..684ce7715 --- /dev/null +++ b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_profile_manager.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include "sprofile_srv_profile_manager.hpp" + +namespace ams::sprofile::srv { + + namespace { + + Result CreateSaveData(const ProfileManager::SaveDataInfo &save_data_info) { + R_TRY_CATCH(fs::CreateSystemSaveData(save_data_info.id, save_data_info.size, save_data_info.journal_size, save_data_info.flags)) { + R_CATCH(fs::ResultPathAlreadyExists) { /* Nintendo accepts already-existing savedata here. */ } + } R_END_TRY_CATCH; + return ResultSuccess(); + } + + } + + ProfileManager::ProfileManager(const SaveDataInfo &save_data_info) + : m_general_mutex(), m_fs_mutex(), m_save_data_info(save_data_info), m_save_file_mounted(false), + m_update_observer_manager() + { + /* ... */ + } + + void ProfileManager::InitializeSaveData() { + /* Acquire locks. */ + std::scoped_lock lk1(m_general_mutex); + std::scoped_lock lk2(m_fs_mutex); + + /* Ensure the savedata exists. */ + if (R_SUCCEEDED(CreateSaveData(m_save_data_info))) { + m_save_file_mounted = R_SUCCEEDED(fs::MountSystemSaveData(m_save_data_info.mount_name, m_save_data_info.id)); + + /* TODO: Remove this after implementation, as it's for debugging. */ + R_ABORT_UNLESS(fs::MountSdCard("sprof-dbg")); + } + } + +} diff --git a/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_profile_manager.hpp b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_profile_manager.hpp index 803fc906e..c800134c1 100644 --- a/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_profile_manager.hpp +++ b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_profile_manager.hpp @@ -15,6 +15,7 @@ */ #pragma once #include +#include "sprofile_srv_profile_update_observer_impl.hpp" namespace ams::sprofile::srv { @@ -28,19 +29,21 @@ namespace ams::sprofile::srv { u32 flags; }; private: - class UpdateObserverManager; private: os::SdkMutex m_general_mutex; os::SdkMutex m_fs_mutex; SaveDataInfo m_save_data_info; + bool m_save_file_mounted; /* TODO: util::optional m_profile_importer; */ /* TODO: util::optional m_profile_metadata; */ /* TODO: util::optional m_service_profile; */ - UpdateObserverManager *m_update_observer_manager; + ProfileUpdateObserverManager m_update_observer_manager; public: ProfileManager(const SaveDataInfo &save_data_info); public: - /* TODO */ + void InitializeSaveData(); + + ProfileUpdateObserverManager &GetUpdateObserverManager() { return m_update_observer_manager; } private: /* TODO */ }; diff --git a/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_profile_update_observer_impl.cpp b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_profile_update_observer_impl.cpp new file mode 100644 index 000000000..e5b4a66ee --- /dev/null +++ b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_profile_update_observer_impl.cpp @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include "sprofile_srv_profile_manager.hpp" +#include "sprofile_srv_profile_update_observer_impl.hpp" + +namespace ams::sprofile::srv { + + namespace { + + class AutoUnregisterObserver : public ProfileUpdateObserverImpl { + public: + static constexpr auto MaxProfiles = 4; + private: + Identifier m_profiles[MaxProfiles]; + int m_profile_count; + os::SdkMutex m_mutex; + ProfileUpdateObserverManager *m_manager; + public: + AutoUnregisterObserver(ProfileUpdateObserverManager *manager) : m_profile_count(0), m_mutex(), m_manager(manager) { /* ... */ } + virtual ~AutoUnregisterObserver() { m_manager->CloseObserver(this); } + public: + Result Listen(Identifier profile) { + /* Lock ourselves. */ + std::scoped_lock lk(m_mutex); + + /* Check if we can listen. */ + R_UNLESS(m_profile_count < MaxProfiles, sprofile::ResultMaxListeners()); + + /* Check if we're already listening. */ + for (auto i = 0; i < m_profile_count; ++i) { + R_UNLESS(m_profiles[i] != profile, sprofile::ResultAlreadyListening()); + } + + /* Add the profile. */ + m_profiles[m_profile_count++] = profile; + return ResultSuccess(); + } + + Result Unlisten(Identifier profile) { + /* Check that we're listening. */ + for (auto i = 0; i < m_profile_count; ++i) { + if (m_profiles[i] == profile) { + m_profiles[i] = m_profiles[--m_profile_count]; + AMS_ABORT_UNLESS(m_profile_count >= 0); + return ResultSuccess(); + } + } + + return sprofile::ResultNotListening(); + } + + Result GetEventHandle(sf::OutCopyHandle out) { + out.SetValue(this->GetEvent().GetReadableHandle()); + return ResultSuccess(); + } + }; + static_assert(sprofile::IsIProfileUpdateObserver); + + } + + Result ProfileUpdateObserverManager::OpenObserver(sf::Out> &out, MemoryResource *memory_resource) { + /* Lock ourselves. */ + std::scoped_lock lk(m_mutex); + + /* Check that we can allocate. */ + R_UNLESS(m_observer_count < MaxObservers, sprofile::ResultMaxObservers()); + + /* Allocate an object. */ + auto obj = sf::ObjectFactory::CreateSharedEmplaced(memory_resource, this); + R_UNLESS(obj != nullptr, sprofile::ResultAllocationFailed()); + + /* Register the observer. */ + m_observers[m_observer_count++] = std::addressof(obj.GetImpl()); + + /* Return the object. */ + *out = std::move(obj); + return ResultSuccess(); + } + + void ProfileUpdateObserverManager::CloseObserver(ProfileUpdateObserverImpl *observer) { + /* Lock ourselves. */ + std::scoped_lock lk(m_mutex); + + /* Find the observer. */ + int index = -1; + for (auto i = 0; i < m_observer_count; ++i) { + if (m_observers[i] == observer) { + index = i; + break; + } + } + AMS_ABORT_UNLESS(index != -1); + + /* Remove from our list. */ + m_observers[index] = m_observers[--m_observer_count]; + + /* Sanity check. */ + AMS_ABORT_UNLESS(m_observer_count >= 0); + } + +} diff --git a/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_profile_update_observer_impl.hpp b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_profile_update_observer_impl.hpp new file mode 100644 index 000000000..6a1810630 --- /dev/null +++ b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_profile_update_observer_impl.hpp @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include +#include "sprofile_srv_i_profile_update_observer.hpp" + +namespace ams::sprofile::srv { + + class ProfileUpdateObserverImpl { + private: + os::SystemEvent m_event; + public: + ProfileUpdateObserverImpl() : m_event(os::EventClearMode_ManualClear, true) { /* ... */ } + virtual ~ProfileUpdateObserverImpl() { /* ... */ } + public: + os::SystemEvent &GetEvent() { return m_event; } + const os::SystemEvent &GetEvent() const { return m_event; } + }; + + class ProfileUpdateObserverManager { + public: + static constexpr auto MaxObservers = 10; + private: + ProfileUpdateObserverImpl *m_observers[MaxObservers]; + int m_observer_count; + os::SdkMutex m_mutex; + public: + ProfileUpdateObserverManager() : m_observer_count(0), m_mutex() { /* ... */ } + public: + Result OpenObserver(sf::Out> &out, MemoryResource *memory_resource); + void CloseObserver(ProfileUpdateObserverImpl *observer); + }; + +} diff --git a/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_service_for_bg_agent.cpp b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_service_for_bg_agent.cpp new file mode 100644 index 000000000..cd9a19ad1 --- /dev/null +++ b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_service_for_bg_agent.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include "sprofile_srv_profile_manager.hpp" +#include "sprofile_srv_service_for_bg_agent.hpp" +#include "sprofile_srv_fs_utils.hpp" + +namespace ams::sprofile::srv { + + Result ServiceForBgAgent::OpenProfileImporter(sf::Out> out) { + AMS_ABORT("TODO: OpenProfileImporter"); + } + + Result ServiceForBgAgent::ReadMetadata(sf::Out out_count, const sf::OutBuffer &out_buf, const sf::InBuffer &meta) { + WriteFile("sprof-dbg:/sprof/meta.bin", meta.GetPointer(), meta.GetSize()); + AMS_ABORT("TODO: ReadMetadata"); + } + Result ServiceForBgAgent::IsUpdateNeeded(sf::Out out, Identifier revision_key) { + WriteFile("sprof-dbg:/sprof/revision_key.bin", std::addressof(revision_key), sizeof(revision_key)); + AMS_ABORT("TODO: IsUpdateNeeded"); + } + + Result ServiceForBgAgent::Reset() { + AMS_ABORT("TODO: Reset"); + } + +} diff --git a/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_service_for_system_process.cpp b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_service_for_system_process.cpp new file mode 100644 index 000000000..f0844e4f9 --- /dev/null +++ b/libraries/libstratosphere/source/sprofile/srv/sprofile_srv_service_for_system_process.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include "sprofile_srv_profile_manager.hpp" +#include "sprofile_srv_service_for_system_process.hpp" + +namespace ams::sprofile::srv { + + Result ServiceForSystemProcess::OpenProfileReader(sf::Out> out) { + /* TODO */ + AMS_ABORT("TODO: OpenProfileReader"); + } + + Result ServiceForSystemProcess::OpenProfileUpdateObserver(sf::Out> out) { + return m_profile_manager->GetUpdateObserverManager().OpenObserver(out, m_memory_resource); + } + + Result ServiceForSystemProcess::OpenProfileControllerForDebug(sf::Out> out) { + /* TODO */ + AMS_ABORT("TODO: OpenProfileControllerForDebug"); + } + +} diff --git a/libraries/libvapours/include/vapours/results.hpp b/libraries/libvapours/include/vapours/results.hpp index a9534855f..49aa3f4a7 100644 --- a/libraries/libvapours/include/vapours/results.hpp +++ b/libraries/libvapours/include/vapours/results.hpp @@ -64,6 +64,7 @@ #include #include #include +#include #include #include #include diff --git a/libraries/libvapours/include/vapours/results/sprofile_results.hpp b/libraries/libvapours/include/vapours/results/sprofile_results.hpp new file mode 100644 index 000000000..81eb78ab1 --- /dev/null +++ b/libraries/libvapours/include/vapours/results/sprofile_results.hpp @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include + +namespace ams::sprofile { + + R_DEFINE_NAMESPACE_RESULT_MODULE(246); + + R_DEFINE_ERROR_RESULT(AllocationFailed, 401); + + R_DEFINE_ERROR_RESULT(MaxListeners, 620); + R_DEFINE_ERROR_RESULT(AlreadyListening, 621); + R_DEFINE_ERROR_RESULT(NotListening, 622); + R_DEFINE_ERROR_RESULT(MaxObservers, 623); + +}